bool KviWatchNotifyListManager::handleWatchReply(KviIrcMessage *msg) { // 600: RPL_LOGON // :prefix 600 <target> <nick> <user> <host> <logintime> :logged online // 601: RPL_LOGON // :prefix 601 <target> <nick> <user> <host> <logintime> :logged offline // 604: PRL_NOWON // :prefix 604 <target> <nick> <user> <host> <logintime> :is online // 605: PRL_NOWOFF // :prefix 605 <target> <nick> <user> <host> 0 :is offline // FIXME: #warning "Use the logintime in some way ?" const char * nk = msg->safeParam(1); const char * us = msg->safeParam(2); const char * ho = msg->safeParam(3); QString dnk = m_pConnection->decodeText(nk); QString dus = m_pConnection->decodeText(us); QString dho = m_pConnection->decodeText(ho); if((msg->numeric() == RPL_LOGON) || (msg->numeric() == RPL_NOWON)) { KviIrcMask m(dnk,dus,dho); doMatchUser(msg,dnk,m); return true; } else if(msg->numeric() == RPL_WATCHOFF) { if(m_pConsole->notifyListView()->findEntry(dnk)) { notifyOffLine(dnk,dus,dho,__tr2qs("removed from watch list")); } else { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Notify list: Stopped watching for \r!n\r%Q\r"),&dnk); } if(m_pRegUserDict->find(dnk))m_pRegUserDict->remove(dnk); // kill that return true; } else if((msg->numeric() == RPL_LOGOFF) || (msg->numeric() == RPL_NOWOFF)) { if(m_pConsole->notifyListView()->findEntry(dnk)) { notifyOffLine(dnk,dus,dho,__tr2qs("watch")); } else { if(msg->numeric() == RPL_NOWOFF) { // This is a reply to a /watch +something if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Notify list: \r!n\r%Q\r is offline (watch)"),&dnk); } else { // This is a RPL_LOGOFF for an user that has not matched the reg-mask notifyOffLine(dnk,dus,dho,__tr2qs("unmatched watch list entry")); } } return true; } return false; }
bool KviStupidNotifyListManager::handleIsOn(KviIrcMessage * msg) { if(m_pConnection->lagMeter()) m_pConnection->lagMeter()->lagCheckComplete("@notify_naive"); KviCString nk; const char * aux = msg->trailing(); while(*aux) { nk = ""; aux = kvi_extractToken(nk, aux, ' '); if(nk.hasData()) { QString nkd = m_pConnection->decodeText(nk.ptr()); QString nksp = " " + nkd; m_szLastIsOnMsg.replace(nksp, "", Qt::CaseInsensitive); if(!(m_pConsole->notifyListView()->findEntry(nkd))) { // not yet notified notifyOnLine(nkd); } } } // ok...check the users that have left irc now... QStringList sl = m_szLastIsOnMsg.isEmpty() ? QStringList() : m_szLastIsOnMsg.split(' ', QString::SkipEmptyParts); for(auto & it : sl) { if(m_pConsole->notifyListView()->findEntry(it)) { // has just left irc notifyOffLine(it); } // else has never been here... } if(((unsigned int)m_iNextNickToCheck) >= m_pNickList->count()) { // have to restart unsigned int iTimeout = KVI_OPTION_UINT(KviOption_uintNotifyListCheckTimeInSecs); if(iTimeout < 5) { // life first of all. // don't allow the user to suicide if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Timeout (%d sec) is too short, resetting to something more reasonable (5 sec)"), iTimeout); iTimeout = 5; KVI_OPTION_UINT(KviOption_uintNotifyListCheckTimeInSecs) = 5; } m_iRestartTimer = startTimer(iTimeout * 1000); } else sendIsOn(); return true; }
bool KviIsOnNotifyListManager::doMatchUser(const QString & notifyString, const KviIrcMask & mask) { const auto i = m_pRegUserDict.find(notifyString); if(i != m_pRegUserDict.end()) { const QString & nam = i->second; // ok... find the user if(KviRegisteredUser * u = g_pRegisteredUserDataBase->findUserByName(nam)) { // ok... match the user if(u->matchesFixed(mask)) { // new user online if(!(m_pConsole->notifyListView()->findEntry(mask.nick()))) { notifyOnLine(mask.nick(), mask.user(), mask.host()); } // else already online, and matching... all ok } else { // not matched.... has he been online before ? if(m_pConsole->notifyListView()->findEntry(mask.nick())) { // has been online just a sec ago, but now the mask does not match // either reguserdb has changed, or the user went offline and another one got his nick // in the meantime... (ugly situation anyway) notifyOffLine(mask.nick(), mask.user(), mask.host(), __tr2qs("registration mask changed, or nickname is being used by someone else")); } else { // has never been online if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Notify list: \r!n\r%Q\r appears to be online, but the mask [%Q@\r!h\r%Q\r] does not match (registration mask does not match, or nickname is being used by someone else)"), &(mask.nick()), &(mask.user()), &(mask.host())); } } } else { // oops... unexpected inconsistency.... reguser db modified ? m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Unexpected inconsistency, registered user DB modified? (restarting)")); stop(); start(); return false; // critical... exit from the call stack } } else { // oops... unexpected inconsistency m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Unexpected inconsistency, expected \r!n\r%Q\r in the registered user DB"), ¬ifyString); } return true; }
bool KviIsOnNotifyListManager::handleIsOn(KviIrcMessage * msg) { if(!m_bExpectingIsOn) return false; // Check if it is our ISON // all the nicks must be on the IsOnList KviPointerList<QString> tmplist; tmplist.setAutoDelete(false); KviCString nk; const char * aux = msg->trailing(); while(*aux) { nk = ""; aux = kvi_extractToken(nk, aux, ' '); if(nk.hasData()) { bool bGotIt = false; QString dnk = m_pConnection->decodeText(nk.ptr()); for(QString * s = m_pIsOnList->first(); s && (!bGotIt); s = m_pIsOnList->next()) { if(KviQString::equalCI(*s, dnk)) { tmplist.append(s); bGotIt = true; } } if(!bGotIt) { // ops...not my userhost! if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Notify list: Hey! You've used ISON behind my back? (I might be confused now...)")); return false; } } } // Ok...looks to be my ison (still not sure at 100%, but can't do better) if(m_pConnection->lagMeter()) m_pConnection->lagMeter()->lagCheckComplete("@notify_ison"); m_bExpectingIsOn = false; m_pOnlineList->clear(); m_pIsOnList->setAutoDelete(false); // Ok...we have an IsOn reply here // The nicks in the IsOnList that are also in the reply are online, and go to the OnlineList // the remaining in the IsOnList are offline QString * s; for(s = tmplist.first(); s; s = tmplist.next()) { m_pIsOnList->removeRef(s); m_pOnlineList->append(s); } m_pIsOnList->setAutoDelete(true); // Ok...all the users that are online, are on the OnlineList // the remaining users are in the m_pIsOnList, and are no longer online // first the easy step: remove the users that have just left irc or have never been online // we're clearling the m_pIsOnList while((s = m_pIsOnList->first())) { if(m_pConsole->notifyListView()->findEntry(*s)) { // has just left IRC... make him part notifyOffLine(*s); } // else has never been here m_pIsOnList->removeFirst(); // autodelete is true } // ok... complex step now: the remaining users in the userhost list are online // if they have been online before, just remove them from the list // otherwise they must be matched for masks // and eventually inserted in the notify view later KviIrcUserDataBase * db = console()->connection()->userDataBase(); KviPointerList<QString> l; l.setAutoDelete(false); for(s = m_pOnlineList->first(); s; s = m_pOnlineList->next()) { if(KviUserListEntry * ent = m_pConsole->notifyListView()->findEntry(*s)) { // the user was online from a previous notify session // might the mask have been changed ? (heh...this is tricky, maybe too much even) if(KVI_OPTION_BOOL(KviOption_boolNotifyListSendUserhostForOnlineUsers)) { // user wants to be sure about online users.... // check if he is on some channels if(ent->globalData()->nRefs() > 1) { // mmmh...we have more than one ref, so the user is at least in one query or channel // look him up on channels, if we find his entry, we can be sure that he is // still the right user KviPointerList<KviChannelWindow> * chlist = m_pConsole->connection()->channelList(); for(KviChannelWindow * ch = chlist->first(); ch; ch = chlist->next()) { if(KviUserListEntry * le = ch->findEntry(*s)) { l.append(s); // ok...found on a channel...we don't need a userhost to match him KviIrcMask mk(*s, le->globalData()->user(), le->globalData()->host()); if(!doMatchUser(*s, mk)) return true; // critical problems = have to restart!!! break; } } } // else Only one ref...we need a userhost to be sure (don't remove from the list) } else { // user wants no userhost for online users...we "hope" that everything will go ok. l.append(s); } //l.append(s); // we will remove him from the list } else { // the user was not online! // check if we have a cached mask if(db) { if(KviIrcUserEntry * ue = db->find(*s)) { // already in the db... do we have a mask ? if(ue->hasUser() && ue->hasHost()) { // yup! we have a complete mask to match on KviIrcMask mk(*s, ue->user(), ue->host()); // lookup the user's name in the m_pRegUserDict if(!doMatchUser(*s, mk)) return true; // critical problems = have to restart!!! l.append(s); // remove anyway } } } } } for(s = l.first(); s; s = l.next()) { m_pOnlineList->removeRef(s); // autodelete is true } if(m_pOnlineList->isEmpty()) { if(m_pNotifyList->isEmpty()) delayedNotifySession(); else delayedIsOnSession(); } else delayedUserhostSession(); return true; }
bool KviWatchNotifyListManager::doMatchUser(KviIrcMessage * msg, const QString & notifyString, const KviIrcMask & mask) { QString * nam = m_pRegUserDict->find(notifyString); if(nam) { // ok...find the user if(KviRegisteredUser * u = g_pRegisteredUserDataBase->findUserByName(*nam)) { // ok ... match the user if(u->matchesFixed(mask)) { // new user online if(!(m_pConsole->notifyListView()->findEntry(mask.nick()))) { notifyOnLine(mask.nick(), mask.user(), mask.host(), "watch"); } else { // else already online, and matching...all ok if(msg->numeric() == RPL_NOWON) { // This is a reply to a /watch +something (should not happen, unless the user is messing) or to /watch l (user requested) notifyOnLine(mask.nick(), mask.user(), mask.host(), __tr2qs("watch entry listing requested by user"), false); } else { // This is a RPL_LOGON....we're desynched ? notifyOnLine(mask.nick(), mask.user(), mask.host(), __tr2qs("possible watch list desync"), false); } } } else { // not matched.... has he been online before ? if(m_pConsole->notifyListView()->findEntry(mask.nick())) { // has been online just a sec ago, but now the mask does not match // prolly the reguserdb has been changed notifyOffLine(mask.nick(), mask.user(), mask.host(), __tr2qs("registration mask changed or desync with the watch service")); } else { // has never been online if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr("Notify list: \r!n\r%Q\r appears to be online, but the mask [%Q@\r!h\r%Q\r] does not match (watch: registration mask does not match, or nickname is being used by someone else)"), &(mask.nick()), &(mask.user()), &(mask.host())); } } } else { // ops... unexpected inconsistency .... reguser db modified ? m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Unexpected inconsistency, registered user DB modified? (watch: restarting)")); stop(); start(); return false; // critical ... exit from the call stack } } else { // not in our dictionary // prolly someone used /WATCH behind our back... bad boy! if(!(m_pConsole->notifyListView()->findEntry(mask.nick()))) { notifyOnLine(mask.nick(), mask.user(), mask.host(), __tr2qs("watch entry added by user")); } } return true; }