void KviLagMeter::lagCheckAbort(const char * key) { KviPointerList<KviLagCheck> l; l.setAutoDelete(false); KviLagCheck * c; if(_OUTPUT_PARANOIC) m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Lag check aborted (%s)"),key); for(c = m_pCheckList->first();c;c = m_pCheckList->next()) if(kvi_strEqualCS(c->szKey.ptr(),key))l.append(c); for(c = l.first();c;c = l.next())m_pCheckList->removeRef(c); }
static bool perlcore_module_ctrl(KviModule *,const char * cmd,void * param) { #ifdef COMPILE_PERL_SUPPORT if(kvi_strEqualCS(cmd,KVI_PERLCORECTRLCOMMAND_EXECUTE)) { KviPerlCoreCtrlCommand_execute * ex = (KviPerlCoreCtrlCommand_execute *)param; if(ex->uSize != sizeof(KviPerlCoreCtrlCommand_execute))return false; g_pCurrentKvsContext = ex->pKvsContext; g_bExecuteQuiet = ex->bQuiet; if(ex->szContext.isEmpty()) { KviPerlInterpreter * m = new KviPerlInterpreter("temporary"); if(!m->init()) { delete m; return false; } ex->bExitOk = m->execute(ex->szCode,ex->lArgs,ex->szRetVal,ex->szError,ex->lWarnings); m->done(); delete m; } else { KviPerlInterpreter * m = perlcore_get_interpreter(ex->szContext); ex->bExitOk = m->execute(ex->szCode,ex->lArgs,ex->szRetVal,ex->szError,ex->lWarnings); } return true; } if(kvi_strEqualCS(cmd,KVI_PERLCORECTRLCOMMAND_DESTROY)) { KviPerlCoreCtrlCommand_destroy * de = (KviPerlCoreCtrlCommand_destroy *)param; if(de->uSize != sizeof(KviPerlCoreCtrlCommand_destroy))return false; perlcore_destroy_interpreter(de->szContext); return true; } #endif // COMPILE_PERL_SUPPORT return false; }
bool KviLagMeter::lagCheckComplete(const char * key) { // find this lag check KviLagCheck * c; for(c = m_pCheckList->first();c;c = m_pCheckList->next()) { if(kvi_strEqualCS(c->szKey.ptr(),key))break; } if(!c)return false; // not found // kill any earlier lag checks (IRC is a sequential proto) while(m_pCheckList->first() != c)m_pCheckList->removeFirst(); if(_OUTPUT_PARANOIC) m_pConnection->console()->output(KVI_OUT_VERBOSE,__tr2qs("Lag check completed (%s)"),key); struct timeval tv; kvi_gettimeofday(&tv,0); unsigned int uLag = ((tv.tv_sec - c->lSecs) * 1000); if(tv.tv_usec < c->lUSecs)uLag -= ((c->lUSecs - tv.tv_usec) / 1000); else uLag += ((tv.tv_usec - c->lUSecs) / 1000); // now check the reliability if(m_uLastReliability > c->uReliability) { // the actual data is more reliable than the new one :/ // change the real lag only by a certain amount // c->uRel : 100 = uLag : m_uLag m_uLag = ((uLag * c->uReliability) + (m_uLag * m_uLastReliability)) / (c->uReliability + m_uLastReliability); } else { // the actual data is less reliable than the new one m_uLag = uLag; } m_tLastCompleted = tv.tv_sec; // now m_tLastOwnCheck = 0; m_tFirstOwnCheck = 0; m_uLastReliability = c->uReliability; m_pCheckList->removeFirst(); return true; }
KVIMODULEEXPORTFUNC void dccModuleCtcpDccParseRoutine(KviDccRequest * dcc) { dcc->szType.toUpper(); for(auto & i : dccParseProcTable) { if(kvi_strEqualCS(i.type, dcc->szType.ptr())) { (i.proc)(dcc); return; } } // ops...we don't know this dcc type if(!dcc->ctcpMsg->msg->haltOutput()) { QString szError = QString(__tr2qs_ctx("Unknown DCC type '%1'", "dcc")).arg(dcc->szType.ptr()); dcc_module_request_error(dcc, szError); } }
bool KviModuleManager::loadModule(const QString &modName) { if(findModule(modName)) { //qDebug("MODULE %s ALREADY IN CORE MEMORY",modName); return true; } QString tmp; QString szName; #if defined(COMPILE_ON_WINDOWS) KviQString::appendFormatted(szName,"kvi%Q.dll",&modName); #elif defined(COMPILE_ON_MINGW) KviQString::appendFormatted(szName,"libkvi%Q.dll",&modName); #else KviQString::appendFormatted(szName,"libkvi%Q.so",&modName); #endif szName=szName.toLower(); g_pApp->getLocalKvircDirectory(tmp,KviApplication::Modules,szName); if(!KviFileUtils::fileExists(tmp)) { g_pApp->getGlobalKvircDirectory(tmp,KviApplication::Modules,szName); } QLibrary* pLibrary = new QLibrary(tmp); pLibrary->setLoadHints(QLibrary::ExportExternalSymbolsHint); if(!pLibrary->load()) { m_szLastError = pLibrary->errorString(); delete pLibrary; return false; } KviModuleInfo * info = (KviModuleInfo *)pLibrary->resolve(KVIRC_MODULE_STRUCTURE_SYMBOL); if(!info) { m_szLastError = __tr2qs("No " KVIRC_MODULE_STRUCTURE_SYMBOL " symbol exported: not a kvirc module ?"); pLibrary->unload(); delete pLibrary; return false; } if(!info->szKVIrcVersion) { m_szLastError = __tr2qs("This module has no version information: refusing to load it"); pLibrary->unload(); delete pLibrary; return false; } if(!KVI_OPTION_BOOL(KviOption_boolIgnoreModuleVersions)) { if(!kvi_strEqualCS(info->szKVIrcVersion,KVI_VERSION)) { m_szLastError = __tr2qs("This module was compiled for a different KVIrc version and can't be loaded"); m_szLastError += " ("; m_szLastError += info->szKVIrcVersion; m_szLastError += ")"; pLibrary->unload(); delete pLibrary; return false; } } KviModule * module = new KviModule(pLibrary,info,modName,szName.toUtf8().data()); // the module is probably up.. the only thing can fail is the init_routine now // load the message catalogue if any if(info->szModuleContext) { QString szDir; // it's more probable to have the translations in the global directory // try it as first... (yes, catalogue overriding is impossible this way.. but, anybody cares ?) g_pApp->getGlobalKvircDirectory(szDir,KviApplication::Locale); if(!KviLocale::instance()->loadCatalogue(info->szModuleContext,szDir)) { // try the local directory then g_pApp->getLocalKvircDirectory(szDir,KviApplication::Locale); KviLocale::instance()->loadCatalogue(info->szModuleContext,szDir); } } if(info->init_routine) { if(!((info->init_routine)(module))) { m_szLastError = __tr2qs("Failed to execute the init routine"); //qDebug("ERROR IN LOADING MODULE %s (%s): failed to execute the init routine",modName,szName.ptr()); delete module; // kill the message catalogue too then KviLocale::instance()->unloadCatalogue(modName); return false; } } m_pModuleDict->insert(modName,module); /* registerDefaultCommands(module); */ module->registerDefaultCommands(); if(KVI_OPTION_BOOL(KviOption_boolCleanupUnusedModules)) { if(!m_pCleanupTimer->isActive()) { if(KVI_OPTION_UINT(KviOption_uintModuleCleanupTimerInterval) < 30) KVI_OPTION_UINT(KviOption_uintModuleCleanupTimerInterval) = 30; m_pCleanupTimer->start(KVI_OPTION_UINT(KviOption_uintModuleCleanupTimerInterval) * 1000); } } // be verbose if needed....just make sure that we're not shutting down... if(_OUTPUT_VERBOSE && !g_pApp->kviClosingDown()) { if(g_pMainWindow) { KviConsoleWindow * pWnd = g_pMainWindow->firstConsole(); if(pWnd) // this may be NULL when the app is starting up pWnd->output( KVI_OUT_VERBOSE, __tr2qs("Loaded module '%s' (%s)"), modName.toUtf8().data(), szName.toUtf8().data() ); } } return true; }
static void dccModuleParseDccSend(KviDccRequest * dcc) { //#warning "Ignore files depending on file type ? (MediaType ?)" // // We have received a DCC SEND request in the following form // // DCC [ST]SEND <filename> <ipaddress> <port> <filesize> // // Now the things are a bit tricky... we eventually can // reply with a DCC RESUME and receive a DCC ACCEPT then // The format of these requests is: // // DCC RESUME <filename> <port> <resumepos> // ACCEPT <filename> <port> <resumepos> // // There is a mIrc extension that allows <port> to be 0 // and adds a last parameter that seems to be a random number (thnx YaP :) // that is used to keep track of the connection. // This extension is used by firewalled machines to initiate a DCC SEND: // the receiving side should respond with a DCC SEND offer // with the same random number appended, listen for a connection, and receive the file // instead of sending it. // // when a zero port request is initiated by another party we get // DCC SEND <filename> <fakeipaddress> 0 <filesize> <tag> // if (and only if) we want to resume we reply with // DCC RESUME <filename> 0 <resumesize> <tag> // in this case the remote part replies again with // DCC ACCEPT <filename> 0 <resumesize> <tag> // and we finally reply with // DCC SEND <filename> <ourip> <ourport> <filesize> <tag> // // when a zero port request is initiated by us we send out // DCC SEND <filename> <fakeipaddress> 0 <filesize> <tag> // and if the remote party wants to resume then we get // DCC RESUME <filename> 0 <resumesize> <tag> // and we eventually reply with // DCC ACCEPT <filename> 0 <resumesize> <tag> // and we finally get // DCC SEND <filename> <remoteip> <remoteport> <filesize> <tag> // // Thus if there is a <tag> and the port is 0, then the remote party // is trying to send a file to us, but if the port is nonzero then // we have sent out a zero port request and the remote party acked it // if((!kvi_strEqualCS(dcc->szParam3.ptr(), "0")) && dcc->szParam5.hasData()) { // DCC SEND <filename> <remoteip> <remoteport> <filesize> <tag> // zero port acknowledge: treat as a RECV that should look like // DCC [TS]RECV <filename> <remoteip> <remoteport> <resume-filesize> // but since we have stored the sharedfile with the name <tag> // we do exchange the params :) KviDccZeroPortTag * t = g_pDccBroker->findZeroPortTag(dcc->szParam5.ptr()); if(t) { // FIXME: #warning "%u will not support 64-bit numbers and won't work as intended here" dcc->szParam4.sprintf("%u", t->m_uResumePosition); g_pDccBroker->removeZeroPortTag(dcc->szParam5.ptr()); } else { // this should never happen since we always add // a zero port tag for out outgoing requests // but well... maybe the user did something behind our back... dcc->szParam4 = "0"; // no resume possible in this case } // swap the tag and the filename (we have added a fileoffer with this tag) dcc->szParam1 = dcc->szParam5; dcc->szParam5 = ""; dccModuleParseDccRecv(dcc); return; } // First of all we check the transfer limits dcc->szParam1 = dcc->pConsole->decodeText(dcc->szParam1); if(!dcc_module_check_limits(dcc)) return; if(!dcc_module_check_concurrent_transfers_limit(dcc)) return; // Then we ensure that the data that the remote end has sent are valid if(!dcc_module_normalize_target_data(dcc, dcc->szParam2, dcc->szParam3)) return; if(!(dcc->szParam4.isUnsignedNum())) { if(!dcc->ctcpMsg->msg->haltOutput()) { dcc->ctcpMsg->msg->console()->output(KVI_OUT_DCCMSG, __tr2qs_ctx("The above request is broken: the fourth parameter should be the file size but doesn't appear to be an unsigned number; trying to continue", "dcc"), dcc->szParam4.ptr()); } dcc->szParam4 = __tr2qs_ctx("<unknown size>", "dcc"); } if(dcc->szParam1.contains('/')) { if(!dcc->ctcpMsg->msg->haltOutput()) { dcc->ctcpMsg->msg->console()->output(KVI_OUT_DCCMSG, __tr2qs_ctx("The above request is broken: the filename contains path components, stripping the leading path and trying to continue", "dcc"), dcc->szParam1.ptr()); } dcc->szParam1.cutToLast('/'); } if(dcc->szParam1.contains("%2F")) { if(!dcc->ctcpMsg->msg->haltOutput()) { dcc->ctcpMsg->msg->console()->output(KVI_OUT_DCCMSG, __tr2qs_ctx("The above request is broken: the filename contains path components, stripping the leading path and trying to continue", "dcc"), dcc->szParam1.ptr()); } dcc->szParam1.cutToLast("%2F"); } KviCString szExtensions = dcc->szType; szExtensions.cutRight(4); // cut off SEND bool bTurboExtension = szExtensions.contains('T', false); #ifdef COMPILE_SSL_SUPPORT bool bSSLExtension = szExtensions.contains('S', false); #else //!COMPILE_SSL_SUPPORT if(szExtensions.contains('S', false)) { dcc_module_request_error(dcc, __tr2qs_ctx("This executable has been compiled without SSL support, the SSL extension to DCC SEND is not available", "dcc")); return; } #endif //!COMPILE_SSL_SUPPORT DccDescriptor * d = new DccDescriptor(dcc->pConsole); d->szNick = dcc->ctcpMsg->pSource->nick(); d->szUser = dcc->ctcpMsg->pSource->user(); d->szHost = dcc->ctcpMsg->pSource->host(); dcc_fill_local_nick_user_host(d, dcc); d->szIp = dcc->szParam2.ptr(); d->szPort = dcc->szParam3.ptr(); d->szFileName = dcc->szParam1.ptr(); d->szFileSize = dcc->szParam4.ptr(); if(d->szPort == "0" && dcc->szParam5.hasData()) { if(KVI_OPTION_BOOL(KviOption_boolDccSendFakeAddressByDefault)) { d->szFakeIp = KVI_OPTION_STRING(KviOption_stringDefaultDccFakeAddress); if(d->szFakeIp.isEmpty()) KVI_OPTION_BOOL(KviOption_boolDccSendFakeAddressByDefault) = false; } d->setZeroPortRequestTag(dcc->szParam5.ptr()); QString tmp; if(!dcc_kvs_get_listen_ip_address(nullptr, d->console(), tmp)) d->szListenIp = "0.0.0.0"; else d->szListenIp = QString(tmp); d->szListenPort = "0"; // any port is OK d->bSendRequest = true; d->szLocalFileSize = d->szFileSize; } d->bActive = !d->isZeroPortRequest(); // we have to connect unless it is a zero port request d->bResume = false; d->bRecvFile = true; d->bIsTdcc = bTurboExtension; d->bNoAcks = d->bIsTdcc; #ifdef COMPILE_SSL_SUPPORT d->bIsSSL = bSSLExtension; #endif d->bOverrideMinimize = false; d->bAutoAccept = KVI_OPTION_BOOL(KviOption_boolAutoAcceptDccSend); d->bIsIncomingAvatar = g_pApp->findPendingAvatarChange(dcc->pConsole, d->szNick, d->szFileName); dcc_module_set_dcc_type(d, "RECV"); if(KVI_OPTION_BOOL(KviOption_boolAutoAcceptIncomingAvatars)) d->bAutoAccept = d->bAutoAccept || d->bIsIncomingAvatar; d->triggerCreationEvent(); g_pDccBroker->recvFileManage(d); }