package com.openfarmanager.android.core.network.smb;
import android.database.Cursor;
import com.openfarmanager.android.App;
import com.openfarmanager.android.R;
import com.openfarmanager.android.core.DataStorageHelper;
import com.openfarmanager.android.core.dbadapters.NetworkAccountDbAdapter;
import com.openfarmanager.android.core.network.NetworkApi;
import com.openfarmanager.android.filesystem.FileProxy;
import com.openfarmanager.android.filesystem.FileSystemScanner;
import com.openfarmanager.android.model.NetworkAccount;
import com.openfarmanager.android.model.NetworkEnum;
import com.openfarmanager.android.model.exeptions.InAppAuthException;
import com.openfarmanager.android.model.exeptions.NetworkException;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import jcifs.UniAddress;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbSession;
import static com.openfarmanager.android.utils.Extensions.tryParse;
/**
* @author Vlad Namashko
*/
public class SmbAPI implements NetworkApi {
public static final String UNKNOWN_USERNAME_OR_BAD_PASSWORD = "Logon failure: unknown user name or bad password.";
public static final String ACCESS_DENIED = "Access is denied.";
public static final String SMB_DOMAIN = "domain";
public static final String SMB_USER = "user";
public static final String SMB_PASSWORD = "password";
private UniAddress mDomain;
private NtlmPasswordAuthentication mAuthentication;
private SmbAccount mCurrentAccount;
public void connectAndSave(String address, String username, String password) throws InAppAuthException {
connect(address, username, password);
// save account to db
JSONObject authData = new JSONObject();
try {
authData.put(SMB_DOMAIN, address);
authData.put(SMB_USER, username);
authData.put(SMB_PASSWORD, password);
long currentAccountId = NetworkAccountDbAdapter.insert(
address + "(" + username + ")",
NetworkEnum.SMB.ordinal(), authData.toString());
List<NetworkAccount> accounts = parseAccounts(NetworkAccountDbAdapter.getAccountById(currentAccountId));
if (accounts.size() == 1) {
mCurrentAccount = (SmbAccount) accounts.get(0);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void connect(SmbAccount smbAccount) throws InAppAuthException {
mCurrentAccount = smbAccount;
connect(smbAccount.getDomain(), smbAccount.getUser(), smbAccount.getPassword());
}
public void connect(String address, String username, String password) throws InAppAuthException {
try {
mDomain = UniAddress.getByName(address);
mAuthentication = new NtlmPasswordAuthentication(address, username, password);
SmbSession.logon(mDomain, mAuthentication);
} catch (UnknownHostException e) {
e.printStackTrace();
throw new InAppAuthException(App.sInstance.getString(R.string.error_wrong_smb_host));
} catch (SmbException e) {
e.printStackTrace();
throw new InAppAuthException(e.getMessage().equals(UNKNOWN_USERNAME_OR_BAD_PASSWORD) ?
App.sInstance.getString(R.string.error_smb_wrong_credentials) : App.sInstance.getString(R.string.error_ftp_io));
}
}
public List<FileProxy> getDirectoryFiles(String path) throws NetworkException {
List<FileProxy> files = new ArrayList<FileProxy>();
try {
SmbFile[] listFiles = new SmbFile("smb://" + mDomain.getHostName() + path +
(path.endsWith("/") ? "" : "/"), mAuthentication).listFiles();
for (SmbFile smbFile : listFiles) {
files.add(new com.openfarmanager.android.filesystem.SmbFile(smbFile, mDomain.getHostName()));
}
FileSystemScanner.sInstance.sort(files);
} catch (SmbException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return files;
}
public String getHostName() {
return mDomain.getHostName();
}
public SmbFile createSmbFile(String path) throws MalformedURLException {
return new SmbFile("smb://" + mDomain.getHostName() + path, mAuthentication);
}
public int getAuthorizedAccountsCount() {
return NetworkAccountDbAdapter.count(NetworkEnum.SMB.ordinal());
}
@Override
public List<NetworkAccount> getAuthorizedAccounts() {
return parseAccounts(NetworkAccountDbAdapter.getAccounts(NetworkEnum.SMB.ordinal()));
}
@Override
public NetworkAccount newAccount() {
return new SmbAccount(-1, App.sInstance.getResources().getString(com.openfarmanager.android.R.string.btn_new),
null, null, null);
}
@Override
public NetworkAccount getCurrentNetworkAccount() {
return mCurrentAccount;
}
@Override
public void delete(FileProxy file) throws Exception {
(new SmbFile("smb://" + mDomain.getHostName() + file.getFullPath(), mAuthentication)).delete();
}
@Override
public String createDirectory(String baseDirectory, String newDirectoryName) throws Exception {
String path = baseDirectory + "/" + newDirectoryName;
new SmbFile("smb://" + mDomain.getHostName() + path, mAuthentication).mkdir();
return path;
}
@Override
public List<FileProxy> search(String path, String query) {
throw new RuntimeException();
}
@Override
public boolean rename(FileProxy srcFile, String s) throws Exception {
new SmbFile("smb://" + mDomain.getHostName() + srcFile.getFullPath(), mAuthentication).renameTo(new SmbFile(s));
return true;
}
private List<NetworkAccount> parseAccounts(Cursor cursor) {
List<NetworkAccount> accounts = new ArrayList<NetworkAccount>();
if (cursor == null) {
return accounts;
}
try {
int idxId = cursor.getColumnIndex(NetworkAccountDbAdapter.Columns.ID);
int idxUserName = cursor.getColumnIndex(NetworkAccountDbAdapter.Columns.USER_NAME);
int idxAuthData = cursor.getColumnIndex(NetworkAccountDbAdapter.Columns.AUTH_DATA);
while(cursor.moveToNext()) {
String authData = cursor.getString(idxAuthData);
try {
JSONObject data = new JSONObject(authData);
SmbAccount account = new SmbAccount(cursor.getLong(idxId), cursor.getString(idxUserName),
data.getString(SMB_DOMAIN), data.getString(SMB_USER), data.getString(SMB_PASSWORD));
accounts.add(account);
} catch (JSONException e) {
e.printStackTrace();
}
}
} finally {
cursor.close();
DataStorageHelper.closeDatabase();
}
return accounts;
}
public static class SmbAccount extends NetworkAccount {
private String mDomain;
private String mUser;
private String mPassword;
public SmbAccount(long id, String userName, JSONObject data) throws JSONException {
this(id, userName, data.getString(SMB_DOMAIN), data.getString(SMB_USER), data.getString(SMB_PASSWORD));
}
public SmbAccount(long id, String userName, String domain, String user, String password) {
mId = id;
mUserName = userName;
mDomain = domain;
mUser = user;
mPassword = password;
}
public String getDomain() {
return mDomain;
}
public String getUser() {
return mUser;
}
public String getPassword() {
return mPassword;
}
@Override
public NetworkEnum getNetworkType() {
return NetworkEnum.SMB;
}
}
}