std::wstring PkyProperty::GetStringW( const char* pszSect, const char* pszKey, std::wstring const& strDefault) { auto const strSect= StringConvert::toWstring( pszSect ); auto const strKey = StringConvert::toWstring( pszKey ); return GetStringW( strSect.c_str(), strKey.c_str(), strDefault ); }
std::string PkyProperty::GetStringA( const wchar_t* pszSect, const wchar_t* pszKey, std::string const& strDefault) { auto const strDef =StringConvert::toWstring( strDefault ); auto const ret = GetStringW( pszSect, pszKey, strDef ); return StringConvert::toString( ret ); }
GXLRESULT CMOListBox::GetStringA(GXINT nIndex, clStringA& str) { clStringW wstr; GXLRESULT lr = GetStringW(nIndex, wstr); str = wstr; return lr; }
BOOL CMenuOrder::LoadMenuOrder(LPCSTR sFolderPath) { if(mois) delete[] mois; if(index) delete[] index; mois = NULL; index = NULL; len = 0; HKEY hKey; BOOL ret = FALSE; lpSubKey = MENU_ORDER_KEY; lpSubKey += sFolderPath; HRESULT hr = RegOpenKey(HKEY_CURRENT_USER, lpSubKey, &hKey); if(hr == ERROR_SUCCESS) { BYTE* lpBuf = NULL; DWORD size = 0; DWORD type = 0; hr = RegQueryValueEx(hKey, "Order", NULL, &type, NULL, &size); if(size>0) { try { lpBuf = new BYTE[size]; } catch(...) { RegCloseKey(hKey); // if(e!=NULL)e->Delete(); return FALSE; } hr = RegQueryValueEx(hKey, "Order", NULL, &type, lpBuf, &size); if(type == REG_BINARY) { BYTE* lpData = lpBuf; lpData += 8; cbsize = GetDWORD(lpData, NULL); reserved = GetDWORD(lpData, NULL); len = GetDWORD(lpData, NULL); if(len>0) { try { mois = new CMenuOrderItem[len]; index = new int[len]; ZeroMemory(index, len*sizeof(int)); } catch(...) { // if(e!=NULL)e->Delete(); len = 0; } } int len1, len2; for(int i =0; i< len && mois!= NULL; i++) { BYTE* lpend = lpBuf+size; BYTE* lpbt = lpData; len1 = mois[i].cbsize = GetDWORD(lpData, lpend); lpend = lpbt + len1; mois[i].order = GetDWORD(lpData, lpend); len2 = mois[i].len = GetWORD(lpData, lpend); mois[i].itemtype = GetWORD(lpData, lpend); mois[i].filesize = GetDWORD(lpData, lpend); mois[i].filedate = GetWORD(lpData, lpend); mois[i].filetime = GetWORD(lpData, lpend); mois[i].filetype = GetWORD(lpData, lpend); if((mois[i].itemtype & 4) != 0) { mois[i].longname = GetStringW(lpData, lpend); } else mois[i].longname = GetString(lpData, lpend); mois[i].shortname = GetString(lpData, lpend); if(mois[i].order>=0 && mois[i].order<len) index[mois[i].order] = i; lpData = lpbt + len1; ret = TRUE; } } delete[] lpBuf; } RegCloseKey(hKey); } return ret; }
/* for use from fish_inject.dll */ EXPORT_SIG(__declspec(dllexport) char*) _OnIncomingIRCLine(HANDLE a_socket, const char* a_line, size_t a_len) { if(!a_socket || !a_line || a_len < 1 || *a_line != ':') return NULL; if(strstr(a_line, " ") == strstr(a_line, " 005 ")) { std::string l_line(a_line, a_len); std::string::size_type l_pos = l_line.find(" NETWORK="); if(l_pos != std::string::npos) { l_pos += 9; // strlen(" NETWORK=") std::string::size_type l_endPos = l_line.find(" ", l_pos); if(l_endPos == std::string::npos) l_endPos = l_line.size(); ::EnterCriticalSection(&s_socketMapLock); // allow overwriting network names for dis/re-connecting BNCs and such: s_socketMap[a_socket] = l_line.substr(l_pos, l_endPos - l_pos); ::LeaveCriticalSection(&s_socketMapLock); return NULL; } } // quick exit to save some CPU cycles: if(!strstr(a_line, "+OK ") && !strstr(a_line, "mcps ")) return NULL; auto l_ini = GetBlowIni(); if(!l_ini->GetBool(L"process_incoming", true)) return NULL; /** list of stuff we possibly need to decrypt: ** :nick!ident@host PRIVMSG #chan :+OK 2T5zD0mPgMn :nick!ident@host PRIVMSG #chan :\x01ACTION +OK 2T5zD0mPgMn\x01 :nick!ident@host PRIVMSG ownNick :+OK 2T5zD0mPgMn :nick!ident@host PRIVMSG ownNick :\x01ACTION +OK 2T5zD0mPgMn\x01 :nick!ident@host NOTICE ownNick :+OK 2T5zD0mPgMn :nick!ident@host NOTICE #chan :+OK 2T5zD0mPgMn :nick!ident@host NOTICE @#chan :+OK 2T5zD0mPgMn :nick!ident@host NOTICE ~#chan :+OK 2T5zD0mPgMn (topic) :irc.tld 332 nick #chan :+OK hqnSD1kaIaE00uei/.3LjAO1Den3t/iMNsc1 :nick!ident@host TOPIC #chan :+OK JRFEAKWS (topic /list) :irc.tld 322 nick #chan 2 :[+snt] +OK BLAH */ std::string l_line(a_line, a_len); std::string l_cmd, l_contact, l_message; std::string::size_type l_cmdPos, l_tmpPos, l_targetPos, l_msgPos; StrTrimRight(l_line); l_cmdPos = l_line.find(' '); if(l_cmdPos != std::string::npos) { while(l_line[l_cmdPos] == ' ') l_cmdPos++; l_tmpPos = l_line.find(' ', l_cmdPos); if(l_tmpPos != std::string::npos) { while(l_line[l_tmpPos + 1] == ' ') l_tmpPos++; l_cmd = l_line.substr(l_cmdPos, l_tmpPos - l_cmdPos); l_msgPos = l_line.find(" :", l_tmpPos + 1); if(l_msgPos != std::string::npos) { l_msgPos += 2; l_message = l_line.substr(l_msgPos); } } } if(l_cmd.empty() || l_message.empty()) return NULL; // check if +OK is in the message part of the line: if(l_message.find("+OK ") == std::string::npos && l_message.find("mcps ") == std::string::npos) return NULL; enum { CMD_PRIVMSG = 1, CMD_ACTION, CMD_NOTICE, CMD_N332, // 332 channel :topic CMD_TOPIC, CMD_N322 // 322 channel users :topic } l_cmd_type; if(!_stricmp(l_cmd.c_str(), "PRIVMSG")) l_cmd_type = CMD_PRIVMSG; else if(!_stricmp(l_cmd.c_str(), "NOTICE")) l_cmd_type = CMD_NOTICE; else if(!strcmp(l_cmd.c_str(), "332")) l_cmd_type = CMD_N332; else if(!_stricmp(l_cmd.c_str(), "TOPIC")) l_cmd_type = CMD_TOPIC; else if(!strcmp(l_cmd.c_str(), "322")) l_cmd_type = CMD_N322; else return NULL; std::string l_leading, l_trailing; if(l_cmd_type == CMD_N322 || l_cmd_type == CMD_N332 || l_cmd_type == CMD_TOPIC) { l_targetPos = l_line.rfind(" #", l_msgPos); if(l_targetPos != std::string::npos && l_targetPos >= l_cmdPos + l_cmd.size()) /* >= because of the leading space in the find string */ { l_targetPos++; // skip the leading space l_tmpPos = l_line.find(' ', l_targetPos + 1); if(l_tmpPos != std::string::npos) { l_contact = l_line.substr(l_targetPos, l_tmpPos - l_targetPos); } } if(l_cmd_type == CMD_N322 && !l_message.empty()) { // account for channel modes in /list, like "[+nts] +OK BLAH" if(l_message[0] == '[') { l_tmpPos = l_message.find("] +OK "); if(l_tmpPos != std::string::npos) { l_leading = l_message.substr(0, l_tmpPos + 2); l_message.erase(0, l_tmpPos + 2); } } } } else { l_contact = l_line.substr(l_tmpPos + 1, l_msgPos - 2 - l_tmpPos - 1); if(!l_contact.empty()) { switch(l_contact[0]) { case '#': case '&': // channel, l_contact = channel name, all is fine. break; case '@': case '+': case '%': // onotice or something like that. l_contact.erase(0, 1); // left in l_contact is the channel name. break; default: // probably a query message. Need to make l_contact the nick name: { l_tmpPos = l_line.find('!'); if(l_tmpPos != std::string::npos) { l_contact = l_line.substr(1, l_tmpPos - 1); } else { l_contact.clear(); } } // :TODO: for future versions: keep track of local nickname and use that to determine channel/query. } } } if(l_contact.empty()) return NULL; if(l_cmd_type == CMD_PRIVMSG && l_message.find("\x01""ACTION ") == 0) { l_message.erase(0, 8); if(l_message.size() > 0 && l_message[l_message.size() - 1] == 0x01) l_message.erase(l_message.size() - 1); l_cmd_type = CMD_ACTION; } if(l_message.find("+OK ") == 0) l_message.erase(0, 4); else if(l_message.find("mcps ") == 0) l_message.erase(0, 5); else return NULL; // something must have gone awry. // account for stuff like trailing time stamps from BNCs: if((l_tmpPos = l_message.find(' ')) != std::string::npos) { l_trailing = l_message.substr(l_tmpPos); l_message.erase(l_tmpPos); } // get blowfish key... bool l_cbc; std::string l_blowKey, l_networkName; ::EnterCriticalSection(&s_socketMapLock); l_networkName = s_socketMap[a_socket]; ::LeaveCriticalSection(&s_socketMapLock); l_blowKey = l_ini->GetBlowKey(l_networkName, l_contact, l_cbc); if(l_blowKey.empty()) return NULL; // put together new message: std::string l_newMsg; if(l_cbc && !l_message.empty() && l_message[0] != '*') { // silent fallback to old style l_cbc = false; } else if(!l_cbc && !l_message.empty() && l_message[0] == '*') { // auto-enable new style even for non-prefixed keys l_cbc = true; } if(l_cbc && !l_message.empty() && l_message[0] == '*') { // strip asterisk l_message.erase(0, 1); } int l_decryptionResult = blowfish_decrypt_auto(l_cbc, l_message, l_newMsg, l_blowKey); if(l_decryptionResult == 0) { // compatibility fix // (we only encode the actual MSG part of CTCP ACTIONs, but the old FiSH.dll and some scripts etc. // encode the whole thing including \x01 and so on) if(l_cmd_type == CMD_PRIVMSG && l_newMsg.find("\x01""ACTION ") == 0) { l_newMsg.erase(0, 8); if(l_newMsg.size() > 0 && l_newMsg[l_newMsg.size() - 1] == 0x01) l_newMsg.erase(l_newMsg.size() - 1); l_cmd_type = CMD_ACTION; } // this obviously needs to be done before appending the crypt mark... fixed 2011-11. } switch(l_decryptionResult) { case -1: l_newMsg = l_message + "=[FiSH: DECRYPTION FAILED!]="; break; case 1: l_newMsg += "\x02&\x02"; /* fall through */ case 0: l_newMsg += l_trailing; if(l_ini->GetSectionBool(l_networkName, l_contact, L"mark_encrypted", !l_ini->GetStringW(L"mark_encrypted", L"").empty())) { // try local setting and use global setting as default ^^ int l_markPos = l_ini->GetInt(L"mark_position"); // 1 = append, 2 = prepend, 0 = disabled if(l_markPos > 0 && l_markPos <= 2) { const std::wstring l_markWide = l_ini->GetStringW(L"mark_encrypted"); std::string l_mark; if(l_ini->NoLegacy()) { std::string l_markDumb; // if the .ini file is UTF-8 encoded, UnicodeToCp would double-encode // the characters, so try this dumbfolded approach of conversion. for each(wchar_t ch in l_markWide) { if(ch && ch <= std::numeric_limits<unsigned char>::max()) l_markDumb += (unsigned char)ch; } if(l_markDumb.empty() || !Utf8Validate(l_markDumb.c_str())) { l_mark = UnicodeToCp(CP_UTF8, l_markWide); } else { l_mark = l_markDumb; } } else { l_mark = UnicodeToCp(CP_UTF8, l_markWide); } l_mark = SimpleMIRCParser(l_mark); #if 0 bool l_msgValid = Utf8Validate(l_newMsg.c_str(); bool l_markValid = Utf8Validate(l_mark.c_str()); if(!l_msgValid && l_markValid) { // prevent total message corruption by using // "neutral" crypt-mark l_mark = " \x0315*\x03"; } #endif if(l_markPos == 1) l_newMsg.append(l_mark); else l_newMsg.insert(0, l_mark); }