/******************************************************************************** * * * SwordReader Install Manager * * * ********************************************************************************* * Copyright (C) 2008 Barry Drake. All Rights Reserved. * ********************************************************************************/ #include #include #include #include #include #include "fx.h" #define UNICODE extern bool DeleteDirectory(const char*); WCHAR swordPath[MAX_PATH]; HANDLE hEvent; // Main Window class SRInstallMGR : public FXMainWindow { // Macro for class hierarchy declarations FXDECLARE(SRInstallMGR) private: FXVerticalFrame *buttonFrame; // Button frame FXSwitcher *switcher; FXButton *button; protected: SRInstallMGR(){} public: FXLabel *captionText; public: // Message handlers long onCmdInstall(FXObject*,FXSelector,void*); void BadExit (char*); const char* stristr(const char*, const char*); char* wstrtostr(const wchar_t*); wchar_t* strtowstr(const char*); void copyconfs(WCHAR*); void CopyOver (WCHAR*, WCHAR*); wchar_t* PrintDirectory(LPWSTR, UINT); void removeModule (LPCWSTR); void getModulePath (LPCWSTR, char&); bool fileExists(char*); void deleteCEFiles (LPCWSTR); public: // Messages for our class enum{ ID_BEGIN=FXMainWindow::ID_LAST, ID_DOINSTALL, ID_LAST }; public: // SRInstallMGR's constructor SRInstallMGR(FXApp* a); // Initialize virtual void create(); virtual ~SRInstallMGR(); }; // Message Map for the SRInstallMGR class FXDEFMAP(SRInstallMGR) SRInstallMGRMap[]={ //________Message_Type_____________________ID____________Message_Handler_______ FXMAPFUNC(SEL_COMMAND, SRInstallMGR::ID_DOINSTALL, SRInstallMGR::onCmdInstall), }; // Macro for the SRInstallMGR class hierarchy implementation FXIMPLEMENT(SRInstallMGR,FXMainWindow,SRInstallMGRMap,ARRAYNUMBER(SRInstallMGRMap)) // Construct a SRInstallMGR SRInstallMGR::SRInstallMGR(FXApp *a):FXMainWindow(a,"SR Manager",NULL,NULL,DECOR_ALL,0,0,180,250){ // RIGHT pane for the buttons buttonFrame=new FXVerticalFrame(this,FRAME_SUNKEN|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT,0,0,0,0,10,10,10,10); button = new FXButton(buttonFrame,"&Click to begin installation\n\nOnly press this if your handheld\ndevice is connected and\nActiveSync is running.\tThis will start the install process.",NULL,this,ID_DOINSTALL,FRAME_THICK|FRAME_RAISED); captionText = new FXLabel(buttonFrame,"Please wait while I catalogue\nyour existing modules, and start\nInstallManager.\n\nThis may take a minute. Then\nplease close InstallManager.\n\nAfterwards, I will need a few\nminutes to transport the module\nfiles over to your mobile device.",NULL,LAYOUT_FILL_Y|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y); } SRInstallMGR::~SRInstallMGR(){ } // Create and initialize void SRInstallMGR::create(){ // Create the windows FXMainWindow::create(); // Make the main window appear show(PLACEMENT_SCREEN); } BOOL IsDots(const CHAR* str) { if(strcmp(str,".") && strcmp(str,"..")) return FALSE; return TRUE; } const char* SRInstallMGR::stristr(const char *haystack, const char *needle){ // not mine - nicked this off the 'net if ( !*needle ) return haystack; for ( ; *haystack; ++haystack ){ if ( toupper(*haystack) == toupper(*needle) ){ const char *h, *n; for ( h = haystack, n = needle; *h && *n; ++h, ++n ){ if ( toupper(*h) != toupper(*n) )break; } if ( !*n ) return haystack; //return the start of the match } } return 0; } char* SRInstallMGR::wstrtostr(const wchar_t *str) { // this came out of original SwordReader code - is there a better way? static char *buffer = 0; if (buffer) delete [] buffer; int len = wcslen(str) + 1; // how much space is needed buffer = new char[len]; wcstombs(buffer, str,len); return buffer; } wchar_t* SRInstallMGR::strtowstr(const char *str) { static wchar_t *buffer = 0; if (buffer) delete [] buffer; int len = strlen(str) + 1; // how much space is needed buffer = new wchar_t[len]; mbstowcs(buffer, str, len); // convert char to WCHAR return buffer; } void SRInstallMGR::copyconfs(WCHAR *confName) { WCHAR wszSrcFile[MAX_PATH]; TCHAR tszDestFile[MAX_PATH]; BYTE Buffer[10000]; HANDLE hSrc, hDest; DWORD dwNumRead, dwNumWritten; wcscpy(wszSrcFile, swordPath); wcscat(wszSrcFile, L"mods.d\\"); wcscat(wszSrcFile, confName); strcpy(tszDestFile, "mods.d\\"); strcat(tszDestFile, wstrtostr(confName)); hSrc = CeCreateFile(wszSrcFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSrc) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I'm struggling to open a file on your mobile device."); exit (-1); } hDest = CreateFile (tszDestFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDest) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem to write\n files to your PC. \n\nDo you have a mods.d directory where\n you put me?"); exit (-1); } if (CeReadFile(hSrc, &Buffer, sizeof(Buffer), &dwNumRead, NULL)) { if (!WriteFile(hDest, &Buffer, dwNumRead, &dwNumWritten, NULL)) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem to read the files on your mobile device."); exit (-1); } } else { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem to read the files on your mobile device."); exit (-1); } if (hSrc){ CeCloseHandle(hSrc); hSrc = NULL; } if (hDest){ CloseHandle (hDest); hDest = NULL; } } WCHAR* SRInstallMGR::PrintDirectory(LPWSTR Path, UINT Indent){ // recurse through device from root DWORD foundCount; LPCE_FIND_DATA findDataArray; WCHAR searchPath[MAX_PATH]; wcscpy(searchPath, Path); wcscat(searchPath, L"*"); if(!CeFindAllFiles(searchPath, FAF_ATTRIBUTES | FAF_NAME, &foundCount, &findDataArray)) { FXMessageBox::error(this,MBOX_OK,"CeFindAllFiles Process Failed","Sorry, I can't seem to read the files on your mobile device."); exit (-1); } if(!foundCount) return(NULL); for(UINT i = 0; i < foundCount; i++) { if(findDataArray[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // directory found WCHAR newPath[MAX_PATH]; wcscpy(newPath, Path); wcscat(newPath, findDataArray[i].cFileName); wcscat(newPath, L"\\"); PrintDirectory(newPath, Indent + 1); } else if ((stristr(wstrtostr(Path), "MODS.D"))){ // not directory - this is a file const char* modstr = stristr(wstrtostr(Path), "MODS.D"); wcscpy(swordPath, Path); int len = strlen (modstr); int swlen = wcslen (swordPath); while (len--) swlen--; swordPath[swlen] = 0; // global swordPath now set to CE sword dir /************************************************************************ // this refers to files on your mobile device, not your PC. // I don't want to do anything with files except when they are in your // MODS.D directory, so 'swordPath' at this point should be your sword // home directory+mods.d, so save it use return from stristr to truncate // I have assumed that mods.d occurs only once!!! There is one possible // additional instance (at least) .... // // TODO // note: have not checked for more than one installation: it is possible // for someone to have installed into several different locations - really! **************************************************************************/ copyconfs(findDataArray[i].cFileName); } // else if ((stristr(wstrtostr ...... } // for(UINT i = 0; ........ if (findDataArray) RapiFreeBuffer(findDataArray); return (swordPath); // swordPath is global ....... I don't like globals ... maybe a 'new' const wchar string would be better?? } void SRInstallMGR::CopyOver (WCHAR* sourceName, WCHAR* destName) { HANDLE hSrc, hCeDest; BYTE Buffer[10000]; DWORD dwNumRead, dwNumWritten; hSrc = CreateFile(wstrtostr(sourceName), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSrc) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem able to open source/host file on PC"); exit (-1); } hCeDest = CeCreateFile(destName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hCeDest ) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem able to open destination file file on your mobile device for writing"); exit (-1); } do { if (ReadFile(hSrc, &Buffer, sizeof(Buffer), &dwNumRead, NULL)) { if (!CeWriteFile(hCeDest, &Buffer, dwNumRead, &dwNumWritten, NULL)) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem able to open destination file file on your mobile device for writing"); exit (-1); } } else { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem able to open the source file file on your mobile device for writing"); exit (-1); } } while (dwNumRead); if (hCeDest){ CeCloseHandle(hCeDest); hCeDest = NULL; } if (hSrc){ CloseHandle (hSrc); hSrc = NULL; } } bool SRInstallMGR::fileExists(char *thisFile) { //char *thisFile = "sword.exe"; HANDLE isFile; isFile = CreateFile((const char*)thisFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == isFile) { CloseHandle (isFile); return false; } CloseHandle (isFile); return true; } void SRInstallMGR::getModulePath (LPCWSTR confName, char &outBuffer) { // each .conf file in mods.d comes here with name char longstr[10000]; const char *pathstr; char mPath[MAX_PATH]; char *modulePath = mPath; char thisName[MAX_PATH]; //BOOL isopen = FALSE; HANDLE modFile; DWORD BytesToRead; DWORD BytesRead = 0; WCHAR namstr[MAX_PATH]; WCHAR* name = namstr; wcscpy (name, L"mods.d\\"); wcscat (name, confName); BytesToRead = sizeof(longstr)-1; wcstombs(thisName, name,MAX_PATH); modFile = CreateFile(thisName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == modFile) { FXMessageBox::error(this,MBOX_OK,"Process failed","Sorry, I can't seem to read files in your mods.d directory. Do you have a mods.d directory where you put me?"); exit (-1); } // read the entire .conf file into our buffer - biggest I know of // now is a 5k .conf, so I've gone for a 10,000 byte buffer .... //isopen = ReadFile(modFile, &longstr, BytesToRead, &BytesRead, NULL); ReadFile(modFile, &longstr, BytesToRead, &BytesRead, NULL); // TODO we ought to check for success 'if isopen' and do something if (modFile){ CloseHandle(modFile); modFile = NULL; } pathstr = stristr (longstr, "DataPath=."); if (!pathstr){ FXMessageBox::error(this,MBOX_OK,"Process failed","Failed to make string match for DataPath=."); exit (-1); } pathstr+=10; // move pointer to end of 'DataPath=.' strcpy (modulePath, "");// this will need to be the swordPath int i = 0; int p = (strlen(modulePath)); p--; while (*(pathstr+i) != 10 && *(pathstr+i) != 13) { // some confs have cr/lf and some only lf (why?) *(modulePath+p++) = *(pathstr+i); i++; } --p; // if we don't want trailing slash *(modulePath+p) = 0; // at end of trailing slash in pathstring // TODO - lexdicts are handled differently in pathing char *tmp = modulePath; while (*(tmp++))if (*tmp == 47) *tmp = 92; // change '/' into '\' tmp = &outBuffer; strcpy (tmp, modulePath); } void SRInstallMGR::deleteCEFiles (LPCWSTR CEPath) { // delete all files in mobile device directory then delete directory WCHAR ThisFile[MAX_PATH]; DWORD foundCount; LPCE_FIND_DATA findDataArray; wcscpy(ThisFile, CEPath); wcscat(ThisFile, L"*"); if(!CeFindAllFiles(ThisFile, FAF_ATTRIBUTES | FAF_NAME, &foundCount, &findDataArray)) { // _tprintf( TEXT("*** CeFindAllFiles failed. ***\n")); return; // TODO needs error MessageBox here and bomb out } if(!foundCount) return; // TODO needs error MessageBox here and bomb out WCHAR newPath[MAX_PATH]; for(UINT i = 0; i < foundCount; i++) { wcscpy(newPath, CEPath); wcscat(newPath, findDataArray[i].cFileName); CeDeleteFile(newPath); } // for(UINT i = 0; i