/* umtsmon - a program to control/monitor your UMTS card * This file copyright (C) 2006, 2008 Klaas van Gend * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation * applicable version is GPL version 2 only. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "umtsmon_global.h" #include "mainwindow.h" #include "TheDeviceManagerSingleton.h" #include "Runner.h" #include "Popup.h" #include "Internationalisation.h" #include #include #include #include #include #include // forward declarations void popupAbortMessageBox(int); void printAbortMessage(int); static const int MAXLONGCOMMANDSIZE = 20; static const int MAXSHORTCOMMANDSIZE = 4; // oops global variable declared here... // let's make sure they do not multiply :-) int theVerbosity = 1; int thePPPVerbosity = 0; static char* theLocale = NULL; static bool setDefProfile(char* anArgument) { DEBUG5("setDefProfile: '%s'\n", anArgument); // all argument checking is done in in the class :-D if (Profile::setActiveProfile(anArgument) == false) { printf("ERROR: Profile \"%s\" does not exist\n", anArgument); exit(2); } return true; } static bool setForceAutodetection( __attribute__ ((unused)) char* anArgument) { TheDeviceManagerSingleton::me().setForceAutodetection(); return true; } static bool setLocale(char* anArgument) { // will be parsed/verified later in main() theLocale = anArgument; return true; } static bool setAutoConnect(__attribute__ ((unused)) char* anArgument) { DEBUG5("setautoconnect\n"); TheSettingsSingleton::getTQSRef().writeEntry(theGeneralAutoConnectSettingName, true); return true; } static bool setNoAutoConnect(__attribute__ ((unused)) char* anArgument) { DEBUG5("setNOautoconnect\n"); TheSettingsSingleton::getTQSRef().writeEntry(theGeneralAutoConnectSettingName, false); return true; } static bool setSerial(char* anArgument) { DEBUG5("setSerial: '%s'\n", anArgument); // no need to do advanced parameter checking // - that'll be done later on, right? // is there a comma in? in that case we neet to set both AT and PPP TQStringList myList = TQStringList::split(',', anArgument); switch (myList.count()) { case 1: TheDeviceManagerSingleton::me().setSuggestedAT(myList[0]); TheDeviceManagerSingleton::me().setSuggestedPPP(""); TheDeviceManagerSingleton::me().setSuggestedDeviceType(DeviceCapabilities::GENERIC_USER_SERIAL); break; case 2: TheDeviceManagerSingleton::me().setSuggestedAT(myList[0]); TheDeviceManagerSingleton::me().setSuggestedPPP(myList[1]); TheDeviceManagerSingleton::me().setSuggestedDeviceType(DeviceCapabilities::GENERIC_USER_SERIAL); break; default: printf("ERROR: supply max 2 devices to --serial\n"); exit(2); break; } return true; } static bool setVerbosity(char* anArgument) { DEBUG1("setVerbosity: '%s'\n", anArgument); // the argument should be a number. Let's parse. int myNumber = atoi(anArgument); if (myNumber < 1 || myNumber > MAX_VERBOSITY) { printf("ERROR: verbosity argument should be between 1 and 5\n"); return false; } theVerbosity = myNumber; DEBUG2("set verbosity level to %d\n", theVerbosity); // check if we have a second argument after a comma (ppp-verbosity) char* comma = strchr(anArgument, ','); if (comma != NULL) { myNumber = atoi(comma + 1); if (myNumber < 0 || myNumber > 2) { printf("ERROR: PPP verbosity argument should be between 0 and 2\n"); return false; } thePPPVerbosity = myNumber; } else { // verbosity > 2 => pppverbosity = 1; verbosity > 4 => pppverbosity = 2 thePPPVerbosity = (theVerbosity - 1) / 2; } DEBUG2("set PPP verbosity level to %d\n", thePPPVerbosity); return true; } static bool help( __attribute__ ((unused)) char* anArgument) { printf(APPNAME " " APPRELEASE "" APPFLAVOUR "\n\nhelp text\n\n"); printf(" --help gives this help text\n"); printf(" -h gives this help text\n"); printf(" --force-autodetect force autodetection (don't use info from config file)\n"); printf(" --serial [,ppp] will prevent autodetection of devices and use serial port [,]\n"); printf(" -s [,] will prevent autodetection of devices and use serial port [,]\n"); printf(" --verbosity [,ppplvl] set verbosity, 1=little (default), %d=all\n", MAX_VERBOSITY); printf(" -v [,ppplvl] set verbosity\n"); printf(" --language set the language, e.g. nl or pt_BR\n"); printf(" --autoconnect set autoconnect to true (persistant!)\n"); printf(" --no-autoconnect set autoconnect to false (persistant!)\n"); printf(" --default-profile sets the default profile to connect with (persistant!)\n"); printf("\n(parameters in <> are required, parameters in [] are optional)\n"); printf("\n"); exit(1); } /// the formatting for theArgsTable struct ArgsStruct { char theFullCommand [MAXLONGCOMMANDSIZE]; char theShortCommand[MAXSHORTCOMMANDSIZE]; bool needsArgument; bool (*theFunctionPtr)(char* anArgument); }; static ArgsStruct theArgsTable[] = { // long, short, has args, function name { "--help", "-h", false, help, }, { "--serial", "-s", true, setSerial, }, { "--verbosity", "-v", true, setVerbosity, }, { "--force-autodetect", "", false, setForceAutodetection, }, { "--language", "", true, setLocale, }, { "--autoconnect", "", false, setAutoConnect, }, { "--no-autoconnect", "", false, setNoAutoConnect, }, { "--default-profile", "-p", true, setDefProfile, }, // keep this one last { "\0", "\0", false, NULL, }, }; /** compare strings. * @returns If 0, no match, if positive nonzero: the character at this index is extra */ static int compareStrings(const char* anArgument, const char* aCommand) { int i=0; while(true) { // we're at the end of the command - a match, maybe with info left... if (aCommand[i] == 0) return i; // the argument is shorter than the command - cannot be a match :-( if (anArgument[i] == 0) break; if (anArgument[i] != aCommand[i]) break; i++; } // if we get here, it was no match :-( return 0; } int main( int argc, char **argv ) { TQApplication myTQApp( argc, argv ); puts( APPNAME " version " APPRELEASE "" APPFLAVOUR " ." ); // perform command line parsing // skip argv[0] because we know what's in there for ( int i = 1; i < myTQApp.argc(); i++ ) { int myMatchPoint = 0; char* myArgvPtr = myTQApp.argv()[i]; ArgsStruct* myTEntry; for (int j = 0; theArgsTable[j].theFullCommand[0]!='\0'; j++) { myTEntry = &(theArgsTable[j]); myMatchPoint = compareStrings(myArgvPtr, myTEntry->theFullCommand); if (myMatchPoint) break; myMatchPoint = compareStrings(myArgvPtr, myTEntry->theShortCommand); if (myMatchPoint) break; } // end of the 'j' loop if (myMatchPoint) { char* anArgument = NULL; // there are several cases: // 1) -s 3 // 2) -s3 // 3) -s=3 // 4) --serial=3 // 5) --serial 3 // 6) --help (no arguments) // 7) -h (no arguments) // cases 1,2,3,4,5: if (myTEntry->needsArgument) { // is there extra data in this argument (i.e. cases 2,3,4) if (myArgvPtr[myMatchPoint] != 0) { // is it a '=' (case3,4) - then advance one character if (myArgvPtr[myMatchPoint] == '=') myMatchPoint++; anArgument = &myArgvPtr[myMatchPoint]; } else { // case 1,5: // is there a next argument to parse? if ( (i+1) < myTQApp.argc()) { anArgument = myTQApp.argv()[i+1]; i++; } else anArgument = NULL; } } if (myTEntry->needsArgument==true && anArgument==NULL) { printf("parsing error: missing argument to '%s'!\n", myArgvPtr); exit(3); } if (myTEntry->theFunctionPtr(anArgument) == false) { printf("...\nExiting gracefully\n\n"); help(NULL); // this should never be reached: exit(1); } } else { printf("ERROR: unknown argument '%s'\n", myArgvPtr); exit(2); } } // end of the 'i' loop // If a user who doesn't run umtsmon from the command line hits an assert, // the program stops without a visible UI message. // let's fix that here: if no verbosity is set, register a SIGABRT handler to pop up a dialog if (theVerbosity <= 1) { printf("installing GUI SIGABRT handler\n"); signal(SIGABRT, popupAbortMessageBox); } else { // also register a handler explaining what to do // if the users enabled lots of verbosity if (theVerbosity >= 5) { printf("installing text SIGABRT handler\n"); signal(SIGABRT, printAbortMessage); } } // Setup translations // * we may have a valid theLocale (i.e. specified on command line), we should check it // * we may have a valid locale as a setting, we should check it // * we may have a valid locale in the environment Internationalisation myI18n( &myTQApp ); bool myI18nResult = false; if (theLocale!=NULL) { myI18nResult = myI18n.tryLocale(theLocale); if (myI18nResult == false) { DEBUG1("ERROR: your specified locale (\"%s\") is not valid\n", theLocale); exit(1); } } else myI18nResult = myI18n.trySavedLocale(); if (myI18nResult == false) myI18nResult = myI18n.tryLocale(TQTextCodec::locale()); if (myI18nResult == false) DEBUG5("Running on the default (en_US) locale\n"); Popup::WarningWithMemory("WelcomeMsg", TQObject::tr("Welcome to umtsmon.")); // check for rootness - useful for the logs if users do odd things if (Runner::amIRoot()) DEBUG1(APPNAME " is running as root!!!\n"); //////////////////////////////////// // and start the application // do not forget to pass on some initialised classes mainwindow w; myTQApp.setMainWidget( &w ); w.setI18nRef(myI18n); w.show(); return myTQApp.exec(); } void popupAbortMessageBox(__attribute__ ((unused)) int aSignalNumber) { static bool isFirstTimeHere=true; if ( !isFirstTimeHere ) return; isFirstTimeHere=false; TQMessageBox::critical (NULL, APPNAME " assert error", APPNAME " ran into a problem and unfortunately had to close. " "It is highly likely that if you run " APPNAME "from a command line, like:\n" APPNAME " -v5\n" "you will get information on what went wrong, including" " information on how to help us solve it.\n" "We thank you in advance for helping us improve " APPNAME "!", TQMessageBox::Ok | TQMessageBox::Default, TQMessageBox::NoButton, TQMessageBox::NoButton); // do not call exit here - or the signal will not be handled correctly } void printAbortMessage(__attribute__ ((unused)) int aSignalNumber) { printf("\n\n *** " APPNAME " version " APPRELEASE "" APPFLAVOUR " closed due to an" " unrecoverable program error.\n" " *** Please e-mail all of the above output to" " umtsmon-develop@lists.sourceforge.net,\n" " *** Or go to the " APPNAME " website and file a bug.\n\n\n"); // do not call exit here - or the signal will not be handled correctly }