/* (C) 2003 XDA Developers * Author: Willem Jan Hengeveld * Web: http://www.xda-developers.com/ * * $Header$ */ // adaptrom.cpp // // this tool gets the desired unknownnr, and language from the device, // and updates the local directory structure and nbf file accordingly // [ the 'PW10A1-ENG-3.16-007' string ] // only update PW10A* devices // don't update if more than 1 language dir was found // // optionally a commandline argument of '-only' can specify what devices to accept // // // should display a popup box when no device is found #include #include #include using namespace std; struct IRAPIStream; #include #include "debug.h" typedef vector bytelist; const char *szTitle= "Adapt ROM"; vector g_acceptList; bool g_verbose= false; bool g_just_fix_checksum= false; string g_nbfinfo; bool g_activeasync_needed= true; string tostring(const WCHAR *wstr) { string astr; while (*wstr) { astr += (char)*wstr++; } return astr; } string tolower(const string& str) { string lstr; for(string::const_iterator i= str.begin() ; i!=str.end() ; ++i) { lstr += tolower(*i); } return lstr; } bool ParseArg_only(char *arg) { char *p= strtok(arg, ","); while (p) { g_acceptList.push_back(tolower(p)); p= strtok(NULL, ","); } return true; } bool ParseCommandline(int argc, char **argv) { for (int i=1 ; iotherunknownnr); string version_lang= tostring(output->version); size_t spacepos= version_lang.find(' '); if (spacepos==string::npos) { printf("ERROR: invalid version+language string from device: '%s'\n", version_lang.c_str()); return false; } version= version_lang.substr(0, spacepos); language= version_lang.substr(spacepos+1); devicename= tostring(output->devicename); LocalFree(output); return true; } typedef struct _tagConnectionInfo { WCHAR unknownnr[50]; WCHAR connection[50]; } ConnectionInfo; bool GetConnectionType(string& connectionType, string& unknownnr) { ConnectionInfo *output=NULL; DWORD outputlen=0; HRESULT res= CeRapiInvoke(L"\\Windows\\GetConnectionType.dll", L"GetConnectionType", 0, 0, &outputlen, (BYTE**)&output, 0, 0); if (output==NULL) { error(res, "GetConnectionType"); return false; } connectionType= tostring(output->connection); unknownnr= tostring(output->unknownnr); LocalFree(output); return true; } wstring StringToWString(const string &str) { WCHAR *ws= new WCHAR[str.length()+2]; _snwprintf(ws, str.length()+1, L"%hs", str.c_str()); wstring wstr(ws); delete ws; return wstr; } typedef enum { FS_DIRECTORY, FS_FILE, FS_NOTFOUND, FS_NOACCESS } FileState; FileState CeGetFileState(const string &name) { DWORD dwAttr= CeGetFileAttributes(StringToWString(name).c_str()); //printf("%08lx : %hs\n", dwAttr, name.c_str()); if (dwAttr==INVALID_FILE_ATTRIBUTES) { DWORD dwError= CeGetLastError(); if (dwError==ERROR_FILE_NOT_FOUND || dwError==ERROR_PATH_NOT_FOUND) return FS_NOTFOUND; else { ceerror("attr=%08lx error=%08lx wname=%ls name=%hs rapi=%08lx\n", dwAttr, dwError, StringToWString(name).c_str(), name.c_str(), CeRapiGetError()); return FS_NOACCESS; } } else if (dwAttr & FILE_ATTRIBUTE_READONLY) return FS_NOACCESS; else if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) return FS_DIRECTORY; else return FS_FILE; } FileState GetFileState(const string &name) { DWORD dwAttr= GetFileAttributes(name.c_str()); if (dwAttr==INVALID_FILE_ATTRIBUTES) { DWORD dwError= GetLastError(); if (dwError==ERROR_FILE_NOT_FOUND || dwError==ERROR_PATH_NOT_FOUND) return FS_NOTFOUND; else return FS_NOACCESS; } else if (dwAttr & FILE_ATTRIBUTE_READONLY) return FS_NOACCESS; else if (dwAttr & FILE_ATTRIBUTE_DIRECTORY) return FS_DIRECTORY; else return FS_FILE; } bool CeCopyFileToDevice(const string& srcfile, const string& dstfile) { FileState lfs= GetFileState(srcfile); if (lfs!=FS_FILE) { printf("ERROR: '%s' does not exist (%d)\n", srcfile.c_str(), lfs); return false; } FileState cefs= CeGetFileState(dstfile); if (cefs==FS_FILE) { if (g_verbose) printf("CE: %s is already there\n", dstfile.c_str()); return true; } if (cefs==FS_DIRECTORY || cefs==FS_NOACCESS) { printf("CE: %s is inaccessible (%d)\n", dstfile.c_str(), cefs); return false; } if (g_verbose) printf("copying %s to CE:%s\n", srcfile.c_str(), dstfile.c_str()); HANDLE hSrc = CreateFile( srcfile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hSrc) { ceerror("Unable to open local file '%s'", srcfile.c_str()); return false; } HANDLE hDest = CeCreateFile( StringToWString(dstfile).c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDest ) { if (g_verbose) ceerror("Unable to open WinCE file '%s'", dstfile.c_str()); CloseHandle(hSrc); return false; } bool bRes= false; BYTE Buffer[16384]; DWORD dwNumRead; do { if (ReadFile( hSrc, &Buffer, sizeof(Buffer), &dwNumRead, NULL)) { DWORD dwNumWritten; if (!CeWriteFile( hDest, &Buffer, dwNumRead, &dwNumWritten, NULL)) { ceerror("Error Writing WinCE file"); goto FatalError; } } else { ceerror("Error Reading local file"); goto FatalError; } } while (dwNumRead); bRes= true; FatalError: CeCloseHandle( hDest); CloseHandle (hSrc); return bRes; } bool TestDeviceSupport(const string& devicename) { // empty list : accept all devices if (g_acceptList.empty()) return true; for(size_t i=0 ; i < g_acceptList.size() ; i++) { if (g_acceptList[i].compare(tolower(devicename))==0) return true; } return false; } bool GetDirectoryForLanguage(const string& language, string& directory) { if (language.compare("ENG")==0) { directory= "English"; return true; } if (language.compare("FRE")==0) { directory= "French"; return true; } if (language.compare("GER")==0) { directory= "German"; return true; } if (language.compare("ITA")==0) { directory= "Italian"; return true; } if (language.compare("JPN")==0) { directory= "Japanese"; return true; } if (language.compare("ESP")==0) { directory= "Spanish"; return true; } if (language.compare("CHT")==0) { directory= "TChinese"; return true; } if (language.compare("CHS")==0) { directory= "SChinese"; return true; } printf("ERROR: unsupported language\n"); return false; } bool UpdateNBFHeader(const string& nbfpath, string& devicename, string& version, string& language, string& unknownnr, DWORD bodysum) { size_t i; char hdrbuf[33]; _snprintf(hdrbuf, 32, "%.6s-%.3s-%.4s-%.3s", devicename.c_str(), language.c_str(), version.c_str(), unknownnr.c_str()); if (strlen(hdrbuf)!=19) { printf("ERROR generating new header: '%s'\n", hdrbuf); return false; } DWORD hdrsum= 0; for (i=0 ; i<19 ; i++) hdrsum += hdrbuf[i]; _snprintf(hdrbuf+19, 32-19, "-%x", (hdrsum+bodysum)&0xffff); hdrbuf[32]= 0; for (i= strlen(hdrbuf) ; i<32 ; i++) hdrbuf[i]= '-'; FILE *f= fopen(nbfpath.c_str(), "r+b"); if (f==NULL) { error("fopen('%s')\n", nbfpath.c_str()); return false; } if (fseek(f, 0, SEEK_SET)) { error("fseek"); fclose(f); return false; } if (1!=fwrite(hdrbuf, 32, 1, f)) { error("fwrite"); fclose(f); return false; } if (fseek(f, 0, SEEK_END)) { error("fseek"); fclose(f); return false; } fclose(f); return true; } /* bool GetRegistryValue(DWORD dwHive, const string& key, const string& valuename, bytelist &value, DWORD& type) { HKEY hKey; if (ERROR_SUCCESS!=CeRegOpenKeyEx(dwHive, StringToWString(key).c_str(), 0, 0, &hKey)) return false; DWORD type; DWORD vallen; if (ERROR_SUCCESS!=CeRegQueryValueEx(hKey, StringToWString(valuename).c_str(), 0, &type, NULL, &vallen)) return false; BYTE *data= new BYTE[vallen]; if (ERROR_SUCCESS!=CeRegQueryValueEx(hKey, StringToWString(valuename).c_str(), 0, &type, value, &vallen)) return false; CeRegCloseKey(hkey); value.assign(data, data+vallen); delete data; return true; } bool GetCalibrationData(bytelist& data) { DWORD type; if (!GetRegistryValue(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\TOUCH", "CalibrationData", data, type)) return false; return (type==REG_SZ); } bool GetOwnerInfo(bytelist& ownerinfo, bytelist& ownernotes) { DWORD type; if (!GetRegistryValue(HKEY_CURRENT_USER, "ControlPanel\\Owner", "Owner", ownerinfo, type)) return false; if (!GetRegistryValue(HKEY_CURRENT_USER, "ControlPanel\\Owner", "Notes", ownernotes, type)) return false; return true; } int addtodata(BYTE *data, char *identifier, const bytelist& data) { int len=0; memcpy(data, identifier, 32); len+=32; DWORD size= data.size(); memcpy(data+len, &size, sizeof(DWORD); len+=sizeof(DWORD); memcpy(data+len, data.begin(), data.size()); len+=data.size(); return len; } bool SaveRegistryDataInNBF(const string& nbfpath, BYTE *registrydata, int datalen) { FILE *f= fopen(nbfpath.c_str(), "r+b"); if (f==NULL) { error("fopen('%s')\n", nbfpath.c_str()); return false; } if (fseek(f, 0x81925800-0x80000000+0x20, SEEK_SET)) { error("fseek"); fclose(f); return false; } if (1!=fwrite(registrydata, datalen, 1, f)) { error("fwrite"); fclose(f); return false; } if (fseek(f, 0, SEEK_END)) { error("fseek"); fclose(f); return false; } fclose(f); } */ bool GetParametersFromDevice(const string nbfdirectory, string& dev_devicename, string& dev_language, string& dev_version, string& dev_unknownnr) { string dev_otherunknownnr; // '32' most of the time if (!GetDeviceData(dev_devicename, dev_language, dev_version, dev_otherunknownnr)) { printf("error getting devicedata\n"); return false; } if (g_verbose) printf("device: device='%s', language='%s', version='%s', otherunknownnr='%s'\n", dev_devicename.c_str(), dev_language.c_str(), dev_version.c_str(), dev_otherunknownnr.c_str()); if (!TestDeviceSupport(dev_devicename)) { printf("unsupported target device '%s'\n", dev_devicename.c_str()); return false; } if (!CeCopyFileToDevice(concatpath(nbfdirectory, "GetConnectionType.dll"), string("\\Windows\\GetConnectionType.dll"))) { if (g_verbose) printf("error copying 'GetConnectionType.dll' to device\n"); //return false; -- not an error } string dev_connectionType; if (!GetConnectionType(dev_connectionType, dev_unknownnr)) { printf("error getting connectiontype\n"); return false; } if (g_verbose) printf("device: conntype='%s', unknownnr='%s'\n", dev_connectionType.c_str(), dev_unknownnr.c_str()); return true; } bool UpdateProgrammeA() { string curdir; if (!GetCurrentDirectory(curdir)) { printf("error getting current directory\n"); return false; } ///////////////////////////////////////////////////////////////////////// // first check local items string nbfdirectory; if (!FindNBFDirectory(curdir, nbfdirectory)) { printf("nbf directory not found in '%s'\n", curdir.c_str()); return false; } if (g_verbose) printf("nbfdir=%s\n", nbfdirectory.c_str()); string nbffile; if (!FindNBFFile(nbfdirectory, nbffile)) { printf("nbf file not found in directory '%s'\n", nbfdirectory.c_str()); return false; } if (g_verbose) printf("nbffile=%s\n", nbffile.c_str()); ///////////////////////////////////////////////////////////////////////// // get parameters from nbf file string nbf_devicename, nbf_language, nbf_version, nbf_unknownnr; DWORD nbf_filesum, calced_headersum; if (!ReadNBFHeader(nbffile, nbf_devicename, nbf_language, nbf_version, nbf_unknownnr, nbf_filesum, calced_headersum)) { printf("error reading header from nbf file '%s'\n", nbffile.c_str()); return false; } if (g_verbose) printf("nbffile: device='%s', language='%s', version='%s', unknownnr='%s'\n", nbf_devicename.c_str(), nbf_language.c_str(), nbf_version.c_str(), nbf_unknownnr.c_str()); DWORD calced_filebody_sum; if (!CalculateFileChecksum(nbffile, calced_filebody_sum)) { printf("error calculating checksum for file '%s'\n", nbffile.c_str()); return false; } if (g_verbose) { printf("original header=%04x\ncalced: headersum=%04x bodysum=%08x : %04x\n", nbf_filesum, calced_headersum, calced_filebody_sum, (calced_filebody_sum+calced_headersum)&0xffff); } if (!g_just_fix_checksum && ((calced_filebody_sum+calced_headersum)&0xffff)!=nbf_filesum) { printf("calculated checksum(%04x) does not match header checksum(%04x)\n", calced_filebody_sum+calced_headersum, nbf_filesum); } string new_devicename; string new_version; string new_language; string new_unknownnr;// '007' for O2 and qtek roms, '003' for t-mobile roms if (!g_nbfinfo.empty()) { // or get it from the commandline specified arguments if (!ParseNbfInfo(g_nbfinfo, new_devicename, new_language, new_version, new_unknownnr)) return false; } else if (g_just_fix_checksum) { new_devicename= nbf_devicename; new_language= nbf_language; new_version= nbf_version; new_unknownnr= nbf_unknownnr; } else { ///////////////////////////////////////////////////////////////////////// // get parameters from device if (!GetParametersFromDevice(nbfdirectory, new_devicename, new_language, new_version, new_unknownnr)) return false; } string new_directory; if (!GetDirectoryForLanguage(new_language, new_directory)) { printf("unsupported language '%s'\n", new_language.c_str()); return false; } if (g_verbose) printf("newlanguagedir='%s'\n", new_directory.c_str()); ///////////////////////////////////////////////////////////////////////// // now do the actual updating if (!UpdateNBFHeader(nbffile, new_devicename, nbf_version, new_language, new_unknownnr, calced_filebody_sum)) { printf("error updating nbffile '%s'\n", nbffile.c_str()); return false; } /* ///////////////////////////////////////////////////////////////////////// // get ownerinfo int datamaxlen= 4*65536-0x25800; BYTE data[4*65536-0x25800]; int datapos=0; bytelist ownerinfo; bytelist ownernotes; if (GetOwnerInfo(ownerinfo, ownernotes)) { datapos += addtodata(data+datapos, "OwnerInfo", ownerinfo); datapos += addtodata(data+datapos, "OwnerNotes", ownernotes); } ///////////////////////////////////////////////////////////////////////// // get calibration info bytelist calibrationdata; if (GetCalibrationData(calibrationdata)) { datapos += addtodata(data+datapos, "CalibrationData", calibrationdata); } SaveRegistryDataInNBF(nbffile, data, datapos); */ string newpath= concatpath(curdir, new_directory); if (tolower(nbfdirectory).compare(tolower(new_directory)) != 0) { if (!MoveFile(nbfdirectory.c_str(), new_directory.c_str())) { printf("error renaming language directory from '%s' to '%s'\n", nbfdirectory.c_str(), new_directory.c_str()); return false; } } return true; } bool WaitForDevice() { RAPIINIT rinit; rinit.cbSize= sizeof(RAPIINIT); rinit.heRapiInit= NULL; rinit.hrRapiInit= -1; if (CeRapiInitEx(&rinit)) { error("CeRapiInit"); return false; } do { DWORD res= MsgWaitForMultipleObjects(1, &rinit.heRapiInit, false, 1000, 0); if (res==WAIT_OBJECT_0) break; if (res!=WAIT_TIMEOUT) { if (g_verbose) { error("waiting for rapi init"); return false; } } res= MessageBox(0, "Please connect your XDA to activesync", "Adapt ROM", MB_RETRYCANCEL); if (res==IDCANCEL) return false; } while(1); if (rinit.hrRapiInit) { MessageBox(0, "Error connecting to XDA", szTitle, MB_ICONERROR); return false; } return true; } int main(int argc, char* argv[]) { if (!ParseCommandline(argc, argv)) return 1; g_activeasync_needed= g_nbfinfo.empty() && !g_just_fix_checksum; if (g_activeasync_needed && !WaitForDevice()) return 1; /* if (CeRapiInit()) { error("CeRapiInit"); return 1; } */ UpdateProgrammeA(); if (!g_activeasync_needed) CeRapiUninit(); return 0; }