Esempio n. 1
0
bool KviLocale::findCatalogue(QString & szBuffer, const QString & szName, const QString & szLocaleDir)
{
	KviCString szLocale = g_szLang;

	QString szLocDir = szLocaleDir;
	KviQString::ensureLastCharIs(szLocDir, KVI_PATH_SEPARATOR_CHAR);

	szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr());

	if(KviFileUtils::fileExists(szBuffer))
		return true;

	if(szLocale.findFirstIdx('.') != -1)
	{
		// things like en_GB.utf8
		// kill them
		szLocale.cutFromFirst('.');

		szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr());
		if(KviFileUtils::fileExists(szBuffer))
			return true;
	}

	if(szLocale.findFirstIdx('@') != -1)
	{
		// things like @euro ?
		// kill them
		szLocale.cutFromFirst('@');
		szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr());
		if(KviFileUtils::fileExists(szBuffer))
			return true;
	}

	if(szLocale.findFirstIdx('_') != -1)
	{
		// things like en_GB
		// kill them
		szLocale.cutFromFirst('_');
		szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr());
		if(KviFileUtils::fileExists(szBuffer))
			return true;
	}

	// try the lower case version too
	szLocale.toLower();
	szBuffer = QString("%1%2_%3.mo").arg(szLocDir, szName).arg(szLocale.ptr());
	if(KviFileUtils::fileExists(szBuffer))
		return true;

	return false;
}
Esempio n. 2
0
QTextCodec * KviLocale::codecForName(const char * pcName)
{
	KviCString szTmp = pcName;
	bool bSendUtf8;

	int iIdx = szTmp.findFirstIdx('[');
	if(iIdx != -1)
	{
		// Might be a composite codec: either UTF-8 [child codec] or child codec [UTF-8]
		KviSmartTextCodec * pCodec = g_pSmartCodecDict->find(pcName);
		if(pCodec)
			return pCodec; // got cached copy

		if(kvi_strEqualCIN("UTF-8 [", pcName, 7))
		{
			// Likely a smart codec that sends UTF-8
			szTmp.replaceAll("UTF-8 [", "");
			szTmp.replaceAll("]", "");
			bSendUtf8 = true;
		}
		else
		{
			// Likely a smart codec that sends child encoding ?
			szTmp.cutFromFirst(' ');
			bSendUtf8 = false;
		}

		QTextCodec * pChildCodec = QTextCodec::codecForName(szTmp.ptr());
		if(pChildCodec)
		{
			pCodec = new KviSmartTextCodec(pcName, pChildCodec, bSendUtf8);

			if(pCodec->ok())
			{
				g_pSmartCodecDict->replace(pcName, pCodec);
				return pCodec;
			}

			delete pCodec;
		}
		else
		{
			// The name of the child codec was invalid: can't create such a smart codec.
			// We probably screwed up the guess above related to the [ char.
			// This code path is also triggered by the yircfuzzer by specifying completely invalid codec names.
		}
	}

	return QTextCodec::codecForName(pcName);
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}