bjavaloader.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       bjavaloader.cc
00003 ///
00004 ///
00005 
00006 /*
00007     Copyright (C) 2008-2009, Nicolas VIVIEN
00008     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00009 
00010         Some parts are inspired from btool.cc
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021     See the GNU General Public License in the COPYING file at the
00022     root directory of this project for more details.
00023 */
00024 
00025 
00026 #include <barry/barry.h>
00027 #include <iostream>
00028 #include <vector>
00029 #include <string>
00030 #include <cstring>
00031 #include <algorithm>
00032 #include <fstream>
00033 #include <string.h>
00034 #include <time.h>
00035 #include "i18n.h"
00036 
00037 #include "barrygetopt.h"
00038 
00039 // supported javaloader commands
00040 #define CMD_LIST                "dir"
00041 #define CMD_ERASE               "erase"
00042 #define CMD_LOAD                "load"
00043 #define CMD_SCREENSHOT          "screenshot"
00044 #define CMD_SETTIME             "settime"
00045 #define CMD_EVENTLOG            "eventlog"
00046 #define CMD_CLEAR_LOG           "cleareventlog"
00047 #define CMD_SAVE                "save"
00048 #define CMD_DEVICEINFO          "deviceinfo"
00049 #define CMD_WIPE                "wipe"
00050 #define CMD_LOGSTRACES          "logstacktraces"
00051 #define CMD_RESETFACTORY        "resettofactory"
00052 
00053 // time string format specifier and user friendly description
00054 #define TIME_FMT         "%Y-%m-%d %H:%M:%S"
00055 #define TIME_FMT_EXAMPLE "yyyy-mm-dd HH:MM:SS"
00056 
00057 using namespace std;
00058 using namespace Barry;
00059 
00060 void Usage()
00061 {
00062    int logical, major, minor;
00063    const char *Version = Barry::Version(logical, major, minor);
00064 
00065    cerr
00066    << "bjavaloader - Command line USB Blackberry Java Loader\n"
00067    << "        Copyright 2008-2009, Nicolas VIVIEN.\n"
00068    << "        Copyright 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)\n"
00069    << "        Using: " << Version << "\n"
00070    << "\n"
00071    << "   -A        Save all modules found\n"
00072    << "   -a        Wipe applications only\n"
00073    << "   -i        Wipe filesystem only\n"
00074    << "   -f        Force erase, if module is in use\n"
00075    << "   -h        This help\n"
00076    << "   -s        List sibling in module list\n"
00077    << "   -p pin    PIN of device to talk with\n"
00078    << "             If only one device is plugged in, this flag is optional\n"
00079    << "   -P pass   Simplistic method to specify device password\n"
00080    << "   -v        Dump protocol data during operation\n"
00081    << "\n"
00082    << "commands\n"
00083    << "\n"
00084    << "   " << CMD_LIST << " [-s]\n"
00085    << "      Lists modules on the handheld\n"
00086    << "\n"
00087    << "   " << CMD_DEVICEINFO << "\n"
00088    << "      Provides information on the handheld\n"
00089    << "\n"
00090    << "   " << CMD_LOAD << " <.cod file> ...\n"
00091    << "      Loads modules onto the handheld\n"
00092    << "\n"
00093    << "   " << CMD_SAVE << " [-A] <module name> ...\n"
00094    << "      Retrieves modules from the handheld and writes to .cod file\n"
00095    << "      Note: will overwrite existing files!\n"
00096    << "\n"
00097    << "   " << CMD_WIPE << " [-a | -i]\n"
00098    << "      Wipes the handheld\n"
00099    << "      Use Caution: Wiping filesystem will remove all data\n"
00100    << "                   such as messages, contacts, etc.\n"
00101    << "                   Wiping applications will remove all .cod files\n"
00102    << "                   on the device, including OS .cod files.\n"
00103    << "\n"
00104    << "   " << CMD_RESETFACTORY << "\n"
00105    << "      Reset IT policy to factory defaults\n"
00106    << "      Use Caution: Resetting IT policy to factory defaults will\n"
00107    << "                   also perform a filesystem wipe which will remove\n"
00108    << "                   all data such as messages, contacts, etc.\n"
00109    << "\n"
00110    << "   " << CMD_ERASE << " [-f] <module name> ...\n"
00111    << "      Erase module from handheld\n"
00112    << "\n"
00113    << "   " << CMD_EVENTLOG << "\n"
00114    << "      Retrieves the handheld event log\n"
00115    << "\n"
00116    << "   " << CMD_CLEAR_LOG << "\n"
00117    << "      Clears the handheld event log\n"
00118    << "\n"
00119    << "   " << CMD_LOGSTRACES << "\n"
00120    << "      Dump the stack traces for all threads to the event log\n"
00121    << "\n"
00122    << "   " << CMD_SCREENSHOT << " <.bmp file>\n"
00123    << "      Make a screenshot of handheld\n"
00124    << "\n"
00125    << "   " << CMD_SETTIME << " [" << TIME_FMT_EXAMPLE << "]\n"
00126    << "      Sets the time on the handheld to the current time\n"
00127    << "      Or the time specified as an argument to " << CMD_SETTIME << "\n"
00128    << "      If given as argument, current system timezone is assumed\n"
00129    << endl;
00130 }
00131 
00132 
00133 class AutoClose
00134 {
00135         FILE *fp;
00136 
00137 public:
00138         AutoClose(FILE *fh) : fp(fh) {}
00139         ~AutoClose()
00140         {
00141                 fclose(fp);
00142         }
00143 };
00144 
00145 void SetTime(Barry::Mode::JavaLoader *javaloader, const char *timestr)
00146 {
00147         time_t when;
00148 
00149         if( timestr ) {
00150                 struct tm timeinfo;
00151                 memset(&timeinfo, 0, sizeof(timeinfo));
00152 
00153                 // parse time string
00154                 char *p = strptime(timestr, TIME_FMT, &timeinfo);
00155 
00156                 // NULL is return when strptime fails to match all of the format
00157                 // string, and returns a pointer to the NULL byte at the end of
00158                 // the input string on success
00159                 if( p == NULL || p != (timestr + strlen(timestr)) ) {
00160                         throw runtime_error(string("Unable to parse time string: ") + timestr);
00161                 }
00162 
00163                 when = mktime(&timeinfo);
00164         } else { // time string is NULL, get current time
00165                 time(&when);
00166         }
00167 
00168         javaloader->SetTime(when);
00169 }
00170 
00171 void SendAppFile(Barry::Mode::JavaLoader *javaloader, const char *filename)
00172 {
00173         ifstream file(filename);
00174         javaloader->LoadApp(file);
00175 }
00176 
00177 void GetScreenshot(Barry::Mode::JavaLoader *javaloader, const char *filename)
00178 {
00179 
00180         // Take a screenshot
00181         //   - info object contains the screenshot properties (width, height...)
00182         //   - image will be filled with the raw pixel screenshot data
00183         JLScreenInfo info;
00184         Data image;
00185         javaloader->GetScreenshot(info, image);
00186 
00187 
00188         // Convert to BMP format
00189         Data bitmap(-1, GetTotalBitmapSize(info));
00190         ScreenshotToBitmap(info, image, bitmap);
00191 
00192         // Write BMP file
00193         FILE *fp = fopen(filename, "wb");
00194         if (fp == NULL) {
00195                 throw runtime_error(string("Can't open: ") + filename);
00196         }
00197         AutoClose ac(fp);
00198 
00199         fwrite(bitmap.GetData(), bitmap.GetSize(), 1, fp);
00200 }
00201 
00202 void SaveModule(Barry::Mode::JavaLoader *javaloader, const char *filename)
00203 {
00204         string fname(filename), module;
00205 
00206         size_t ext_index = fname.rfind(".cod");
00207         if( ext_index != string::npos ) {
00208                 // filename contains .cod extension, strip it for module name
00209                 module = fname.substr(0, ext_index);
00210         }
00211         else {
00212                 // filename does not contain .cod extension, use it as module name
00213                 module = fname;
00214                 // append extension to file name
00215                 fname.append(".cod");
00216         }
00217 
00218         ofstream file(fname.c_str(), ios::binary | ios::trunc);
00219         javaloader->Save(module.c_str(), file);
00220 }
00221 
00222 
00223 int main(int argc, char *argv[])
00224 {
00225         INIT_I18N(PACKAGE);
00226 
00227         cout.sync_with_stdio(true);     // leave this on, since libusb uses
00228                                         // stdio for debug messages
00229 
00230         try {
00231 
00232                 uint32_t pin = 0;
00233                 bool list_siblings = false,
00234                         force_erase = false,
00235                         data_dump = false,
00236                         all_modules = false,
00237                         wipe_apps = true,
00238                         wipe_fs = true;
00239                 string password;
00240                 vector<string> params;
00241                 string busname;
00242                 string devname;
00243                 string iconvCharset;
00244                 Usb::EndpointPair epOverride;
00245 
00246                 // process command line options
00247                 for(;;) {
00248                         int cmd = getopt(argc, argv, "Aaifhsp:P:v");
00249                         if( cmd == -1 )
00250                                 break;
00251 
00252                         switch( cmd )
00253                         {
00254                         case 'p':       // Blackberry PIN
00255                                 pin = strtoul(optarg, NULL, 16);
00256                                 break;
00257 
00258                         case 'P':       // Device password
00259                                 password = optarg;
00260                                 break;
00261 
00262                         case 'f':       // turn on 'force' mode for erase
00263                                 force_erase = true;
00264                                 break;
00265 
00266                         case 's':       // turn on listing of sibling modules
00267                                 list_siblings = true;
00268                                 break;
00269 
00270                         case 'v':       // data dump on
00271                                 data_dump = true;
00272                                 break;
00273 
00274                         case 'A':       // save all modules
00275                                 all_modules = true;
00276                                 break;
00277 
00278                         case 'a':       // wipe apps only
00279                                 wipe_fs = false;
00280                                 break;
00281 
00282                         case 'i':       // wipe filesystem
00283                                 wipe_apps = false;
00284                                 break;
00285 
00286                         case 'h':       // help
00287                         default:
00288                                 Usage();
00289                                 return 0;
00290                         }
00291                 }
00292 
00293                 argc -= optind;
00294                 argv += optind;
00295 
00296                 if( argc < 1 ) {
00297                         cerr << "missing command" << endl;
00298                         Usage();
00299                         return 1;
00300                 }
00301 
00302                 // Fetch command from remaining arguments
00303                 string cmd = argv[0];
00304                 argc --;
00305                 argv ++;
00306 
00307                 // Put the remaining arguments into an array
00308                 for (; argc > 0; argc --, argv ++) {
00309                         params.push_back(string(argv[0]));
00310                 }
00311 
00312                 // Initialize the barry library.  Must be called before
00313                 // anything else.
00314                 Barry::Init(data_dump);
00315 
00316                 // Probe the USB bus for Blackberry devices and display.
00317                 // If user has specified a PIN, search for it in the
00318                 // available device list here as well
00319                 Barry::Probe probe;
00320                 int activeDevice = probe.FindActive(pin);
00321                 if( activeDevice == -1 ) {
00322                         cerr << "No device selected, or PIN not found" << endl;
00323                         return 1;
00324                 }
00325 
00326                 // Create our controller object
00327                 Barry::Controller con(probe.Get(activeDevice));
00328                 Barry::Mode::JavaLoader javaloader(con);
00329 
00330                 //
00331                 // execute each mode that was turned on
00332                 //
00333                 javaloader.Open(password.c_str());
00334                 javaloader.StartStream();
00335 
00336                 if( cmd == CMD_LIST ) {
00337                         JLDirectory dir;
00338                         javaloader.GetDirectory(dir, list_siblings);
00339                         cout << dir;
00340                 }
00341                 else if( cmd == CMD_LOAD ) {
00342                         if( params.size() == 0 ) {
00343                                 cerr << "specify at least one .cod file to load" << endl;
00344                                 Usage();
00345                                 return 1;
00346                         }
00347 
00348                         vector<string>::iterator i = params.begin(), end = params.end();
00349                         for( ; i != end; ++i ) {
00350                                 cout << "loading " << (*i) << "... ";
00351                                 SendAppFile(&javaloader, (*i).c_str());
00352                                 cout << "done." << endl;
00353                         }
00354                 }
00355                 else if( cmd == CMD_ERASE ) {
00356                         if( params.size() == 0 ) {
00357                                 cerr << "specify at least one module to erase" << endl;
00358                                 Usage();
00359                                 return 1;
00360                         }
00361 
00362                         vector<string>::iterator i = params.begin(), end = params.end();
00363                         for( ; i != end; ++i ) {
00364                                 cout << "erasing: " << (*i) << "... ";
00365                                 if( force_erase )
00366                                         javaloader.ForceErase((*i));
00367                                 else
00368                                         javaloader.Erase((*i));
00369                                 cout << "done." << endl;
00370                         }
00371                 }
00372                 else if( cmd == CMD_SCREENSHOT ) {
00373                         if( params.size() == 0 ) {
00374                                 cerr << "specify a .bmp filename" << endl;
00375                                 Usage();
00376                                 return 1;
00377                         }
00378 
00379                         GetScreenshot(&javaloader, params[0].c_str());
00380                 }
00381                 else if( cmd == CMD_SETTIME ) {
00382                         if( params.size() > 0 ) {
00383                                 SetTime(&javaloader, params[0].c_str());
00384                         } else {
00385                                 SetTime(&javaloader, NULL);
00386                         }
00387                 }
00388                 else if( cmd == CMD_EVENTLOG ) {
00389                         JLEventlog log;
00390                         javaloader.GetEventlog(log);
00391                         cout << log;
00392                 }
00393                 else if( cmd == CMD_CLEAR_LOG ) {
00394                         javaloader.ClearEventlog();
00395                 }
00396                 else if( cmd == CMD_LOGSTRACES ) {
00397                         javaloader.LogStackTraces();
00398                 }
00399                 else if( cmd == CMD_SAVE ) {
00400                         if( all_modules ) {
00401                                 JLDirectory dir;
00402                                 javaloader.GetDirectory(dir, false);
00403                                 JLDirectory::BaseIterator i = dir.begin();
00404                                 for( ; i != dir.end(); ++i ) {
00405                                         cout << "saving: " << i->Name << "... ";
00406                                         SaveModule(&javaloader,i->Name.c_str());
00407                                         cout << "done." << endl;
00408                                 }
00409                         }
00410                         else if( params.size() == 0 ) {
00411                                 cerr << "specify at least one module to save" << endl;
00412                                 Usage();
00413                                 return 1;
00414                         }
00415                         else {
00416                                 vector<string>::iterator i = params.begin(), end = params.end();
00417                                 for( ; i != end; ++i ) {
00418                                         cout << "saving: " << (*i) << "... ";
00419                                         SaveModule(&javaloader, (*i).c_str());
00420                                         cout << "done." << endl;
00421                                 }
00422                         }
00423                 }
00424                 else if( cmd == CMD_DEVICEINFO ) {
00425                         JLDeviceInfo info;
00426                         javaloader.DeviceInfo(info);
00427                         cout << info;
00428                 }
00429                 else if( cmd == CMD_WIPE ) {
00430                         cout
00431                                 << "Use Caution: Wiping filesystem will remove all data\n"
00432                                 << "             such as messages, contacts, etc.\n"
00433                                 << "             Wiping applications will remove all .cod files\n"
00434                                 << "             on the device, including OS .cod files.\n\n"
00435                                 << "You have selected to wipe the filesystem of device '" << probe.Get(activeDevice).m_pin.Str() << "'\n"
00436                                 << "Continue with wipe? (yes/no) ";
00437                         string confirm;
00438                         getline(cin, confirm);
00439                         if( confirm == "yes" ) {
00440                                 javaloader.Wipe(wipe_apps, wipe_fs);
00441                         }
00442                         else {
00443                                 cout << "Response of 'yes' not received, aborting." << endl;
00444                         }
00445                 }
00446                 else if( cmd == CMD_RESETFACTORY ) {
00447                         cout
00448                                 << "Use Caution: Resetting IT policy to factory defaults will\n"
00449                                 << "             also perform a filesystem wipe which will remove\n"
00450                                 << "             all data such as messages, contacts, etc.\n\n"
00451                                 << "You have selected to reset device '" << probe.Get(activeDevice).m_pin.Str() << "' to factory defaults\n"
00452                                 << "Continue with wipe? (yes/no) ";
00453                         string confirm;
00454                         getline(cin, confirm);
00455                         if( confirm == "yes" ) {
00456                                 javaloader.ResetToFactory();
00457                         }
00458                         else {
00459                                 cout << "Response of 'yes' not received, aborting." << endl;
00460                         }
00461                 }
00462                 else {
00463                         cerr << "invalid command \"" << cmd << "\"" << endl;
00464                         Usage();
00465                         return 1;
00466                 }
00467 
00468                 // Stop
00469                 javaloader.StopStream();
00470 
00471         }
00472         catch( Usb::Error &ue) {
00473                 std::cout << endl;      // flush any normal output first
00474                 std::cerr << "Usb::Error caught: " << ue.what() << endl;
00475                 return 1;
00476         }
00477         catch( Barry::Error &se ) {
00478                 std::cout << endl;
00479                 std::cerr << "Barry::Error caught: " << se.what() << endl;
00480                 return 1;
00481         }
00482         catch( std::exception &e ) {
00483                 std::cout << endl;
00484                 std::cerr << "std::exception caught: " << e.what() << endl;
00485                 return 1;
00486         }
00487 
00488         return 0;
00489 }
00490