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; }
void RegistrationWizard::notifyNickChanged(const QString &) { bool bYes = !m_pNotifyCheck->isChecked(); if(!bYes) { // we need at least one nickname then :) KviCString tmp = m_pNotifyNickEdit1->text(); if(tmp.hasData()) { bYes = true; } else { tmp = m_pNotifyNickEdit2->text(); if(tmp.hasData())bYes = true; } } setNextEnabled(m_pPage4,bYes); }
void KviConfigurationFile::writeEntry(const QString & szKey,const QList<int> &list) { m_bDirty = true; KviConfigurationFileGroup * p_group = getCurrentGroup(); KviCString szData; for(QList<int>::ConstIterator it = list.begin();it != list.end();++it) { if(szData.hasData())szData.append(','); szData.append(KviCString::Format,"%d",*it); } //qDebug("Writing option list for group %s and key %s: %s",m_szGroup.latin1(),szKey.latin1(),szData.ptr()); p_group->replace(szKey,new QString(szData.ptr())); }
void KviVariantTableItem::setContentFromEditor(QWidget * w) { switch(m_property.type()) { case QVariant::String: m_property = QVariant(((QLineEdit *)w)->text()); break; case QVariant::Int: m_property = QVariant(((QLineEdit *)w)->text().toInt()); break; case QVariant::UInt: m_property = QVariant(((QLineEdit *)w)->text().toUInt()); break; case QVariant::Bool: m_property = QVariant(((QComboBox *)w)->currentItem(),1); break; case QVariant::Color: m_property.asColor().setNamedColor(((QLineEdit *)w)->text()); break; case QVariant::Font: { KviCString txt = ((QComboBox *)w)->currentText(); if(txt.hasData()) { KviCString fam = txt; fam.cutFromFirst(',',true); fam.trimmed(); KviCString psz = txt; psz.cutToFirst(',',true); psz.trimmed(); bool bOk; unsigned int uSize = psz.toUInt(&bOk); if(!bOk)uSize = 12; m_property = QVariant(QFont(fam.ptr(),uSize)); } } break; default: break; } }
bool hasLeadingChars(KviCString ** pszArray, char c) { if(!(*pszArray)) return false; // can't have more leading chars bool bGotIt = false; while(*pszArray) { if(*((*pszArray)->ptr()) == c) { // found at least one such leading char bGotIt = true; } else { // we pretend this line to be empty KviCString szTmp = *(*pszArray); szTmp.trim(); if(szTmp.hasData()) return false; *(*pszArray) = ""; // set it to empty also in the main buffer } pszArray++; } return bGotIt; }
bool KviIsOnNotifyListManager::handleUserhost(KviIrcMessage * msg) { if(!m_bExpectingUserhost) return false; // first check for consistency: all the replies must be on the USERHOST list KviPointerList<KviIrcMask> tmplist; tmplist.setAutoDelete(true); KviCString nk; const char * aux = msg->trailing(); while(*aux) { nk = ""; aux = kvi_extractToken(nk, aux, ' '); if(nk.hasData()) { // split it in a mask KviCString nick; KviCString user; KviCString host; int idx = nk.findFirstIdx('='); if(idx != -1) { nick = nk.left(idx); if(nick.lastCharIs('*')) nick.cutRight(1); nk.cutLeft(idx + 1); if(nk.firstCharIs('+') || nk.firstCharIs('-')) nk.cutLeft(1); idx = nk.findFirstIdx('@'); if(idx != -1) { user = nk.left(idx); nk.cutLeft(idx + 1); host = nk; } else { user = "******"; host = nk; } bool bGotIt = false; QString szNick = m_pConnection->decodeText(nick.ptr()); QString szUser = m_pConnection->decodeText(user.ptr()); QString szHost = m_pConnection->decodeText(host.ptr()); for(QString * s = m_pUserhostList->first(); s && (!bGotIt); s = m_pUserhostList->next()) { if(KviQString::equalCI(*s, szNick)) { KviIrcMask * mk = new KviIrcMask(szNick, szUser, szHost); tmplist.append(mk); bGotIt = true; m_pUserhostList->removeRef(s); } } if(!bGotIt) { // ops...not my userhost! if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Hey! You've used USERHOST behind my back? (I might be confused now...)")); return false; } } else { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Broken USERHOST reply from the server? (%s)"), nk.ptr()); } } } // Ok...looks to be my usershot (still not sure at 100%, but can't do better) if(m_pConnection->lagMeter()) m_pConnection->lagMeter()->lagCheckComplete("@notify_userhost"); m_bExpectingUserhost = false; for(KviIrcMask * mk = tmplist.first(); mk; mk = tmplist.next()) { if(!doMatchUser(mk->nick(), *mk)) return true; // have to restart!!! } if(!(m_pUserhostList->isEmpty())) { // ops...someone is no longer online ? while(QString * s = m_pUserhostList->first()) { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Notify list: \r!n\r%Q\r appears to have gone offline before USERHOST reply was received, will recheck in the next loop"), s); m_pUserhostList->removeFirst(); } } if(m_pOnlineList->isEmpty()) { if(m_pNotifyList->isEmpty()) delayedNotifySession(); else delayedIsOnSession(); } else delayedUserhostSession(); 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 KviHttpRequest::processHeader(KviCString &szHeader) { int idx = szHeader.findFirstIdx("\r\n"); KviCString szResponse; if(idx != -1) { szResponse = szHeader.left(idx); szHeader.cutLeft(idx + 2); } else { szResponse = szHeader; szHeader = ""; } szResponse.trim(); bool bValid = false; unsigned int uStatus = 0; // check the response value if(kvi_strEqualCSN(szResponse.ptr(),"HTTP",4)) { KviCString szR = szResponse; szR.cutToFirst(' '); szR.trim(); int idx = szR.findFirstIdx(' '); KviCString szNumber; if(idx != -1)szNumber = szR.left(idx); else szNumber = szR; bool bOk; uStatus = szNumber.toUInt(&bOk); if(bOk)bValid = true; } QString szUniResponse = QString::fromUtf8(szResponse.ptr()); if(!bValid) { // the response is invalid ? resetInternalStatus(); m_szLastError = __tr2qs("Invalid HTTP response: %1").arg(szUniResponse); emit terminated(false); return false; } emit status(__tr2qs("Received HTTP response: %1").arg(szUniResponse)); KviPointerList<KviCString> hlist; hlist.setAutoDelete(true); idx = szHeader.findFirstIdx("\r\n"); while(idx != -1) { if(idx > 0) { hlist.append(new KviCString(szHeader.ptr(),idx)); szHeader.cutLeft(idx + 2); } idx = szHeader.findFirstIdx("\r\n"); } if(szHeader.hasData())hlist.append(new KviCString(szHeader)); KviPointerHashTable<const char *,KviCString> hdr(11,false,true); hdr.setAutoDelete(true); for(KviCString * s = hlist.first();s;s = hlist.next()) { idx = s->findFirstIdx(":"); if(idx != -1) { KviCString szName = s->left(idx); s->cutLeft(idx + 1); s->trim(); hdr.replace(szName.ptr(),new KviCString(*s)); //qDebug("FOUND HEADER (%s)=(%s)",szName.ptr(),s->ptr()); } } KviCString * size = hdr.find("Content-length"); if(size) { bool bOk; m_uTotalSize = size->toUInt(&bOk); if(!bOk)m_uTotalSize = 0; } KviCString * contentEncoding = hdr.find("Content-encoding"); if(contentEncoding) { m_bGzip = contentEncoding->equalsCI("gzip"); } KviCString * transferEncoding = hdr.find("Transfer-Encoding"); if(transferEncoding) { if(kvi_strEqualCI(transferEncoding->ptr(),"chunked")) { // be prepared to handle the chunked transfer encoding as required by HTTP/1.1 m_bChunkedTransferEncoding = true; m_uRemainingChunkSize = 0; } } // check the status // case 200: // OK // case 206: // Partial content // case 100: // Continue ?? // case 101: // Switching protocols ??? // case 201: // Created // case 202: // Accepted // case 203: // Non-Authoritative Information // case 204: // No content // case 205: // Reset content // case 300: // Multiple choices // case 301: // Moved permanently // case 302: // Found // case 303: // See Other // case 304: // Not modified // case 305: // Use Proxy // case 306: // ??? // case 307: // Temporary Redirect // case 400: // Bad request // case 401: // Unauthorized // case 402: // Payment Required // case 403: // Forbidden // case 404: // Not found // case 405: // Method not allowed // case 406: // Not acceptable // case 407: // Proxy authentication required // case 408: // Request timeout // case 409: // Conflict // case 410: // Gone // case 411: // Length required // case 412: // Precondition failed // case 413: // Request entity too large // case 414: // Request-URI Too Long // case 415: // Unsupported media type // case 416: // Requested range not satisfiable // case 417: // Expectation Failed // case 500: // Internal server error // case 501: // Not implemented // case 502: // Bad gateway // case 503: // Service unavailable // case 504: // Gateway timeout // case 505: // HTTP Version not supported if( (uStatus != 200) && // OK (uStatus != 206) // Partial content ) { // This is not "OK" and not "Partial content" // Error, redirect or something confusing if(m_eProcessingType != HeadersOnly) { switch(uStatus) { case 301: // Moved permanently case 302: // Found case 303: // See Other case 307: // Temporary Redirect { if(!m_bFollowRedirects) { resetInternalStatus(); m_szLastError = szResponse.ptr(); emit terminated(false); return false; } m_uRedirectCount++; if(m_uRedirectCount > m_uMaximumRedirectCount) { resetInternalStatus(); m_szLastError = __tr2qs("Too many redirects"); emit terminated(false); return false; } KviCString * location = hdr.find("Location"); if(!location) { resetInternalStatus(); m_szLastError = __tr2qs("Bad redirect"); emit terminated(false); return false; } KviUrl url(location->ptr()); if( (url.url() == m_connectionUrl.url()) || (url.url() == m_url.url()) ) { resetInternalStatus(); m_szLastError = __tr2qs("Redirect loop"); emit terminated(false); return false; } m_connectionUrl = url; emit status(__tr2qs("Following Redirect to %1").arg(url.url())); if(!start()) emit terminated(false); return false; // will exit the call stack } break; break; default: // assume error resetInternalStatus(); m_szLastError = szResponse.ptr(); emit terminated(false); return false; break; } // this is an error then } // else the server will terminate (it was a HEAD request) } emit receivedResponse(szUniResponse); emit header(&hdr); if((m_uMaxContentLength > 0) && (m_uTotalSize > ((unsigned int)m_uMaxContentLength))) { resetInternalStatus(); m_szLastError=__tr2qs("The amount of received data exceeds the maximum length"); emit terminated(false); return false; } // fixme: could check for data type etc... return true; }
void DccChatWindow::connectionInProgress() { if(m_pDescriptor->bActive) { output(KVI_OUT_DCCMSG, __tr2qs_ctx("Contacting host %Q on port %Q", "dcc"), &(m_pDescriptor->szIp), &(m_pDescriptor->szPort)); } else { output(KVI_OUT_DCCMSG, __tr2qs_ctx("Listening on interface %Q port %Q", "dcc"), &(m_pMarshal->localIp()), &(m_pMarshal->localPort())); if(m_pDescriptor->bSendRequest) { KviCString ip; if(!m_pDescriptor->szFakeIp.isEmpty()) { ip = m_pDescriptor->szFakeIp; } else { ip = m_pDescriptor->szListenIp; if(KVI_OPTION_BOOL(KviOption_boolDccGuessIpFromServerWhenLocalIsUnroutable)) { if(!kvi_isRoutableIpString(ip.ptr())) { // try to get the IP that the IRC server can see if(m_pDescriptor->console()) { KviCString tmp = m_pDescriptor->console()->connection() ? m_pDescriptor->console()->connection()->userInfo()->hostIp().toUtf8().data() : ""; if(tmp.hasData()) { ip = tmp; output(KVI_OUT_DCCMSG, __tr2qs_ctx("The local IP address is private, determining from IRC server: %s", "dcc"), ip.ptr()); } else { output(KVI_OUT_DCCMSG, __tr2qs_ctx("The local IP address is private, but unable to determine it from the IRC server", "dcc")); } } else { output(KVI_OUT_DCCMSG, __tr2qs_ctx("The local IP address is private, but have no IRC server to determine it from", "dcc")); } } } } QString port = !m_pDescriptor->szFakePort.isEmpty() ? m_pDescriptor->szFakePort : QString(m_pMarshal->localPort()); //FIXME: #warning "OPTION FOR SENDING 127.0.0.1 and so on (not an unsigned number)" struct in_addr a; if(KviNetUtils::stringIpToBinaryIp(ip.ptr(), &a)) ip.setNum(htonl(a.s_addr)); QString szReq = QString("PRIVMSG %1 :%2DCC %3 chat %4 %5").arg(m_pDescriptor->szNick, QChar(0x01), m_pDescriptor->szType, ip.ptr(), port); if(m_pDescriptor->isZeroPortRequest()) { szReq.append(" "); szReq += m_pDescriptor->zeroPortRequestTag(); } szReq.append((char)(0x01)); m_pDescriptor->console()->connection()->sendData(m_pDescriptor->console()->connection()->encodeText(szReq).data()); output(KVI_OUT_DCCMSG, __tr2qs_ctx("Sent DCC %Q request to %Q, waiting for the remote client to connect...", "dcc"), &(m_pDescriptor->szType), &(m_pDescriptor->szNick)); //qDebug(m_pDescriptor->szNick); } else output(KVI_OUT_DCCMSG, __tr2qs_ctx("DCC %Q request not sent, awaiting manual connection", "dcc"), &(m_pDescriptor->szType)); } KVS_TRIGGER_EVENT_1(KviEvent_OnDCCChatConnectionInProgress, this, m_pDescriptor->idString()); }
bool KviIsOnNotifyListManager::handleUserhost(KviIrcMessage * msg) { if(!m_bExpectingUserhost) return false; // first check for consistency: all the replies must be on the USERHOST list std::map<std::size_t, std::unique_ptr<KviIrcMask>> tmplist; KviCString nk; const char * aux = msg->trailing(); while(*aux) { nk = ""; aux = kvi_extractToken(nk, aux, ' '); if(nk.hasData()) { // split it in a mask KviCString nick; KviCString user; KviCString host; int idx = nk.findFirstIdx('='); if(idx != -1) { nick = nk.left(idx); if(nick.lastCharIs('*')) nick.cutRight(1); nk.cutLeft(idx + 1); if(nk.firstCharIs('+') || nk.firstCharIs('-')) nk.cutLeft(1); idx = nk.findFirstIdx('@'); if(idx != -1) { user = nk.left(idx); nk.cutLeft(idx + 1); host = nk; } else { user = "******"; host = nk; } bool bGotIt = false; QString szNick = m_pConnection->decodeText(nick.ptr()); QString szUser = m_pConnection->decodeText(user.ptr()); QString szHost = m_pConnection->decodeText(host.ptr()); std::size_t i = 0; for(const auto & s : m_UserhostList) { if(KviQString::equalCI(s, szNick)) { tmplist.emplace(i, std::make_unique<KviIrcMask>(szNick, szUser, szHost)); bGotIt = true; break; } } if(!bGotIt) { // oops... not my userhost! if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Hey! You've used USERHOST behind my back? (I might be confused now...)")); return false; } } else { if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMWARNING, __tr2qs("Notify list: Broken USERHOST reply from the server? (%s)"), nk.ptr()); } } } // Ok... looks to be my usershot (still not sure at 100%, but can't do better) if(m_pConnection->lagMeter()) m_pConnection->lagMeter()->lagCheckComplete("@notify_userhost"); m_bExpectingUserhost = false; for(auto & pair : tmplist) { KviIrcMask * mk = pair.second.get(); if(!doMatchUser(mk->nick(), *mk)) return true; // have to restart!!! } for(auto i = tmplist.rbegin(); i != tmplist.rend(); ++i) m_UserhostList.erase(m_UserhostList.begin() + i->first); for(const auto & s : m_UserhostList) { // oops... someone is no longer online ? if(_OUTPUT_VERBOSE) m_pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Notify list: \r!n\r%Q\r appears to have gone offline before USERHOST reply was received, will recheck in the next loop"), &s); } m_UserhostList.clear(); if(m_OnlineList.empty()) { if(m_NotifyList.empty()) delayedNotifySession(); else delayedIsOnSession(); } else { delayedUserhostSession(); } return true; }
bool KviMessageCatalogue::load(const QString & szName) { QString szCatalogueFile(szName); // Try to load the header KviFile f(szCatalogueFile); if(!f.open(QFile::ReadOnly)) { qDebug("[KviLocale]: Failed to open the messages file %s: probably doesn't exist",szCatalogueFile.toUtf8().data()); return false; } GnuMoFileHeader hdr; if(f.read((char *)&hdr,sizeof(GnuMoFileHeader)) < (int)sizeof(GnuMoFileHeader)) { qDebug("KviLocale: Failed to read header of %s",szCatalogueFile.toUtf8().data()); f.close(); return false; } bool bMustSwap = false; if(hdr.magic != KVI_LOCALE_MAGIC) { if(hdr.magic == KVI_LOCALE_MAGIC_SWAPPED) { qDebug("KviLocale: Swapped magic for file %s: swapping data too",szCatalogueFile.toUtf8().data()); bMustSwap = true; } else { qDebug("KviLocale: Bad locale magic for file %s: not a *.mo file ?",szCatalogueFile.toUtf8().data()); f.close(); return false; } } if(KVI_SWAP_IF_NEEDED(bMustSwap,hdr.revision) != MO_REVISION_NUMBER) { qDebug("KviLocale: Invalid *.mo file revision number for file %s",szCatalogueFile.toUtf8().data()); f.close(); return false; } int iStringsNum = KVI_SWAP_IF_NEEDED(bMustSwap,hdr.nstrings); if(iStringsNum <= 0) { qDebug("KviLocale: No translated messages found in file %s",szCatalogueFile.toUtf8().data()); f.close(); return false; } if(iStringsNum >= 9972) { qDebug("Number of strings too big...sure that it is a KVIrc catalog file ?"); iStringsNum = 9972; } // return back f.seek(0); unsigned int uSize = f.size(); char * pcBuffer = (char *)KviMemory::allocate(uSize); // FIXME: maybe read it in blocks eh ? if(f.read(pcBuffer,uSize) < (int)uSize) { qDebug("KviLocale: Error while reading the translation file %s",szCatalogueFile.toUtf8().data()); KviMemory::free(pcBuffer); f.close(); return false; } // Check for broken *.mo files if(uSize < (24 + (sizeof(GnuMoStringDescriptor) * iStringsNum))) { qDebug("KviLocale: Broken translation file %s (too small for all descriptors)",szCatalogueFile.toUtf8().data()); KviMemory::free(pcBuffer); f.close(); return false; } GnuMoStringDescriptor * pOrigDescriptor = (GnuMoStringDescriptor *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.orig_tab_offset)); GnuMoStringDescriptor * pTransDescriptor = (GnuMoStringDescriptor *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,hdr.trans_tab_offset)); // Check again for broken *.mo files int iExpectedFileSize = KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[iStringsNum - 1].offset) + KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[iStringsNum - 1].length); if(uSize < (unsigned int)iExpectedFileSize) { qDebug("KviLocale: Broken translation file %s (too small for all the message strings)",szCatalogueFile.toUtf8().data()); KviMemory::free(pcBuffer); f.close(); return false; } // Ok...we can run now int iDictSize = kvi_getFirstBiggerPrime(iStringsNum); if(m_pMessages) delete m_pMessages; m_pMessages = new KviPointerHashTable<const char *,KviTranslationEntry>(iDictSize,true,false); // dictSize, case sensitive, don't copy keys m_pMessages->setAutoDelete(true); KviCString szHeader; for(int i = 0; i < iStringsNum; i++) { // FIXME: "Check for NULL inside strings here ?" //qDebug("original seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].offset), // KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].length)); //qDebug("translated seems to be at %u and %u byttes long",KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].offset), // KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].length)); KviTranslationEntry * e = new KviTranslationEntry( (char *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].offset)), KVI_SWAP_IF_NEEDED(bMustSwap,pOrigDescriptor[i].length), (char *)(pcBuffer + KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].offset)), KVI_SWAP_IF_NEEDED(bMustSwap,pTransDescriptor[i].length)); // In some (or all?) *.mo files the first string // is zero bytes long and the translated one contains // information about the translation if(e->m_szKey.len() == 0) { szHeader = e->m_szEncodedTranslation; delete e; continue; } m_pMessages->insert(e->m_szKey.ptr(),e); } KviMemory::free(pcBuffer); f.close(); m_pTextCodec = 0; // find out the text encoding, if possible if(szHeader.hasData()) { // find "charset=*\n" int iIdx = szHeader.findFirstIdx("charset="); if(iIdx != -1) { szHeader.cutLeft(iIdx + 8); szHeader.cutFromFirst('\n'); szHeader.trim(); m_pTextCodec = KviLocale::instance()->codecForName(szHeader.ptr()); if(!m_pTextCodec) { qDebug("Can't find the codec for charset=%s",szHeader.ptr()); qDebug("Falling back to codecForLocale()"); m_pTextCodec = QTextCodec::codecForLocale(); } } } if(!m_pTextCodec) { qDebug("The message catalogue does not have a \"charset\" header"); qDebug("Assuming utf8"); // FIXME: or codecForLocale() ? m_pTextCodec = QTextCodec::codecForName("UTF-8"); } return true; }