//============================================================================= // // File : kvi_main.cpp // Creation date : Sun Jun 18 2000 12:38:45 by Szymon Stefanek // // This file is part of the KVirc irc client distribution // Copyright (C) 1999-2000 Szymon Stefanek (pragma at kvirc dot net) // // 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; either version 2 // of the License, or (at your opinion) any later version. // // 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. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #define __KVIRC__ #include "kvi_app.h" #include "kvi_string.h" #include "kvi_settings.h" #include "kvi_ircurl.h" #include "kvi_defaults.h" #include "kvi_sourcesdate.h" #include "kvi_msgbox.h" #ifndef COMPILE_NO_IPC extern bool kvi_sendIpcMessage(const char * message); // kvi_ipc.cpp #endif #include //for debug() #include #define KVI_ARGS_RETCODE_OK 0 #define KVI_ARGS_RETCODE_ERROR 1 #define KVI_ARGS_RETCODE_STOP 2 typedef struct _ParseArgs { int argc; char ** argv; char * configFile; bool createFile; bool bForceNewSession; bool bShowPopup; bool bShowSplashScreen; bool bExecuteCommandAndClose; KviStr szExecCommand; KviStr szExecRemoteCommand; } ParseArgs; int parseArgs(ParseArgs * a) { KviStr szServer; KviStr szPort; int idx; if(a->argc < 2)return KVI_ARGS_RETCODE_OK; for(idx = 1;idx < a->argc;idx++) { TQString szMessage; char * p = a->argv[idx]; if((kvi_strLen(p) > 3) && (*p == '-') && (*(p+1) == '-'))p++; if(kvi_strEqualCI("-v",p) || kvi_strEqualCI("-version",p)) { KviTQString::appendFormatted(szMessage,"KVIrc %s '%s'\n",KVI_VERSION,KVI_RELEASE_NAME); KviTQString::appendFormatted(szMessage,"Sources date: %s\n",KVI_SOURCES_DATE); KviTQString::appendFormatted(szMessage,"Build date: %s\n",KVI_BUILD_DATE); KviTQString::appendFormatted(szMessage,"Home page: http://www.kvirc.net/\n"); #ifdef COMPILE_ON_WINDOWS MessageBox(0,szMessage.local8Bit().data(),"KVIrc",0); #else debug("%s", szMessage); #endif return KVI_ARGS_RETCODE_STOP; } if(kvi_strEqualCI("-h",p) || kvi_strEqualCI("-help",p)) { KviTQString::appendFormatted(szMessage,"Usage:\n"); KviTQString::appendFormatted(szMessage," %s [options] [server [port]] [ircurl [ircurl [...]]]\n",a->argv[0]); KviTQString::appendFormatted(szMessage," \n"); KviTQString::appendFormatted(szMessage,"Available options:\n"); KviTQString::appendFormatted(szMessage," -h, --help : Print this help and exit\n"); KviTQString::appendFormatted(szMessage," -v, --version: Print version information and exit\n"); KviTQString::appendFormatted(szMessage," -c : Use as config file instead of ~/%s\n",KVI_HOME_CONFIG_FILE_NAME); KviTQString::appendFormatted(szMessage," (defaults to $HOME/%s if does not exist)\n",KVI_HOME_CONFIG_FILE_NAME); KviTQString::appendFormatted(szMessage," -n : Use as config file instead of $HOME/%s\n",KVI_HOME_CONFIG_FILE_NAME); KviTQString::appendFormatted(szMessage," (create if it does not exist)\n"); #ifdef COMPILE_NO_IPC KviTQString::appendFormatted(szMessage," -f : Accepted but ignored (for compatibility)\n"); #else KviTQString::appendFormatted(szMessage," -f : Force a new KVIrc session, even if there is already\n"); KviTQString::appendFormatted(szMessage," a running one.\n"); #endif KviTQString::appendFormatted(szMessage," -e : If a KVIrc session is already running, execute\n"); KviTQString::appendFormatted(szMessage," the in that session, otherwise start up\n"); KviTQString::appendFormatted(szMessage," normally and execute \n"); KviTQString::appendFormatted(szMessage," must be a single shell token.\n"); KviTQString::appendFormatted(szMessage," You can eventually use this switch more than once\n"); KviTQString::appendFormatted(szMessage," -x : If a KVIrc session is already running, execute\n"); KviTQString::appendFormatted(szMessage," the in that session, otherwise exit from application without doing anything/\n"); KviTQString::appendFormatted(szMessage," must be a single shell token.\n"); KviTQString::appendFormatted(szMessage," You can eventually use this switch more than once\n"); KviTQString::appendFormatted(szMessage," -r : If a KVIrc session is already running, execute the \n"); KviTQString::appendFormatted(szMessage," in that session, otherwise start up normally (do not execute).\n"); KviTQString::appendFormatted(szMessage," must be a single shell token.\n"); KviTQString::appendFormatted(szMessage," You can eventually use this switch more than once\n"); KviTQString::appendFormatted(szMessage," -m : If a KVIrc session is already running, show an informational\n"); KviTQString::appendFormatted(szMessage," popup dialog instead of writing to the console"); KviTQString::appendFormatted(szMessage," --nosplash : Do not show the splash screen at startup\n"); KviTQString::appendFormatted(szMessage," [server] : Connect to this server after startup\n"); KviTQString::appendFormatted(szMessage," [port] : Use this port for connection\n"); KviTQString::appendFormatted(szMessage," [ircurl] : URL in the following form:\n"); KviTQString::appendFormatted(szMessage," irc[6]://[:][/[?]]\n"); #ifdef COMPILE_ON_WINDOWS MessageBox(0,szMessage.local8Bit().data(),"KVIrc",0); #else debug("%s", szMessage); #endif return KVI_ARGS_RETCODE_STOP; } if(kvi_strEqualCI("-c",p)) { idx++; if(idx >= a->argc) { debug("Option -c requires a config file name"); return KVI_ARGS_RETCODE_ERROR; } p = a->argv[idx]; a->configFile = p; debug("Using file %s as config",p); continue; } if(kvi_strEqualCI("-e",p)) { idx++; if(idx >= a->argc) { debug("Option -e requires a command"); return KVI_ARGS_RETCODE_ERROR; } p = a->argv[idx]; if(a->szExecCommand.hasData())a->szExecCommand.append("\n"); a->szExecCommand.append(p); continue; } if(kvi_strEqualCI("-x",p)) { idx++; if(idx >= a->argc) { debug("Option -x requires a command"); return KVI_ARGS_RETCODE_ERROR; } p = a->argv[idx]; if(a->szExecCommand.hasData())a->szExecCommand.append("\n"); a->szExecCommand.append(p); a->bExecuteCommandAndClose=true; continue; } if(kvi_strEqualCI("-r",p)) { idx++; if(idx >= a->argc) { debug("Option -r requires a command"); return KVI_ARGS_RETCODE_ERROR; } p = a->argv[idx]; if(a->szExecRemoteCommand.hasData())a->szExecRemoteCommand.append("\n"); a->szExecRemoteCommand.append(p); continue; } if(kvi_strEqualCI("-m",p)) { a->bShowPopup = true; continue; } if(kvi_strEqualCI("-n",p)) { idx++; if(idx >= a->argc) { debug("Option -n requires a config file name"); return KVI_ARGS_RETCODE_ERROR; } p = a->argv[idx]; a->configFile = p; a->createFile=true; debug("Using file %s as config",p); continue; } if(kvi_strEqualCI("-nosplash",p)) { a->bShowSplashScreen = false; continue; } if(kvi_strEqualCI("-f",p)) { a->bForceNewSession = true; continue; } if(kvi_strEqualCI("-session",p)||kvi_strEqualCI("-display",p)) { // TQt apps are supposed to handle the params to these switches, but we'll skip arg for now idx++; continue; } if(*p != '-') { // no dash if(kvi_strEqualCIN(p,"irc://",6) || kvi_strEqualCIN(p,"irc6://",7) || kvi_strEqualCIN(p,"ircs://",7) || kvi_strEqualCIN(p,"ircs6://",8)) { KviStr tmp = TQString(TQString::fromLocal8Bit(p)); if(a->szExecCommand.hasData())a->szExecCommand.append('\n'); a->szExecCommand.append("openurl "); tmp.replaceAll("$",""); // the urls can't contain $ signs tmp.replaceAll(";",""); // the urls can't contain ; signs a->szExecCommand.append(tmp); } else { TQString tmp = TQString::fromLocal8Bit(p); bool bOk; tmp.toUInt(&bOk); if(bOk)szPort = tmp; else { TQString ri = tmp.right(4); if(KviTQString::equalCI(ri,".kvs")) { if(a->szExecCommand.hasData())a->szExecCommand.append('\n'); a->szExecCommand.append("parse \""); tmp.replace('$',"\\$"); tmp.replace('\\',"\\\\"); a->szExecCommand.append(tmp); a->szExecCommand.append('"'); } else if(KviTQString::equalCI(ri,".kvt")) { if(a->szExecCommand.hasData())a->szExecCommand.append('\n'); a->szExecCommand.append("theme.install \""); tmp.replace('$',"\\$"); tmp.replace('\\',"\\\\"); a->szExecCommand.append(tmp); a->szExecCommand.append('"'); } else szServer = tmp; // assume a plain server name } } } } if(szServer.hasData()) { if(a->szExecCommand.hasData())a->szExecCommand.append('\n'); a->szExecCommand.append("server -u "); a->szExecCommand.append(szServer); if(szPort.hasData()) { a->szExecCommand.append(' '); a->szExecCommand.append(szPort); } } return KVI_ARGS_RETCODE_OK; } #if defined(Q_OS_MACX) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3) // Repair broken colour definitions due to "lazy" static object initialization void repair_colors(void) { if(TQt::white.red() == 0) { TQt::color0 = (tqRgb(255,255,255 ),0); TQt::color1 = (tqRgb(0,0,0),1); TQt::black.setRgb(0,0,0); TQt::white.setRgb(255,255,255); TQt::darkGray.setRgb(128,128,128); TQt::gray.setRgb(160,160,164); TQt::lightGray.setRgb(192,192,192); TQt::red.setRgb(255,0,0); TQt::green.setRgb(0,255,0); TQt::blue.setRgb(0,0,255); TQt::cyan.setRgb(0,255,255); TQt::magenta.setRgb(255,0,255); TQt::yellow.setRgb(255,255,0); TQt::darkRed.setRgb(128,0,0); TQt::darkGreen.setRgb(0,128,0); TQt::darkBlue.setRgb(0,0,128); TQt::darkCyan.setRgb(0,128,128); TQt::darkMagenta.setRgb(128,0,128); TQt::darkYellow.setRgb(128,128,0); } } #endif //Q_OS_MACX int main(int argc,char ** argv) { #if defined(Q_OS_MACX) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3) repair_colors(); #endif //Q_OS_MACX ParseArgs a; a.argc = argc; a.argv = argv; a.configFile = 0; a.createFile = false; a.bForceNewSession = false; a.bShowPopup = false, a.bShowSplashScreen = true; a.bExecuteCommandAndClose = false; int retCode = parseArgs(&a); if(retCode != KVI_ARGS_RETCODE_OK)return ((retCode == KVI_ARGS_RETCODE_ERROR) ? (-1) : 0); // Need to have the X socket open before IPC startup KviApp * theApp = new KviApp(argc,argv); KviStr szRemoteCommand = a.szExecCommand; if(a.szExecRemoteCommand.hasData()) { if(szRemoteCommand.hasData())szRemoteCommand.append('\n'); szRemoteCommand.append(a.szExecRemoteCommand); } /* FIXME: There is a race condition in the IPC mechanism. If one starts two instances of kvirc one immediately after another then both instances may run through kvi_sendIpcMessage without finding the sentinel window and thus both may decide to start. A weak file locking mechanism should be used too... #ifdef COMPILE_ON_WINDOWS TQString szLock = convertSeparators(cleanDirPath(TQDir::homeDirPath() + "/.kvirc.lock")); #else TQString szLock = convertSeparators(cleanDirPath(TQDir::homeDirPath() + "/.kvirc.lock")); #endif TQFileInfo inf(szLock); bool bLocked = false; if(inf.exists()) { iLocked = inf.lastModified().secsTo(TQDateTime::currentDateTime()); } */ #ifndef COMPILE_NO_IPC if(!a.bForceNewSession) { // here we could use CreateMutex on win and semget() on linux // in order to get a shared semaphore to ensure instance unicity. if(kvi_sendIpcMessage(szRemoteCommand.ptr())) { if(szRemoteCommand.isEmpty()) { KviStr tmp(KviStr::Format,"Another KVIrc session is already running on this display and with this user id.\nUse %s -f if you want to force a new session.",argv[0]); if(a.bShowPopup) TQMessageBox::information(0,"Session - KVIrc",tmp.ptr(),TQMessageBox::Ok); else debug("%s", tmp.ptr()); } delete theApp; return 0; } else if(a.bExecuteCommandAndClose) { delete theApp; return 0; } } #endif theApp->m_bCreateConfig = a.createFile; theApp->m_szConfigFile = a.configFile; theApp->m_szExecAfterStartup = a.szExecCommand; theApp->m_bShowSplashScreen = a.bShowSplashScreen; theApp->setup(); // YEAH! int retVal = theApp->exec(); // :) delete theApp; theApp = 0; return retVal; }