summaryrefslogtreecommitdiff
path: root/protocols/AimOscar/src
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/AimOscar/src')
-rw-r--r--protocols/AimOscar/src/aim.cpp137
-rw-r--r--protocols/AimOscar/src/aim.h341
-rw-r--r--protocols/AimOscar/src/avatars.cpp312
-rw-r--r--protocols/AimOscar/src/avatars.h54
-rw-r--r--protocols/AimOscar/src/away.cpp125
-rw-r--r--protocols/AimOscar/src/chat.cpp343
-rw-r--r--protocols/AimOscar/src/chat.h53
-rw-r--r--protocols/AimOscar/src/client.cpp994
-rw-r--r--protocols/AimOscar/src/connection.cpp640
-rw-r--r--protocols/AimOscar/src/conv.cpp900
-rw-r--r--protocols/AimOscar/src/conv.h56
-rw-r--r--protocols/AimOscar/src/defines.h353
-rw-r--r--protocols/AimOscar/src/direct_connect.cpp88
-rw-r--r--protocols/AimOscar/src/direct_connect.h24
-rw-r--r--protocols/AimOscar/src/error.cpp289
-rw-r--r--protocols/AimOscar/src/file.cpp592
-rw-r--r--protocols/AimOscar/src/file.h81
-rw-r--r--protocols/AimOscar/src/flap.cpp60
-rw-r--r--protocols/AimOscar/src/flap.h39
-rw-r--r--protocols/AimOscar/src/links.cpp195
-rw-r--r--protocols/AimOscar/src/links.h24
-rw-r--r--protocols/AimOscar/src/packets.cpp123
-rw-r--r--protocols/AimOscar/src/packets.h66
-rw-r--r--protocols/AimOscar/src/popup.cpp114
-rw-r--r--protocols/AimOscar/src/proto.cpp913
-rw-r--r--protocols/AimOscar/src/proto.h502
-rw-r--r--protocols/AimOscar/src/proxy.cpp174
-rw-r--r--protocols/AimOscar/src/proxy.h24
-rw-r--r--protocols/AimOscar/src/resource.h123
-rw-r--r--protocols/AimOscar/src/server.cpp2397
-rw-r--r--protocols/AimOscar/src/services.cpp531
-rw-r--r--protocols/AimOscar/src/snac.cpp65
-rw-r--r--protocols/AimOscar/src/snac.h49
-rw-r--r--protocols/AimOscar/src/theme.cpp542
-rw-r--r--protocols/AimOscar/src/theme.h46
-rw-r--r--protocols/AimOscar/src/thread.cpp92
-rw-r--r--protocols/AimOscar/src/tlv.cpp103
-rw-r--r--protocols/AimOscar/src/tlv.h52
-rw-r--r--protocols/AimOscar/src/ui.cpp1584
-rw-r--r--protocols/AimOscar/src/ui.h61
-rw-r--r--protocols/AimOscar/src/utility.cpp878
-rw-r--r--protocols/AimOscar/src/utility.h66
-rw-r--r--protocols/AimOscar/src/version.h20
43 files changed, 14225 insertions, 0 deletions
diff --git a/protocols/AimOscar/src/aim.cpp b/protocols/AimOscar/src/aim.cpp
new file mode 100644
index 0000000000..1cc9482e14
--- /dev/null
+++ b/protocols/AimOscar/src/aim.cpp
@@ -0,0 +1,137 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "version.h"
+
+char AIM_CAP_MIRANDA[16] = "MirandaA";
+
+
+int hLangpack;
+
+HINSTANCE hInstance;
+
+static HANDLE hMooduleLoaded;
+
+/////////////////////////////////////////////////////////////////////////////
+// Protocol instances
+static int sttCompareProtocols(const CAimProto *p1, const CAimProto *p2)
+{
+ return _tcscmp(p1->m_tszUserName, p2->m_tszUserName);
+}
+
+OBJLIST<CAimProto> g_Instances(1, sttCompareProtocols);
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Dll entry point
+
+extern "C"
+BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD /*fdwReason*/,LPVOID /*lpvReserved*/)
+{
+ hInstance = hinstDLL;
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Plugin information
+
+static const PLUGININFOEX pluginInfo =
+{
+ sizeof(PLUGININFOEX),
+ "AIM Protocol",
+ __VERSION_DWORD,
+ "Provides support for AOL® Instant Messenger (AIM) protocol",
+ "Boris Krasnovskiy, Aaron Myles Landwehr",
+ "borkra@miranda-im.org",
+ "© 2008-2011 Boris Krasnovskiy, 2005-2006 Aaron Myles Landwehr",
+ "http://miranda-ng.org/",
+ UNICODE_AWARE,
+ {0x3750a5a3, 0xbf0d, 0x490e, {0xb6, 0x5d, 0x41, 0xac, 0x4d, 0x29, 0xae, 0xb3}} // {3750A5A3-BF0D-490e-B65D-41AC4D29AEB3}
+};
+
+extern "C" __declspec(dllexport) const PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ *(unsigned long*)(&AIM_CAP_MIRANDA[8]) = _htonl(mirandaVersion);
+ *(unsigned long*)(&AIM_CAP_MIRANDA[12]) = _htonl(__VERSION_DWORD);
+ return &pluginInfo;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Interface information
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
+
+////////////////////////////////////////////////////////////////////////////////////////
+// OnModulesLoaded - finalizes plugin's configuration on load
+
+static int OnModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ aim_links_init();
+ InitExtraIcons();
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load
+
+static PROTO_INTERFACE* protoInit(const char* pszProtoName, const TCHAR* tszUserName)
+{
+ CAimProto *ppro = new CAimProto(pszProtoName, tszUserName);
+ g_Instances.insert(ppro);
+ return ppro;
+}
+
+static int protoUninit(PROTO_INTERFACE* ppro)
+{
+ g_Instances.remove((CAimProto*)ppro);
+ return 0;
+}
+
+extern "C" int __declspec(dllexport) Load(void)
+{
+
+ mir_getLP(&pluginInfo);
+
+ hMooduleLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+
+ PROTOCOLDESCRIPTOR pd = {0};
+ pd.cbSize = sizeof(pd);
+ pd.szName = "AIM";
+ pd.type = PROTOTYPE_PROTOCOL;
+ pd.fnInit = protoInit;
+ pd.fnUninit = protoUninit;
+ CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM) & pd);
+
+ InitThemeSupport();
+ InitIcons();
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unload
+
+extern "C" int __declspec(dllexport) Unload(void)
+{
+ aim_links_destroy();
+ UnhookEvent(hMooduleLoaded);
+
+ DestroyExtraIcons();
+ return 0;
+}
diff --git a/protocols/AimOscar/src/aim.h b/protocols/AimOscar/src/aim.h
new file mode 100644
index 0000000000..fb6d1071ee
--- /dev/null
+++ b/protocols/AimOscar/src/aim.h
@@ -0,0 +1,341 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef AIM_H
+#define AIM_H
+
+#define MIRANDA_VER 0x0A00
+
+#include <m_stdhdr.h>
+
+//System includes
+#include <windows.h>
+#include <vssym32.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <io.h>
+#include <prsht.h>
+#include <richedit.h>
+#include <sys/stat.h>
+#include <time.h>
+
+//Miranda IM includes
+#ifdef _MSC_VER
+#pragma warning( disable: 4100 )
+#endif
+
+#include <newpluginapi.h>
+#include <m_avatars.h>
+#include <m_button.h>
+#include <m_chat.h>
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_clui.h>
+#include <m_database.h>
+#include <m_history.h>
+#include <m_idle.h>
+#include <m_langpack.h>
+#include <m_message.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <statusmodes.h>
+#include <m_system.h>
+#include <m_userinfo.h>
+#include <m_addcontact.h>
+#include <m_icolib.h>
+#include <m_utils.h>
+#include <m_system_cpp.h>
+#include <m_imgsrvc.h>
+#include <win2k.h>
+
+//independent includes
+#include "flap.h"
+#include "snac.h"
+#include "tlv.h"
+
+//rest of includes
+#include "avatars.h"
+#include "utility.h"
+#include "chat.h"
+#include "direct_connect.h"
+#include "conv.h"
+#include "file.h"
+#include "links.h"
+#include "packets.h"
+#include "proxy.h"
+#include "resource.h"
+#include "proto.h"
+#include "theme.h"
+#include "ui.h"
+
+// Protocol limits
+#define MAX_SCREEN_NAME_LENGTH 97
+#define MAX_GROUP_NAME_LENGTH 48
+#define MAX_NICKNAME_LENGTH 64
+#define MAX_MESSAGE_LENGTH 3978
+#define MAX_STATUS_MESSAGE_LENGTH 251
+#define MAX_AWAY_MESSAGE_LENGTH 4096
+#define MAX_ICON_SIZE 7168
+
+// ICBM parameter flags
+#define ICBM_CHANNEL_MSGS_ALLOWED 0x00000001
+#define ICBM_MISSED_CALLS_ENABLED 0x00000002
+#define ICBM_EVENTS_ALLOWED 0x00000008
+#define ICBM_SMS_SUPPORTED 0x00000010
+#define ICBM_OFFLINE_MSGS_ALLOWED 0x00000100
+
+// SSI preferences
+#define SHOW_IDLE 0x00000400
+#define SHOW_RECENT_BUDDIES 0x00020000
+#define SHOW_TYPING 0x00400000
+
+//Extended Status Icon Numbers
+#define ACCOUNT_TYPE_UNCONFIRMED 1
+#define ACCOUNT_TYPE_CONFIRMED 2
+#define ACCOUNT_TYPE_ICQ 3
+#define ACCOUNT_TYPE_AOL 4
+#define ACCOUNT_TYPE_ADMIN 5
+#define EXTENDED_STATUS_BOT 1
+#define EXTENDED_STATUS_HIPTOP 2
+
+//Popup flags
+#define MAIL_POPUP 0x04
+#define ERROR_POPUP 0x08
+#define TCHAR_POPUP 0x10
+
+//Main Option Window Keys
+#define AIM_KEY_SN "SN"
+#define AIM_KEY_NK "Nick"
+#define AIM_KEY_PW "Password"
+#define AIM_KEY_HN "loginhost"
+#define AIM_KEY_PN "loginport"
+#define AIM_KEY_DC "DelConf"//delivery confirmation
+#define AIM_KEY_FP "ForceProxyTransfer"
+#define AIM_KEY_HF "HiptopFake"
+#define AIM_KEY_AT "DisableATIcons"
+#define AIM_KEY_ES "DisableESIcons"
+#define AIM_KEY_DM "DisableModeMsg"
+#define AIM_KEY_FI "FormatIncoming"//html->bbcodes
+#define AIM_KEY_FO "FormatOutgoing"//bbcodes->html
+#define AIM_KEY_II "InstantIdle"
+#define AIM_KEY_IIT "InstantIdleTS"
+#define AIM_KEY_CM "CheckMail"
+#define AIM_KEY_MG "ManageGroups"
+#define AIM_KEY_DA "DisableAvatars"
+#define AIM_KEY_DSSL "DisableSSL"
+#define AIM_KEY_FSC "ForceSingleClient"
+
+#define OTH_KEY_SM "StatusMsg"
+#define OTH_KEY_GP "Group"
+//Module Name Key
+#define MOD_KEY_CL "CList"
+//Settings Keys
+#define AIM_KEY_PR "Profile"
+#define AIM_KEY_LA "LastAwayChange"
+//Contact Keys
+#define AIM_KEY_BI "BuddyId"
+#define AIM_KEY_GI "GroupId"
+#define AIM_KEY_ST "Status"
+#define AIM_KEY_IT "IdleTS"
+#define AIM_KEY_OT "LogonTS"
+#define AIM_KEY_MS "MemberTS"
+#define AIM_KEY_AC "AccType"//account type
+#define AIM_KEY_ET "ESType"//Extended Status type
+#define AIM_KEY_MV "MirVer"
+#define AIM_KEY_US "Utf8Support"
+#define AIM_KEY_NL "NotOnList"
+#define AIM_KEY_LM "LastMessage"
+#define AIM_KEY_AH "AvatarHash"
+#define AIM_KEY_AHT "AvatarType"
+#define AIM_KEY_EM "e-mail"
+#define AIM_KEY_LV "LastVer"
+#define AIM_KEY_TIS "TotalIMsSent"
+#define AIM_KEY_TIR "TotalIMsReceived"
+#define AIM_KEY_TAM "TotalAwayMessages"
+#define AIM_KEY_TTO "TotalTimeOnline"
+#define AIM_KEY_BLS "IsBlast"
+#define AIM_KEY_NIL "IsNotInList"
+
+#define AIM_DEFAULT_SERVER "slogin.oscar.aol.com"
+#define AIM_DEFAULT_SERVER_NS "login.oscar.aol.com"
+#define AIM_PROXY_SERVER "ars.oscar.aol.com"
+#define AIM_DEFAULT_PORT 5190
+#define AIM_DEFAULT_SSL_PORT 443
+
+//Some Defaults for various things
+#define DEFAULT_KEEPALIVE_TIMER 39 // secs
+#define DEFAULT_GRACE_PERIOD 60
+#define AIM_DEFAULT_GROUP "miranda merged"
+#define SYSTEM_BUDDY "aolsystemmsg"
+#define DEFAULT_AWAY_MSG "I am away from my computer right now."
+//Md5 Roasting stuff
+#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
+#define MD5_HASH_LENGTH 16
+
+//Aim Version Stuff
+#define AIM_CLIENT_MAJOR_VERSION 5
+#define AIM_CLIENT_MINOR_VERSION 9
+#define AIM_CLIENT_LESSER_VERSION 0
+#define AIM_CLIENT_BUILD_NUMBER 0x1772
+#define AIM_CLIENT_ID_NUMBER 0x0109
+#define AIM_CLIENT_DISTRIBUTION_NUMBER 0x0150
+
+#define AIM_LANGUAGE "en"
+#define AIM_COUNTRY "us"
+#define AIM_MSG_TYPE "text/x-aolrtf; charset=\"us-ascii\""
+#define AIM_MSG_TYPE_UNICODE "text/x-aolrtf; charset=\"unicode-2-0\""
+#define AIM_TOOL_VERSION "\x01\x10\x18\xf1"
+
+//Supported Clients
+#define CLIENT_UNKNOWN "?"
+#define CLIENT_AIM5 "AIM 5.x"
+#define CLIENT_AIM4 "AIM 4.x"
+#define CLIENT_AIMEXPRESS5 "AIM Express 5"
+#define CLIENT_AIMEXPRESS6 "AIM Express 6"
+#define CLIENT_AIMEXPRESS7 "AIM Express 7"
+#define CLIENT_ICQ "ICQ"
+#define CLIENT_AIM_TRITON "AIM Triton"
+#define CLIENT_AIM6_1 "AIM 6.1"
+#define CLIENT_AIM6_5 "AIM 6.5"
+#define CLIENT_AIM6_8 "AIM 6.8"
+#define CLIENT_AIM6_9 "AIM 6.9"
+#define CLIENT_AIM7_0 "AIM 7.0"
+#define CLIENT_AIMTOC "AIM TOC"
+#define CLIENT_BOT "AIM Bot"
+#define CLIENT_GAIM "Gaim"
+#define CLIENT_PURPLE "Purple"
+#define CLIENT_ADIUM "Adium X"
+#define CLIENT_GPRS "GPRS"
+#define CLIENT_ICHAT "iChat"
+#define CLIENT_IM2 "IM2"
+#define CLIENT_KOPETE "Kopete"
+#define CLIENT_MEEBO "Meebo"
+#define CLIENT_DIGSBY "Digsby"
+#define CLIENT_BEEJIVE "beejive"
+#define CLIENT_MICQ "mICQ"
+#define CLIENT_AIMOSCAR "Miranda IM %d.%d.%d.%d (AIM v%d.%d.%d.%d)"
+#define CLIENT_OSCARJ "Miranda IM %d.%d.%d.%d%s (ICQ v%d.%d.%d.%d%s)"
+#define CLIENT_OSCARSN "Miranda IM %d.%d.%d.%d%s (ICQ S!N v%d.%d.%d.%d%s)%s"
+#define CLIENT_OSCARPL "Miranda IM %d.%d.%d.%d%s (ICQ Plus v%d.%d.%d.%d%s)%s"
+#define CLIENT_NAIM "naim"
+#define CLIENT_QIP "qip"
+#define CLIENT_SIM "SIM"
+#define CLIENT_SMS "SMS"
+#define CLIENT_TERRAIM "TerraIM"
+#define CLIENT_TRILLIAN_PRO "Trillian Pro"
+#define CLIENT_TRILLIAN "Trillian"
+#define CLIENT_TRILLIAN_ASTRA "Trillian Astra"
+#define CLIENT_BLAST "Blast Group"
+
+//Aim Caps
+#define AIM_CAPS_LENGTH 16
+
+// Official
+#define AIM_CAP_SHORT_CAPS "\x09\x46\x00\x00\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_SECURE_IM "\x09\x46\x00\x01\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_XHTML_IM "\x09\x46\x00\x02\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_RTCVIDEO "\x09\x46\x01\x01\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_HAS_MICROPHONE "\x09\x46\x01\x02\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_HAS_CAMERA "\x09\x46\x01\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_RTCAUDIO "\x09\x46\x01\x04\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_HOST_STATUS_TEXT_AWARE "\x09\x46\x01\x0a\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_RT_IM "\x09\x46\x01\x0b\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_SMART_CAPS "\x09\x46\x01\xff\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_FILE_TRANSFER "\x09\x46\x13\x43\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_DIRECT_IM "\x09\x46\x13\x45\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_FILE_SHARING "\x09\x46\x13\x48\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_SUPPORT_ICQ "\x09\x46\x13\x4D\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+
+#define AIM_CAP_AVAILABLE_FOR_CALL "\x09\x46\x01\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_ACA "\x09\x46\x01\x06\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_MULTI_AUDIO "\x09\x46\x01\x07\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_MULTI_VIDEO "\x09\x46\x01\x08\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_VICEROY "\x09\x46\xf0\x04\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_BUDDY_ICON "\x09\x46\x13\x46\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_VOICE_CHAT "\x09\x46\x13\x41\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_DIRECT_PLAY "\x09\x46\x13\x42\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_ICQ_DIRECT_CONNECT "\x09\x46\x13\x44\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_GAMES "\x09\x46\x13\x47\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_ICQ_SERVER_RELAY "\x09\x46\x13\x49\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"//icq? channel 2 extended, TLV(0x2711) based messages
+#define AIM_CAP_CHAT_ROBOTS "\x09\x46\x13\x4A\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_SHARE_BUDDIES "\x09\x46\x13\x4B\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_CHAT "\x74\x8F\x24\x20\x62\x87\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_AMO "\x09\x46\x01\x0c\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+
+// Extensions
+#define AIM_CAP_HIPTOP "\x09\x46\x13\x23\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UTF8 "\x09\x46\x13\x4E\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWN4 "\x09\x46\xf0\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWNC "\x09\x46\xf0\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_IM2 "\x74\xed\xc3\x36\x44\xdf\x48\x5b\x8b\x1c\x67\x1a\x1f\x86\x09\x9f"
+#define AIM_CAP_TRILLIAN "\xF2\xE7\xC7\xF4\xFE\xAD\x4D\xFB\xB2\x35\x36\x79\x8B\xDF\0\0"
+extern char AIM_CAP_MIRANDA[]; //Miranda cap EXTERN
+
+//Aim Services
+#define AIM_SERVICE_GENERIC "\0\x01\0\x04"//version 4
+#define AIM_SERVICE_SSI "\0\x13\0\x03"//version 3
+#define AIM_SERVICE_LOCATION "\0\x02\0\x01"//version 1
+#define AIM_SERVICE_BUDDYLIST "\0\x03\0\x01"//version 1
+#define AIM_SERVICE_MESSAGING "\0\x04\0\x01"//version 1
+#define AIM_SERVICE_INVITATION "\0\x06\0\x01"//version 1
+#define AIM_SERVICE_ADMIN "\0\x07\0\x01"//version 1
+#define AIM_SERVICE_POPUP "\0\x08\0\x01"//version 1
+#define AIM_SERVICE_BOS "\0\x09\0\x01"//version 1
+#define AIM_SERVICE_AVATAR "\0\x10\0\x01"//version 1
+#define AIM_SERVICE_USERLOOKUP "\0\x0A\0\x01"//version 1
+#define AIM_SERVICE_STATS "\0\x0B\0\x01"//version 1
+#define AIM_SERVICE_CHATNAV "\0\x0D\0\x01"//version 1
+#define AIM_SERVICE_DIRSEARCH "\0\x0F\0\x01"//version 1
+#define AIM_SERVICE_CHAT "\0\x0E\0\x01"//version 1
+#define AIM_SERVICE_ICQ "\0\x15\0\x01"//version 1
+#define AIM_SERVICE_MAIL "\0\x18\0\x01"//version 1
+#define AIM_SERVICE_UNKNOWN "\0\x22\0\x01"//version 1
+#define AIM_SERVICE_RATES "\0\x01\0\x02\0\x03\0\x04\0\x05"
+
+//Aim Statuses
+#define AIM_STATUS_WEBAWARE "\0\x01"
+#define AIM_STATUS_SHOWIP "\0\x02"
+#define AIM_STATUS_BIRTHDAY "\0\x08"
+#define AIM_STATUS_WEBFRONT "\0\x20"
+#define AIM_STATUS_DCAUTH "\x10\0"
+#define AIM_STATUS_DCCONT "\x20\0"
+#define AIM_STATUS_NULL "\0\0"
+
+#define AIM_STATUS_ONLINE 0x00000000
+#define AIM_STATUS_AWAY 0x00000001
+#define AIM_STATUS_DND 0x00000002
+#define AIM_STATUS_OUT 0x00000004
+#define AIM_STATUS_BUSY 0x00000010
+#define AIM_STATUS_CHAT 0x00000020 // Broken. If set, you cannot unset.
+#define AIM_STATUS_INVISIBLE 0x00000100
+
+extern HINSTANCE hInstance; //plugin dll instance
+
+#define _strlens(a) (a ? strlen(a) : 0)
+#define _strcmps(a,b) (a != b && (!a || !b || strcmp(a, b)))
+
+//#define ALLOW_BUSY
+
+#endif
diff --git a/protocols/AimOscar/src/avatars.cpp b/protocols/AimOscar/src/avatars.cpp
new file mode 100644
index 0000000000..4c7de35f18
--- /dev/null
+++ b/protocols/AimOscar/src/avatars.cpp
@@ -0,0 +1,312 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "avatars.h"
+
+#include "m_folders.h"
+
+void __cdecl CAimProto::avatar_request_thread(void* param)
+{
+ HANDLE hContact = (HANDLE)param;
+
+ char *sn = getSetting(hContact, AIM_KEY_SN);
+ LOG("Starting avatar request thread for %s)", sn);
+
+ if (wait_conn(hAvatarConn, hAvatarEvent, 0x10))
+ {
+ char *hash_str = getSetting(hContact, AIM_KEY_AH);
+ char type = getByte(hContact, AIM_KEY_AHT, 1);
+
+ size_t len = (strlen(hash_str) + 1) / 2;
+ char* hash = (char*)alloca(len);
+ string_to_bytes(hash_str, hash);
+ LOG("Requesting an Avatar: %s (Hash: %s)", sn, hash_str);
+ aim_request_avatar(hAvatarConn, avatar_seqno, sn, type, hash, (unsigned short)len);
+
+ mir_free(hash_str);
+ }
+
+ mir_free(sn);
+}
+
+void __cdecl CAimProto::avatar_upload_thread(void* param)
+{
+ avatar_up_req* req = (avatar_up_req*)param;
+
+ if (wait_conn(hAvatarConn, hAvatarEvent, 0x10))
+ {
+ if (req->size2)
+ {
+ aim_upload_avatar(hAvatarConn, avatar_seqno, 1, req->data2, req->size2);
+ aim_upload_avatar(hAvatarConn, avatar_seqno, 12, req->data1, req->size1);
+ }
+ else
+ aim_upload_avatar(hAvatarConn, avatar_seqno, 1, req->data1, req->size1);
+ }
+ delete req;
+}
+
+void CAimProto::avatar_request_handler(HANDLE hContact, char* hash, unsigned char type)//checks to see if the avatar needs requested
+{
+ if (hContact == NULL)
+ {
+ hash = hash_lg ? hash_lg : hash_sm;
+ type = hash_lg ? 12 : 1;
+ }
+
+ char* saved_hash = getSetting(hContact, AIM_KEY_AH);
+ if (hash && _stricmp(hash, "0201d20472") && _stricmp(hash, "2b00003341")) //gaim default icon fix- we don't want their blank icon displaying.
+ {
+ if (_strcmps(saved_hash, hash))
+ {
+ setByte(hContact, AIM_KEY_AHT, type);
+ setString(hContact, AIM_KEY_AH, hash);
+
+ sendBroadcast(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
+ }
+ }
+ else
+ {
+ if (saved_hash)
+ {
+ deleteSetting(hContact, AIM_KEY_AHT);
+ deleteSetting(hContact, AIM_KEY_AH);
+
+ sendBroadcast(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
+ }
+ }
+ mir_free(saved_hash);
+}
+
+void CAimProto::avatar_retrieval_handler(const char* sn, const char* hash, const char* data, int data_len)
+{
+ bool res = false;
+ PROTO_AVATAR_INFORMATIONT AI = {0};
+ AI.cbSize = sizeof(AI);
+
+ AI.hContact = contact_from_sn(sn);
+
+ if (data_len > 0)
+ {
+ const TCHAR *type;
+ AI.format = detect_image_type(data, type);
+ get_avatar_filename(AI.hContact, AI.filename, SIZEOF(AI.filename), type);
+
+ int fileId = _topen(AI.filename, _O_CREAT | _O_TRUNC | _O_WRONLY | O_BINARY, _S_IREAD | _S_IWRITE);
+ if (fileId >= 0)
+ {
+ _write(fileId, data, data_len);
+ _close(fileId);
+ res = true;
+
+ char *my_sn = getSetting(AIM_KEY_SN);
+ if (!_strcmps(sn, my_sn))
+ CallService(MS_AV_REPORTMYAVATARCHANGED, (WPARAM)m_szModuleName, 0);
+ mir_free(my_sn);
+ }
+// else
+// ShowError("Cannot set avatar. File '%s' could not be created/overwritten", file);
+ }
+ else
+ LOG("AIM sent avatar of zero length for %s.(Usually caused by repeated request for the same icon)", sn);
+
+ sendBroadcast(AI.hContact, ACKTYPE_AVATAR, res ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, &AI, 0);
+}
+
+int detect_image_type(const char* stream, const TCHAR* &type_ret)
+{
+ if(stream[0]=='G'&&stream[1]=='I'&&stream[2]=='F')
+ {
+ type_ret = _T(".gif");
+ return PA_FORMAT_GIF;
+ }
+ else if(stream[1]=='P'&&stream[2]=='N'&&stream[3]=='G')
+ {
+ type_ret = _T(".png");
+ return PA_FORMAT_PNG;
+ }
+ else if(stream[0]=='B'&&stream[1]=='M')
+ {
+ type_ret = _T(".bmp");
+ return PA_FORMAT_BMP;
+ }
+ else//assume jpg
+ {
+ type_ret = _T(".jpg");
+ return PA_FORMAT_JPEG;
+ }
+}
+
+int detect_image_type(const TCHAR* file)
+{
+ const TCHAR *ext = _tcsrchr(file, '.');
+ if (ext == NULL)
+ return PA_FORMAT_UNKNOWN;
+ if (_tcsicmp(ext, _T(".gif")) == 0)
+ return PA_FORMAT_GIF;
+ else if (_tcsicmp(ext, _T(".bmp")) == 0)
+ return PA_FORMAT_BMP;
+ else if (_tcsicmp(ext, _T(".png")) == 0)
+ return PA_FORMAT_PNG;
+ else
+ return PA_FORMAT_JPEG;
+}
+
+void CAimProto::init_custom_folders(void)
+{
+ if (init_cst_fld_ran) return;
+
+ TCHAR AvatarsFolder[MAX_PATH];
+
+ TCHAR *tszModuleName = mir_a2t(m_szModuleName);
+ mir_sntprintf(AvatarsFolder, SIZEOF(AvatarsFolder), _T("%%miranda_avatarcache%%\\%s"), tszModuleName);
+ hAvatarsFolder = FoldersRegisterCustomPathT(m_szModuleName, "Avatars", AvatarsFolder);
+ mir_free(tszModuleName);
+
+ init_cst_fld_ran = true;
+}
+
+int CAimProto::get_avatar_filename(HANDLE hContact, TCHAR* pszDest, size_t cbLen, const TCHAR *ext)
+{
+ size_t tPathLen;
+ bool found = false;
+
+ init_custom_folders();
+
+ TCHAR* path = (TCHAR*)alloca(cbLen * sizeof(TCHAR));
+ if (hAvatarsFolder == NULL || FoldersGetCustomPathT(hAvatarsFolder, path, (int)cbLen, _T("")))
+ {
+ TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_avatarcache%"));
+ TCHAR *tszModuleName = mir_a2t(m_szModuleName);
+ tPathLen = mir_sntprintf(pszDest, cbLen, _T("%s\\%s"), tmpPath, tszModuleName);
+ mir_free(tszModuleName);
+ mir_free(tmpPath);
+ }
+ else
+ {
+ _tcscpy(pszDest, path);
+ tPathLen = _tcslen(pszDest);
+ }
+
+ if (ext && _taccess(pszDest, 0))
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)pszDest);
+
+ size_t tPathLen2 = tPathLen;
+
+ DBVARIANT dbv;
+ if (getTString(hContact, AIM_KEY_AH, &dbv)) return GAIR_NOAVATAR;
+ tPathLen += mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T("\\%s"), dbv.ptszVal);
+ DBFreeVariant(&dbv);
+
+ if (ext == NULL)
+ {
+ mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, _T(".*"));
+
+ _tfinddata_t c_file;
+ long hFile = _tfindfirst(pszDest, &c_file);
+ if (hFile > -1L)
+ {
+ do {
+ if (_tcsrchr(c_file.name, '.'))
+ {
+ mir_sntprintf(pszDest + tPathLen2, cbLen - tPathLen2, _T("\\%s"), c_file.name);
+ found = true;
+ }
+ } while (_tfindnext(hFile, &c_file) == 0);
+ _findclose( hFile );
+ }
+
+ if (!found) pszDest[0] = 0;
+ }
+ else
+ {
+ mir_sntprintf(pszDest + tPathLen, cbLen - tPathLen, ext);
+ found = _taccess(pszDest, 0) == 0;
+ }
+
+ return found ? GAIR_SUCCESS : GAIR_WAITFOR;
+}
+
+bool get_avatar_hash(const TCHAR* file, char* hash, char** data, unsigned short &size)
+{
+ int fileId = _topen(file, _O_RDONLY | _O_BINARY, _S_IREAD);
+ if (fileId == -1) return false;
+
+ long lAvatar = _filelength(fileId);
+ if (lAvatar <= 0)
+ {
+ _close(fileId);
+ return false;
+ }
+
+ char* pResult = (char*)mir_alloc(lAvatar);
+ int res = _read(fileId, pResult, lAvatar);
+ _close(fileId);
+
+ if (res <= 0)
+ {
+ mir_free(pResult);
+ return false;
+ }
+
+ mir_md5_state_t state;
+ mir_md5_init(&state);
+ mir_md5_append(&state, (unsigned char*)pResult, lAvatar);
+ mir_md5_finish(&state, (unsigned char*)hash);
+
+ if (data)
+ {
+ *data = pResult;
+ size = (unsigned short)lAvatar;
+ }
+ else
+ mir_free(pResult);
+
+ return true;
+}
+
+void rescale_image(char *data, unsigned short size, char *&data1, unsigned short &size1)
+{
+ FI_INTERFACE *fei = NULL;
+ CallService(MS_IMG_GETINTERFACE, FI_IF_VERSION, (LPARAM) &fei);
+ if (fei == NULL) return;
+
+ FIMEMORY *hmem = fei->FI_OpenMemory((BYTE *)data, size);
+ FREE_IMAGE_FORMAT fif = fei->FI_GetFileTypeFromMemory(hmem, 0);
+ FIBITMAP *dib = fei->FI_LoadFromMemory(fif, hmem, 0);
+ fei->FI_CloseMemory(hmem);
+
+ if (fei->FI_GetWidth(dib) > 64)
+ {
+ FIBITMAP *dib1 = fei->FI_Rescale(dib, 64, 64, FILTER_BSPLINE);
+
+ FIMEMORY *hmem = fei->FI_OpenMemory(NULL, 0);
+ fei->FI_SaveToMemory(fif, dib1, hmem, 0);
+
+ BYTE *data2; DWORD size2;
+ fei->FI_AcquireMemory(hmem, &data2, &size2);
+ data1 = (char*)mir_alloc(size2);
+ memcpy(data1, data2, size2);
+ size1 = size2;
+
+ fei->FI_CloseMemory(hmem);
+ fei->FI_Unload(dib1);
+ }
+ fei->FI_Unload(dib);
+} \ No newline at end of file
diff --git a/protocols/AimOscar/src/avatars.h b/protocols/AimOscar/src/avatars.h
new file mode 100644
index 0000000000..69c7ec49bf
--- /dev/null
+++ b/protocols/AimOscar/src/avatars.h
@@ -0,0 +1,54 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef AVATARS_H
+#define AVATARS_H
+
+struct avatar_req
+{
+ char* sn;
+ char* hash;
+ unsigned char type;
+
+ avatar_req(char* sn, char* hash, unsigned char type)
+ : sn(sn), hash(mir_strdup(hash)), type(type) {}
+
+ ~avatar_req()
+ { mir_free(sn); mir_free(hash); }
+};
+
+struct avatar_up_req
+{
+ char* data1;
+ char* data2;
+ unsigned short size1;
+ unsigned short size2;
+
+ avatar_up_req(char* data1, unsigned short size1, char* data2, unsigned short size2)
+ : data1(data1), size1(size1), data2(data2), size2(size2) {}
+
+ ~avatar_up_req()
+ { mir_free(data1); mir_free(data2); }
+};
+
+int detect_image_type(const char* stream, const TCHAR* &type_ret);
+int detect_image_type(const TCHAR* file);
+bool get_avatar_hash(const TCHAR* file, char* hash, char** data, unsigned short &size);
+void rescale_image(char *data, unsigned short size, char *&data1, unsigned short &size1);
+
+#endif
diff --git a/protocols/AimOscar/src/away.cpp b/protocols/AimOscar/src/away.cpp
new file mode 100644
index 0000000000..45ed0097cd
--- /dev/null
+++ b/protocols/AimOscar/src/away.cpp
@@ -0,0 +1,125 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+char** CAimProto::get_status_msg_loc(int status)
+{
+ static const int modes[] =
+ {
+ ID_STATUS_ONLINE,
+ ID_STATUS_AWAY,
+ ID_STATUS_DND,
+ ID_STATUS_NA,
+ ID_STATUS_OCCUPIED,
+ ID_STATUS_FREECHAT,
+ ID_STATUS_INVISIBLE,
+ ID_STATUS_ONTHEPHONE,
+ ID_STATUS_OUTTOLUNCH,
+ };
+
+ for (int i=0; i<9; i++)
+ if (modes[i] == status) return &modeMsgs[i];
+
+ return NULL;
+}
+
+int CAimProto::aim_set_away(HANDLE hServerConn, unsigned short &seqno, const char *amsg, bool set)//user info
+{
+ unsigned short offset=0;
+ char* html_msg = NULL;
+ size_t msg_size = 0;
+ if (set)
+ {
+ if (!amsg) return -1;
+ setDword(AIM_KEY_LA, (DWORD)time(NULL));
+ html_msg = html_encode(amsg && amsg[0] ? amsg : DEFAULT_AWAY_MSG);
+ msg_size = strlen(html_msg);
+ }
+
+ aimString str(html_msg);
+ const char *charset = str.isUnicode() ? AIM_MSG_TYPE_UNICODE : AIM_MSG_TYPE;
+ const unsigned short charset_len = (unsigned short)strlen(charset);
+
+ const char* msg = str.getBuf();
+ const unsigned short msg_len = str.getSize();
+
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*3+charset_len+msg_len+1);
+
+ aim_writesnac(0x02,0x04,offset,buf);
+ aim_writetlv(0x03,charset_len,charset,offset,buf);
+ aim_writetlv(0x04,(unsigned short)msg_len,msg,offset,buf);
+
+// aim_writetlvchar(0x0f,2,offset,buf);
+
+ mir_free(html_msg);
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_status(HANDLE hServerConn,unsigned short &seqno,unsigned long status_type)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*2];
+ aim_writesnac(0x01,0x1E,offset,buf);
+ aim_writetlvlong(0x06,status_type,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_statusmsg(HANDLE hServerConn,unsigned short &seqno,const char *msg)//user info
+{
+ size_t msg_size =_strlens(msg);
+
+ unsigned short msgoffset=0;
+ char* msgbuf=(char*)alloca(10+msg_size);
+
+ if (msg_size)
+ {
+ char* msgb=(char*)alloca(4+msg_size);
+ msgb[0]=(unsigned char)(msg_size >> 8);
+ msgb[1]=(unsigned char)(msg_size & 0xff);
+ memcpy(&msgb[2],msg,msg_size);
+ msgb[msg_size+2]=0;
+ msgb[msg_size+3]=0;
+
+ aim_writebartid(2,4,(unsigned short)(msg_size+4),msgb,msgoffset,msgbuf);
+ }
+ else
+ aim_writebartid(2,0,0,NULL,msgoffset,msgbuf);
+
+ unsigned short offset=0;
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE+msgoffset+8);
+ aim_writesnac(0x01,0x1e,offset,buf);
+ aim_writetlv(0x1d,msgoffset,msgbuf,offset,buf);
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_query_away_message(HANDLE hServerConn,unsigned short &seqno,const char* sn)
+{
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ char* buf=(char*)alloca(SNAC_SIZE+5+sn_length);
+ aim_writesnac(0x02,0x15,offset,buf);
+ aim_writegeneric(4,"\0\0\0\x02",offset,buf);
+ aim_writegeneric(1,(char*)&sn_length,offset,buf);
+ aim_writegeneric(sn_length,sn,offset,buf);
+ int res=aim_sendflap(hServerConn,0x02,offset,buf,seqno)==0;
+ return res;
+}
+
diff --git a/protocols/AimOscar/src/chat.cpp b/protocols/AimOscar/src/chat.cpp
new file mode 100644
index 0000000000..1c9f329486
--- /dev/null
+++ b/protocols/AimOscar/src/chat.cpp
@@ -0,0 +1,343 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+static const COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+void CAimProto::chat_register(void)
+{
+ GCREGISTER gcr = {0};
+ gcr.cbSize = sizeof(gcr);
+ gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR | GC_TCHAR;
+ gcr.iMaxText = 0;
+ gcr.nColors = 16;
+ gcr.pColors = (COLORREF*)crCols;
+ gcr.ptszModuleDispName = m_tszUserName;
+ gcr.pszModule = m_szModuleName;
+ CallServiceSync(MS_GC_REGISTER, 0, (LPARAM)&gcr);
+
+ HookProtoEvent(ME_GC_EVENT, &CAimProto::OnGCEvent);
+ HookProtoEvent(ME_GC_BUILDMENU, &CAimProto::OnGCMenuHook );
+}
+
+void CAimProto::chat_start(const char* id, unsigned short exchange)
+{
+ TCHAR* idt = mir_a2t(id);
+
+ GCSESSION gcw = {0};
+ gcw.cbSize = sizeof(gcw);
+ gcw.dwFlags = GC_TCHAR;
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = m_szModuleName;
+ gcw.ptszName = idt;
+ gcw.ptszID = idt;
+ CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw);
+
+ GCDEST gcd = { m_szModuleName, { NULL }, GC_EVENT_ADDGROUP };
+ gcd.ptszID = idt;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(gce);
+ gce.dwFlags = GC_TCHAR;
+ gce.pDest = &gcd;
+ gce.ptszStatus = TranslateT("Me");
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.ptszStatus = TranslateT("Others");
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_CONTROL;
+ CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
+ CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+ CallServiceSync(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce);
+
+ setWord(find_chat_contact(id), "Exchange", exchange);
+
+ mir_free(idt);
+}
+
+void CAimProto::chat_event(const char* id, const char* sn, int evt, const TCHAR* msg)
+{
+ TCHAR* idt = mir_a2t(id);
+ TCHAR* snt = mir_a2t(sn);
+
+ HANDLE hContact = contact_from_sn(sn);
+ TCHAR* nick = hContact ? (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,
+ WPARAM(hContact), GCDNF_TCHAR) : snt;
+
+ GCDEST gcd = { m_szModuleName, { NULL }, evt };
+ gcd.ptszID = idt;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(gce);
+ gce.dwFlags = GC_TCHAR | GCEF_ADDTOLOG;
+ gce.pDest = &gcd;
+ gce.ptszNick = nick;
+ gce.ptszUID = snt;
+ gce.bIsMe = _stricmp(sn, username) == 0;
+ gce.ptszStatus = gce.bIsMe ? TranslateT("Me") : TranslateT("Others");
+ gce.ptszText = msg;
+ gce.time = time(NULL);
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ mir_free(snt);
+ mir_free(idt);
+}
+
+void CAimProto::chat_leave(const char* id)
+{
+ TCHAR* idt = mir_a2t(id);
+
+ GCDEST gcd = { m_szModuleName, { NULL }, GC_EVENT_CONTROL };
+ gcd.ptszID = idt;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.dwFlags = GC_TCHAR;
+ gce.pDest = &gcd;
+ CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce);
+ CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
+
+ mir_free(idt);
+}
+
+
+int CAimProto::OnGCEvent(WPARAM wParam,LPARAM lParam)
+{
+ GCHOOK *gch = (GCHOOK*) lParam;
+ if (!gch) return 1;
+
+ if (strcmp(gch->pDest->pszModule, m_szModuleName)) return 0;
+
+ char* id = mir_t2a(gch->pDest->ptszID);
+ chat_list_item* item = find_chat_by_id(id);
+
+ if (item == NULL) return 0;
+
+ switch (gch->pDest->iType)
+ {
+ case GC_SESSION_TERMINATE:
+ aim_sendflap(item->hconn,0x04,0,NULL,item->seqno);
+ Netlib_Shutdown(item->hconn);
+ break;
+
+ case GC_USER_MESSAGE:
+ if (gch->ptszText && _tcslen(gch->ptszText))
+ {
+ char* msg = mir_utf8encodeT(gch->ptszText);
+ aim_chat_send_message(item->hconn, item->seqno, msg);
+ mir_free(msg);
+ }
+ break;
+ case GC_USER_CHANMGR:
+ DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), NULL, invite_to_chat_dialog,
+ LPARAM(new invite_chat_param(item->id, this)));
+ break;
+
+ case GC_USER_PRIVMESS:
+ {
+ char* sn = mir_t2a(gch->ptszUID);
+ HANDLE hContact = contact_from_sn(sn);
+ mir_free(sn);
+ CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0);
+ }
+ break;
+
+ case GC_USER_LOGMENU:
+ switch(gch->dwData)
+ {
+ case 10:
+ DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHATROOM_INVITE), NULL, invite_to_chat_dialog,
+ LPARAM(new invite_chat_param(item->id, this)));
+ break;
+
+ case 20:
+ chat_leave(id);
+ break;
+ }
+ break;
+
+ case GC_USER_NICKLISTMENU:
+ {
+ char *sn = mir_t2a(gch->ptszUID);
+ HANDLE hContact = contact_from_sn(sn);
+ mir_free(sn);
+
+ switch (gch->dwData)
+ {
+ case 10:
+ CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0);
+ break;
+
+ case 20:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)hContact, 0);
+ break;
+
+ case 110:
+ chat_leave(id);
+ break;
+ }
+ }
+ break;
+
+ case GC_USER_TYPNOTIFY:
+ break;
+ }
+ mir_free(id);
+
+ return 0;
+}
+
+int CAimProto::OnGCMenuHook(WPARAM wParam,LPARAM lParam)
+{
+ GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam;
+
+ if ( gcmi == NULL || _stricmp(gcmi->pszModule, m_szModuleName )) return 0;
+
+ if ( gcmi->Type == MENU_ON_LOG )
+ {
+ static const struct gc_item Items[] = {
+ { TranslateT("&Invite user..."), 10, MENU_ITEM, FALSE },
+ { TranslateT("&Leave chat session"), 20, MENU_ITEM, FALSE }
+ };
+ gcmi->nItems = SIZEOF(Items);
+ gcmi->Item = (gc_item*)Items;
+ }
+ else if ( gcmi->Type == MENU_ON_NICKLIST )
+ {
+ char* sn = mir_t2a(gcmi->pszUID);
+ if ( !strcmp(username, sn))
+ {
+ static const struct gc_item Items[] = {
+ { TranslateT("User &details"), 10, MENU_ITEM, FALSE },
+ { TranslateT("User &history"), 20, MENU_ITEM, FALSE },
+ { _T(""), 100, MENU_SEPARATOR, FALSE },
+ { TranslateT("&Leave chat session"), 110, MENU_ITEM, FALSE }
+ };
+ gcmi->nItems = SIZEOF(Items);
+ gcmi->Item = (gc_item*)Items;
+ }
+ else {
+ static const struct gc_item Items[] = {
+ { TranslateT("User &details"), 10, MENU_ITEM, FALSE },
+ { TranslateT("User &history"), 20, MENU_ITEM, FALSE }
+ };
+ gcmi->nItems = SIZEOF(Items);
+ gcmi->Item = (gc_item*)Items;
+ }
+ mir_free(sn);
+ }
+
+ return 0;
+}
+
+
+void __cdecl CAimProto::chatnav_request_thread( void* param )
+{
+ chatnav_param* par = (chatnav_param*)param;
+
+ if (wait_conn(hChatNavConn, hChatNavEvent, 0x0d))
+ {
+ if (par->isroom)
+ aim_chatnav_create(hChatNavConn, chatnav_seqno, par->id, par->exchange);
+ else
+ aim_chatnav_room_info(hChatNavConn, chatnav_seqno, par->id, par->exchange, par->instance);
+ }
+ delete par;
+}
+
+chat_list_item* CAimProto::find_chat_by_cid(unsigned short cid)
+{
+ chat_list_item* item = NULL;
+ for(int i=0; i<chat_rooms.getCount(); ++i)
+ {
+ if (chat_rooms[i].cid == cid)
+ {
+ item = &chat_rooms[i];
+ break;
+ }
+ }
+ return item;
+}
+
+chat_list_item* CAimProto::find_chat_by_id(char* id)
+{
+ chat_list_item* item = NULL;
+ for(int i=0; i<chat_rooms.getCount(); ++i)
+ {
+ if (strcmp(chat_rooms[i].id, id) == 0)
+ {
+ item = &chat_rooms[i];
+ break;
+ }
+ }
+ return item;
+}
+
+chat_list_item* CAimProto::find_chat_by_conn(HANDLE conn)
+{
+ chat_list_item* item = NULL;
+ for(int i=0; i<chat_rooms.getCount(); ++i)
+ {
+ if (chat_rooms[i].hconn == conn)
+ {
+ item = &chat_rooms[i];
+ break;
+ }
+ }
+ return item;
+}
+
+void CAimProto::remove_chat_by_ptr(chat_list_item* item)
+{
+ for(int i=0; i<chat_rooms.getCount(); ++i)
+ {
+ if (&chat_rooms[i] == item)
+ {
+ chat_rooms.remove(i);
+ break;
+ }
+ }
+}
+
+void CAimProto::shutdown_chat_conn(void)
+{
+ for(int i=0; i<chat_rooms.getCount(); ++i)
+ {
+ chat_list_item& item = chat_rooms[i];
+ if (item.hconn)
+ {
+ aim_sendflap(item.hconn,0x04,0,NULL,item.seqno);
+ Netlib_Shutdown(item.hconn);
+ }
+ }
+}
+
+void CAimProto::close_chat_conn(void)
+{
+ for(int i=0; i<chat_rooms.getCount(); ++i)
+ {
+ chat_list_item& item = chat_rooms[i];
+ if (item.hconn)
+ {
+ Netlib_CloseHandle(item.hconn);
+ item.hconn = NULL;
+ }
+ }
+} \ No newline at end of file
diff --git a/protocols/AimOscar/src/chat.h b/protocols/AimOscar/src/chat.h
new file mode 100644
index 0000000000..5b819544aa
--- /dev/null
+++ b/protocols/AimOscar/src/chat.h
@@ -0,0 +1,53 @@
+#ifndef CHAT_H
+#define CHAT_H
+
+struct chatnav_param
+{
+ char* id;
+ unsigned short exchange;
+ unsigned short instance;
+
+ char* message;
+ char* sn;
+ char* icbm_cookie;
+
+ bool isroom;
+
+ chatnav_param(char* tid, unsigned short ex, unsigned short in, char* msg, char* nm, char* icki)
+ { id = tid; exchange = ex; instance = in; isroom = false;
+ message = mir_strdup(msg); sn = mir_strdup(nm); icbm_cookie = (char*)mir_alloc(8); memcpy(icbm_cookie, icki, 8); }
+
+ chatnav_param(char* tid, unsigned short ex)
+ { id = mir_strdup(tid); exchange = ex; isroom = true;
+ message = NULL; sn = NULL; icbm_cookie = NULL; }
+
+ ~chatnav_param()
+ {
+ mir_free(id);
+ mir_free(message);
+ mir_free(sn);
+ mir_free(icbm_cookie);
+ }
+};
+
+struct chat_list_item
+{
+ char* id;
+ char* cookie;
+ HANDLE hconn;
+ unsigned short cid;
+ unsigned short seqno;
+ unsigned short exchange;
+ unsigned short instance;
+ char* CHAT_COOKIE;
+ int CHAT_COOKIE_LENGTH;
+
+ chat_list_item(char* tid, char* tcookie, unsigned short ex, unsigned short in)
+ { id = mir_strdup(tid); cid = get_random(); seqno = 0; hconn = NULL;
+ cookie = mir_strdup(tcookie); exchange = ex; instance = in; }
+
+ ~chat_list_item()
+ { mir_free(id); mir_free(cookie); }
+};
+
+#endif \ No newline at end of file
diff --git a/protocols/AimOscar/src/client.cpp b/protocols/AimOscar/src/client.cpp
new file mode 100644
index 0000000000..5c4421ac11
--- /dev/null
+++ b/protocols/AimOscar/src/client.cpp
@@ -0,0 +1,994 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "version.h"
+
+int CAimProto::aim_send_connection_packet(HANDLE hServerConn,unsigned short &seqno,char *buf)
+{
+ return aim_sendflap(hServerConn,0x01,4,buf,seqno);
+}
+
+int CAimProto::aim_authkey_request(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*3+strlen(username));
+ aim_writesnac(0x17,0x06,offset,buf);
+ aim_writetlv(0x01,(unsigned short)strlen(username),username,offset,buf);
+ aim_writetlv(0x4B,0,0,offset,buf);
+ aim_writetlv(0x5A,0,0,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_auth_request(HANDLE hServerConn,unsigned short &seqno,const char* key,const char* language,
+ const char* country, const char* username, const char* password)
+{
+ unsigned short offset=0;
+ mir_md5_byte_t pass_hash[16];
+ mir_md5_byte_t auth_hash[16];
+ mir_md5_state_t state;
+
+ mir_md5_init(&state);
+ mir_md5_append(&state,(const mir_md5_byte_t *)password, (int)strlen(password));
+ mir_md5_finish(&state,pass_hash);
+ mir_md5_init(&state);
+ mir_md5_append(&state,(mir_md5_byte_t*)key, (int)strlen(key));
+ mir_md5_append(&state,(mir_md5_byte_t*)pass_hash,MD5_HASH_LENGTH);
+ mir_md5_append(&state,(mir_md5_byte_t*)AIM_MD5_STRING, sizeof(AIM_MD5_STRING)-1);
+ mir_md5_finish(&state,auth_hash);
+
+ char client_id[64], mirver[64];
+ CallService(MS_SYSTEM_GETVERSIONTEXT, sizeof(mirver), (LPARAM)mirver);
+ int client_id_len = mir_snprintf(client_id, sizeof(client_id), "Miranda AIM, version %s", mirver);
+
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*14+MD5_HASH_LENGTH+strlen(username)+client_id_len+30+strlen(language)+strlen(country));
+
+ aim_writesnac(0x17,0x02,offset,buf);
+ aim_writetlv(0x01,(unsigned short)strlen(username),username,offset,buf);
+ aim_writetlv(0x25,MD5_HASH_LENGTH,(char*)auth_hash,offset,buf);
+ aim_writetlv(0x4C,0,0,offset,buf);//signifies new password hash instead of old method
+ aim_writetlv(0x03,(unsigned short)client_id_len,client_id,offset,buf);
+ aim_writetlvshort(0x17,AIM_CLIENT_MAJOR_VERSION,offset,buf);
+ aim_writetlvshort(0x18,AIM_CLIENT_MINOR_VERSION,offset,buf);
+ aim_writetlvshort(0x19,AIM_CLIENT_LESSER_VERSION,offset,buf);
+ aim_writetlvshort(0x1A,AIM_CLIENT_BUILD_NUMBER,offset,buf);
+ aim_writetlvshort(0x16,AIM_CLIENT_ID_NUMBER,offset,buf);
+ aim_writetlvlong(0x14,AIM_CLIENT_DISTRIBUTION_NUMBER,offset,buf);
+ aim_writetlv(0x0F,(unsigned short)strlen(language),language,offset,buf);
+ aim_writetlv(0x0E,(unsigned short)strlen(country),country,offset,buf);
+ aim_writetlvchar(0x4A,getByte(AIM_KEY_FSC, 0) ? 3 : 1,offset,buf);
+// aim_writetlvchar(0x94,0,offset,buf);
+ if (!getByte(AIM_KEY_DSSL, 0))
+ aim_writetlv(0x8c,0,NULL,offset,buf); // Request SSL connection
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_send_cookie(HANDLE hServerConn,unsigned short &seqno,int cookie_size,char * cookie)
+{
+ unsigned short offset=0;
+ char* buf=(char*)alloca(TLV_HEADER_SIZE*2+cookie_size);
+ aim_writelong(0x01,offset,buf);//protocol version number
+ aim_writetlv(0x06,(unsigned short)cookie_size,cookie,offset,buf);
+ return aim_sendflap(hServerConn,0x01,offset,buf,seqno);
+}
+
+int CAimProto::aim_send_service_request(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*12];
+ aim_writesnac(0x01,0x17,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writefamily(AIM_SERVICE_SSI,offset,buf);
+ aim_writefamily(AIM_SERVICE_LOCATION,offset,buf);
+ aim_writefamily(AIM_SERVICE_BUDDYLIST,offset,buf);
+ aim_writefamily(AIM_SERVICE_MESSAGING,offset,buf);
+ aim_writefamily(AIM_SERVICE_ICQ,offset,buf);
+ aim_writefamily(AIM_SERVICE_INVITATION,offset,buf);
+ aim_writefamily(AIM_SERVICE_POPUP,offset,buf);
+ aim_writefamily(AIM_SERVICE_BOS,offset,buf);
+ aim_writefamily(AIM_SERVICE_USERLOOKUP,offset,buf);
+ aim_writefamily(AIM_SERVICE_STATS,offset,buf);
+ aim_writefamily(AIM_SERVICE_UNKNOWN,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_new_service_request(HANDLE hServerConn,unsigned short &seqno,unsigned short service)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+2+TLV_HEADER_SIZE];
+ aim_writesnac(0x01,0x04,offset,buf);
+ aim_writeshort(service,offset,buf);
+ if (!getByte(AIM_KEY_DSSL, 0))
+ aim_writetlv(0x8c,0,NULL,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_request_rates(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x01,0x06,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_accept_rates(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE*2];
+ aim_writesnac(0x01,0x08,offset,buf);
+ aim_writegeneric(10,AIM_SERVICE_RATES,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_request_icbm(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x04,0x04,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_icbm(HANDLE hServerConn,unsigned short &seqno)
+{
+ const unsigned icbm_flags = ICBM_CHANNEL_MSGS_ALLOWED | ICBM_MISSED_CALLS_ENABLED |
+ ICBM_EVENTS_ALLOWED | ICBM_SMS_SUPPORTED | ICBM_OFFLINE_MSGS_ALLOWED;
+// const unsigned icbm_flags = 0x3db;
+
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+16];
+ aim_writesnac(0x04,0x02,offset,buf);
+ aim_writeshort(0,offset,buf); //channel
+ aim_writelong(icbm_flags,offset,buf); //flags
+ aim_writeshort(0x1f40,offset,buf); //max snac size 8000
+ aim_writeshort(0x03e7,offset,buf); //max sender warning level 999 (0-1000) WinAim default
+ aim_writeshort(0x03e7,offset,buf); //max receiver warning level 999 (0-1000) WinAim default
+ aim_writelong(0,offset,buf); //min message interval, ms 0
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_request_offline_msgs(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x04,0x10,offset,buf); // Subtype for offline messages 0x10
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_request_list(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x13,0x04,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_activate_list(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x13,0x07,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+/*
+0000 00 05 00 02 00 17 00 06 00 03 00 00 00 00 07 00 ................
+0010 01 00 00 08 00 01 01 00 0a 00 14 00 02 00 08 66 ...............f
+0020 61 63 65 62 6f 6f 6b 00 06 67 6f 6f 67 6c 65 acebook..google
+
+int CAimProto::aim_request_rights(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+50];
+ aim_writesnac(0x03,0x02,offset,buf);
+ aim_writetlvshort(0x05,0x17,offset,buf);
+ aim_writetlv(0x06,3,"\x0\x0",offset,buf);
+ aim_writetlvchar(0x07,0x01,offset,buf);
+ aim_writetlvshort(0x05,0x17,offset,buf);
+ aim_writetlvshort(0x05,0x17,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+*/
+int CAimProto::aim_set_caps(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ int i=1;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*3+AIM_CAPS_LENGTH*50+sizeof(AIM_MSG_TYPE)];
+ char temp[AIM_CAPS_LENGTH*20];
+ memcpy(temp,AIM_CAP_SHORT_CAPS,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_HOST_STATUS_TEXT_AWARE,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_SMART_CAPS,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_FILE_TRANSFER,AIM_CAPS_LENGTH);
+// memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_HAS_MICROPHONE,AIM_CAPS_LENGTH);
+// memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_RTCAUDIO,AIM_CAPS_LENGTH);
+// memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_HAS_CAMERA,AIM_CAPS_LENGTH);
+// memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_RTCVIDEO,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_BUDDY_ICON,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_CHAT,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_SUPPORT_ICQ,AIM_CAPS_LENGTH);
+// memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_ICQ_SERVER_RELAY,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_UTF8,AIM_CAPS_LENGTH);
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_MIRANDA,AIM_CAPS_LENGTH);
+ if(getByte(AIM_KEY_HF, 0))
+ memcpy(&temp[AIM_CAPS_LENGTH*i++],AIM_CAP_HIPTOP,AIM_CAPS_LENGTH);
+ aim_writesnac(0x02,0x04,offset,buf);
+ aim_writetlv(0x05,(unsigned short)(AIM_CAPS_LENGTH*i),temp,offset,buf);
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_profile(HANDLE hServerConn,unsigned short &seqno, char* amsg)//user info
+{
+ aimString str(amsg);
+ const char *charset = str.isUnicode() ? AIM_MSG_TYPE_UNICODE : AIM_MSG_TYPE;
+ const unsigned short charset_len = (unsigned short)strlen(charset);
+
+ const char* msg = str.getBuf();
+ const unsigned short msg_len = str.getSize();
+
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*3+1+charset_len+msg_len);
+ unsigned short offset=0;
+
+ aim_writesnac(0x02,0x04,offset,buf);
+ aim_writetlvchar(0x0c,1,offset,buf);
+ aim_writetlv(0x01,charset_len,charset,offset,buf);
+ aim_writetlv(0x02,msg_len,msg,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_client_ready(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset = 0;
+
+ NETLIBCONNINFO connInfo = { sizeof(connInfo) };
+ CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hServerConn, (LPARAM)&connInfo);
+
+ internal_ip = connInfo.dwIpv4;
+
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*22];
+ aim_writesnac(0x01,0x02,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_SSI,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_LOCATION,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_BUDDYLIST,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_MESSAGING,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_ICQ,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_INVITATION,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ //removed extra generic server
+ aim_writefamily(AIM_SERVICE_POPUP,offset,buf);
+ aim_writegeneric(4,"\x01\x04\0\x01",offset,buf);//different version number like trillian 3.1
+ aim_writefamily(AIM_SERVICE_BOS,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_USERLOOKUP,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_STATS,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_mail_ready(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*4];
+ aim_writesnac(0x01,0x02,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_MAIL,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_avatar_ready(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*4];
+ aim_writesnac(0x01,0x02,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_AVATAR,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chatnav_ready(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*4];
+ aim_writesnac(0x01,0x02,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_CHATNAV,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chat_ready(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*4];
+ aim_writesnac(0x01,0x02,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_CHAT,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_send_message(HANDLE hServerConn,unsigned short &seqno,const char* sn,char* amsg,bool auto_response, bool blast)
+{
+ aimString str(amsg);
+
+ const char* msg = str.getBuf();
+ const unsigned short msg_len = str.getSize();
+
+ unsigned short tlv_offset=0;
+ char* tlv_buf=(char*)alloca(5+msg_len+8);
+
+ char icbm_cookie[8];
+ CallService(MS_UTILS_GETRANDOM, 8, (LPARAM)icbm_cookie);
+
+ aim_writegeneric(5,"\x05\x01\x00\x01\x01",tlv_offset,tlv_buf); // icbm im capabilities
+ aim_writeshort(0x0101,tlv_offset,tlv_buf); // icbm im text tag
+ aim_writeshort(msg_len+4,tlv_offset,tlv_buf); // icbm im text tag length
+ aim_writeshort(str.isUnicode()?2:0,tlv_offset,tlv_buf); // character set
+ aim_writeshort(0,tlv_offset,tlv_buf); // language
+
+ aim_writegeneric(msg_len,msg,tlv_offset,tlv_buf); // message text
+
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ char* buf= (char*)alloca(SNAC_SIZE+8+3+sn_length+TLV_HEADER_SIZE*3+tlv_offset);
+
+ aim_writesnac(0x04,0x06,offset,buf,get_random());
+ aim_writegeneric(8,icbm_cookie,offset,buf); // icbm cookie
+ aim_writeshort(0x01,offset,buf); // channel
+ aim_writechar((unsigned char)sn_length,offset,buf); // screen name len
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+
+ aim_writetlv(0x02,tlv_offset,tlv_buf,offset,buf);
+
+ if (!blast)
+ {
+ if(auto_response)
+ aim_writetlv(0x04,0,0,offset,buf); // auto-response message
+ else
+ {
+ aim_writetlv(0x03,0,0,offset,buf); // message ack request
+ aim_writetlv(0x06,0,0,offset,buf); // offline message storage
+ }
+ }
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno) ? 0 : *(int*)icbm_cookie & 0x7fffffff;
+}
+
+int CAimProto::aim_query_profile(HANDLE hServerConn,unsigned short &seqno,char* sn)
+{
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ char* buf=(char*)alloca(SNAC_SIZE+5+sn_length);
+ aim_writesnac(0x02,0x15,offset,buf);
+ aim_writelong(0x01,offset,buf);
+ aim_writechar((unsigned char)sn_length,offset,buf);
+ aim_writegeneric(sn_length,sn,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno)==0;
+}
+
+int CAimProto::aim_delete_contact(HANDLE hServerConn, unsigned short &seqno, char* sn, unsigned short item_id,
+ unsigned short group_id, unsigned short list, bool nil)
+{
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ char* buf=(char*)alloca(SNAC_SIZE+sn_length+10);
+ aim_writesnac(0x13,0x0a,offset,buf, get_random()); // SSI Delete
+ aim_writeshort(sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+ aim_writeshort(group_id,offset,buf); // group id
+ aim_writeshort(item_id,offset,buf); // buddy id
+ aim_writeshort(list,offset,buf); // buddy type
+ aim_writeshort(nil?4:0,offset,buf); // length of extra data
+ if (nil) aim_writetlv(0x6a,0,NULL,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_add_contact(HANDLE hServerConn, unsigned short &seqno, const char* sn, unsigned short item_id,
+ unsigned short group_id, unsigned short list, char* nick, char* note)
+{
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ unsigned short nick_length = (unsigned short)_strlens(nick);
+ unsigned short note_length = (unsigned short)_strlens(note);
+ unsigned short tlv_len = nick || note ? TLV_HEADER_SIZE * 2 + nick_length + note_length : 0;
+
+ char* buf=(char*)alloca(SNAC_SIZE + sn_length + 10 + tlv_len);
+ aim_writesnac(0x13,0x08,offset,buf, get_random()); // SSI Add
+ aim_writeshort(sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+ aim_writeshort(group_id,offset,buf); // group id
+ aim_writeshort(item_id,offset,buf); // buddy id
+ aim_writeshort(list,offset, buf); // buddy type
+ aim_writeshort(tlv_len,offset,buf); // length of extra data
+
+ if (nick || note)
+ {
+ aim_writetlv(0x13c,note_length,note,offset,buf);
+ aim_writetlv(0x131,nick_length,nick,offset,buf);
+ }
+ return aim_sendflap(hServerConn, 0x02, offset, buf, seqno);
+}
+
+int CAimProto::aim_mod_group(HANDLE hServerConn, unsigned short &seqno, const char* name, unsigned short group_id,
+ char* members, unsigned short members_length)
+{
+ unsigned short offset=0;
+ unsigned short name_length=(unsigned short)strlen(name);
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE+name_length+members_length+10);
+ aim_writesnac(0x13,0x09,offset,buf, get_random()); // SSI Edit
+ aim_writeshort(name_length,offset,buf); // group name length
+ aim_writegeneric(name_length,name,offset,buf); // group name
+ aim_writeshort(group_id,offset,buf); // group id
+ aim_writeshort(0,offset,buf); // buddy id
+ aim_writeshort(1,offset,buf); // buddy type: Group
+ aim_writeshort(TLV_HEADER_SIZE+members_length,offset,buf); // length of extra data
+ aim_writetlv(0xc8,members_length,members,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_mod_buddy(HANDLE hServerConn, unsigned short &seqno, const char* sn,
+ unsigned short buddy_id, unsigned short group_id,
+ char* nick, char* note)
+{
+ unsigned short offset=0;
+ unsigned short sn_length = (unsigned short)strlen(sn);
+ unsigned short nick_length = (unsigned short)_strlens(nick);
+ unsigned short note_length = (unsigned short)_strlens(note);
+ unsigned short tlv_len = TLV_HEADER_SIZE * 2 + nick_length + note_length;
+
+ char* buf=(char*)alloca(SNAC_SIZE+sn_length+10+tlv_len);
+ aim_writesnac(0x13,0x09,offset,buf, get_random()); // SSI Edit
+ aim_writeshort(sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+ aim_writeshort(buddy_id,offset,buf); // buddy id
+ aim_writeshort(group_id,offset,buf); // group id
+ aim_writeshort(0,offset,buf); // buddy type: Buddy
+ aim_writeshort(tlv_len,offset,buf); // length of extra data
+
+ aim_writetlv(0x13c,note_length,note,offset,buf);
+ aim_writetlv(0x131,nick_length,nick,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_pd_info(HANDLE hServerConn, unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*3+20];
+ unsigned short req = 0x09;
+ if (pd_info_id == 0)
+ {
+ pd_info_id = get_random();
+ req = 0x08;
+ }
+ aim_writesnac(0x13,req,offset,buf, get_random()); // SSI Edit/Add
+ aim_writeshort(0,offset,buf); // name length
+ aim_writeshort(0,offset,buf); // group id (root)
+ aim_writeshort(pd_info_id,offset,buf); // buddy id
+ aim_writeshort(0x4,offset,buf); // pd info id
+ aim_writeshort(0x15,offset,buf); // size
+ aim_writetlvchar(0xca,pd_mode,offset,buf); // pd mode
+ aim_writetlvlong(0xcb,0xffffffff,offset,buf); // pd mask
+ aim_writetlvlong(0xcc,pd_flags,offset,buf); // pd flags
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_ssi_update_preferences(HANDLE hServerConn, unsigned short &seqno)
+{
+ unsigned short offset = 0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*4+100];
+ unsigned short req = 0x09;
+ if (pref1_id == 0)
+ {
+ pref1_id = get_random();
+ req = 0x08;
+ }
+ aim_writesnac(0x13,req,offset,buf, get_random()); // SSI Edit/Add
+ aim_writeshort(0,offset,buf); // group name length
+ aim_writeshort(0,offset,buf); // group id (root)
+ aim_writeshort(pref1_id,offset,buf); // buddy id
+ aim_writeshort(5,offset,buf); // buddy type: Presence
+
+ unsigned short tlv_len = TLV_HEADER_SIZE * 2 + 8;
+ if (pref2_len) tlv_len += TLV_HEADER_SIZE + pref2_len;
+ if (pref2_set_len) tlv_len += TLV_HEADER_SIZE + pref2_set_len;
+
+ aim_writeshort(tlv_len,offset,buf); // length of extra data
+ aim_writetlvlong(0xc9,pref1_flags,offset,buf); // Update Buddy preferences 1
+ aim_writetlvlong(0xd6,pref1_set_flags,offset,buf); // Update Buddy preferences 1
+ if (pref2_len)
+ aim_writetlv(0xd7,pref2_len,pref2_flags,offset,buf); // Update Buddy preferences 2
+ if (pref2_set_len)
+ aim_writetlv(0xd8,pref2_set_len,pref2_set_flags,offset,buf);// Update Buddy preferences 2
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_ssi_update(HANDLE hServerConn, unsigned short &seqno, bool start)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x13,start?0x11:0x12,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno)==0;
+}
+
+int CAimProto::aim_keepalive(HANDLE hServerConn,unsigned short &seqno)
+{
+ return aim_sendflap(hServerConn,0x05,4,"\x0\x0\x0\xEE",seqno);
+}
+
+// used when requesting a regular file transfer
+int CAimProto::aim_send_file(HANDLE hServerConn, unsigned short &seqno,
+ unsigned long ip, unsigned short port,
+ bool force_proxy, file_transfer *ft)
+{
+ char msg_frag[2048];
+ unsigned short frag_offset=0;
+
+ aim_writeshort(0,frag_offset,msg_frag); // request type
+ aim_writegeneric(8,ft->icbm_cookie,frag_offset,msg_frag); // icbm cookie
+ aim_writegeneric(AIM_CAPS_LENGTH, AIM_CAP_FILE_TRANSFER,
+ frag_offset, msg_frag); // uuid
+ aim_writetlvshort(0x0a,++ft->req_num,frag_offset,msg_frag); // request number
+// aim_writetlvshort(0x12,2,frag_offset,msg_frag); // max protocol version
+
+ aim_writetlvlong(0x02,ip,frag_offset,msg_frag); // ip
+ aim_writetlvlong(0x16,~ip,frag_offset,msg_frag); // ip check
+
+ aim_writetlvshort(0x05,port,frag_offset,msg_frag); // port
+ aim_writetlvshort(0x17,~port,frag_offset,msg_frag); // port ip check
+
+ if (force_proxy)
+ aim_writetlv(0x10,0,0,frag_offset,msg_frag); // request proxy transfer
+ else
+ aim_writetlvlong(0x03,internal_ip,frag_offset,msg_frag); // ip
+
+ if (ft->req_num == 1)
+ {
+ if (ft->message)
+ {
+ aimString dscr(ft->message);
+
+ const char* charset = dscr.isUnicode() ? "unicode-2-0" : "us-ascii";
+ const unsigned short charset_len = (unsigned short)strlen(charset);
+
+ const char* desc_msg = dscr.getBuf();
+ const unsigned short desc_len = dscr.getSize();
+
+ aim_writetlv(0x0e,2,"en",frag_offset,msg_frag); // language used by the data
+ aim_writetlv(0x0d,charset_len,charset,frag_offset,msg_frag);// charset used by the data
+ aim_writetlv(0x0c,desc_len,desc_msg,frag_offset,msg_frag); // invitaion text
+ }
+
+ aim_writetlv(0x0f,0,0,frag_offset,msg_frag); // request host check
+
+ const char* fname = get_fname(ft->file);
+ const unsigned short fnlen = (unsigned short)strlen(fname);
+
+ char* fblock = (char*)alloca(9 + fnlen);
+ *(unsigned short*)&fblock[0] = _htons(ft->pfts.totalFiles > 1 ? 2 : 1); // single file transfer
+ *(unsigned short*)&fblock[2] = _htons(ft->pfts.totalFiles); // number of files
+ *(unsigned long*) &fblock[4] = _htonl(ft->pfts.totalBytes); // total bytes in files
+ memcpy(&fblock[8], fname, fnlen + 1);
+
+ const char* enc = is_utf(fname) ? "utf-8" : "us-ascii";
+ aim_writetlv(0x2711,9+fnlen,fblock,frag_offset,msg_frag); // extra data, file names, size
+ aim_writetlv(0x2712,8,enc,frag_offset,msg_frag); // character set used by data
+// aim_writetlvlong64(0x2713,ft->pfts.totalBytes,frag_offset,msg_frag); // file length
+
+ LOG("Attempting to Send a file to a buddy.");
+ }
+ else
+ {
+ aim_writetlvshort(0x14,0x0a,frag_offset,msg_frag); // Counter proposal reason
+ }
+
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(ft->sn);
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*2+12+frag_offset+sn_length);
+ aim_writesnac(0x04,0x06,offset,buf); // msg to host
+ aim_writegeneric(8,ft->icbm_cookie,offset,buf); // icbm cookie
+ aim_writeshort(2,offset,buf); // icbm channel
+ aim_writechar((unsigned char)sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,ft->sn,offset,buf); // screen name
+ aim_writetlv(0x05,frag_offset,msg_frag,offset,buf); // icbm tags
+ aim_writetlv(0x03,0,0,offset,buf); // request ack
+
+ char cip[20];
+ long_ip_to_char_ip(ip, cip);
+ LOG("IP for Buddy to connect to: %s:%u", cip, port);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno)==0;
+}
+
+
+int CAimProto::aim_file_ad(HANDLE hServerConn,unsigned short &seqno,char* sn, char* icbm_cookie, bool deny, unsigned short max_ver)
+{
+ unsigned short frag_offset=0;
+ char msg_frag[10+AIM_CAPS_LENGTH+TLV_HEADER_SIZE*2+6];
+ aim_writeshort(deny ? 1 : 2,frag_offset,msg_frag); // icbm accept / deny
+ aim_writegeneric(8,icbm_cookie,frag_offset,msg_frag); // icbm cookie
+ aim_writegeneric(AIM_CAPS_LENGTH,
+ AIM_CAP_FILE_TRANSFER,frag_offset,msg_frag); // uuid
+
+// if (max_ver > 1)
+// aim_writetlvshort(0x12,2,frag_offset,msg_frag); // max protocol version
+
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ unsigned short offset=0;
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE+21+frag_offset+sn_length);
+ aim_writesnac(0x04,0x06,offset,buf); // msg to host
+ aim_writegeneric(8,icbm_cookie,offset,buf); // icbm cookie
+ aim_writeshort(2,offset,buf); // icbm channel
+ aim_writechar((unsigned char)sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+ aim_writetlv(0x05,frag_offset,msg_frag,offset,buf); // icbm tags
+
+ LOG("%s a file transfer.", deny ? "Denying" : "Accepting");
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno)==0;
+}
+
+int CAimProto::aim_typing_notification(HANDLE hServerConn,unsigned short &seqno,char* sn,unsigned short type)
+{
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ char* buf= (char*)alloca(SNAC_SIZE+sn_length+13);
+ aim_writesnac(0x04,0x14,offset,buf);
+ aim_writegeneric(8,"\0\0\0\0\0\0\0\0",offset,buf); // icbm cookie
+ aim_writeshort(1,offset,buf); // icbm channel
+ aim_writechar((unsigned char)sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+ aim_writeshort(type,offset,buf); // typing event
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_idle(HANDLE hServerConn,unsigned short &seqno,unsigned long seconds)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+4];
+ aim_writesnac(0x01,0x11,offset,buf);
+ aim_writelong(seconds,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_request_mail(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+34];
+ aim_writesnac(0x18,0x06,offset,buf);
+ aim_writegeneric(34,
+ "\x00\x02"
+ "\xb3\x80\x9a\xd8\x0d\xba\x11\xd5\x9f\x8a\x00\x60\xb0\xee\x06\x31"
+ "\x5d\x5e\x17\x08\x55\xaa\x11\xd3\xb1\x43\x00\x60\xb0\xfb\x1e\xcb",
+ offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_activate_mail(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+17];
+ aim_writesnac(0x18,0x16,offset,buf);
+ aim_writegeneric(17,"\x02\x04\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00",offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_request_avatar(HANDLE hServerConn,unsigned short &seqno, const char* sn, unsigned short bart_type, const char* hash, unsigned short hash_size)
+{
+ unsigned short offset=0;
+ unsigned char sn_length=(unsigned char)strlen(sn);
+ char* buf= (char*)alloca(SNAC_SIZE+sn_length+hash_size+12);
+ aim_writesnac(0x10,0x06,offset,buf);
+ aim_writechar(sn_length,offset,buf); // screen name length
+ aim_writegeneric(sn_length,sn,offset,buf); // screen name
+ aim_writechar(1,offset,buf); // number of BART ID
+ aim_writebartid(bart_type,0,hash_size,hash,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_set_avatar_hash(HANDLE hServerConn, unsigned short &seqno, char flags, unsigned short bart_type, unsigned short &id, char size, const char* hash)
+{
+ unsigned short offset=0;
+
+ char bart_type_txt[8];
+ ultoa(bart_type, bart_type_txt, 10);
+ unsigned short bart_type_len = (unsigned short)strlen(bart_type_txt);
+
+ unsigned short req = 0x09;
+ if (id == 0)
+ {
+ id = get_random();
+ req = 0x08;
+ }
+
+ char* buf = (char*)alloca(SNAC_SIZE + TLV_HEADER_SIZE * 2 + 20 + size + bart_type_len);
+ aim_writesnac(0x13,req,offset,buf, get_random()); // SSI Edit/Add
+ aim_writeshort(bart_type_len,offset,buf); // name length
+ aim_writegeneric(bart_type_len,bart_type_txt,offset,buf); // name
+ aim_writeshort(0,offset,buf); // group id
+ aim_writeshort(id,offset,buf); // buddy id
+ aim_writeshort(0x14,offset,buf); // buddy type: Buddy Icon
+ aim_writeshort(2+size+TLV_HEADER_SIZE,offset,buf); // length of extra data
+
+ char* buf2 = (char*)alloca(2+size);
+ buf2[0] = flags;
+ buf2[1] = (char)size;
+ memcpy(&buf2[2], hash, size);
+ aim_writetlv(0xd5, 2+size, buf2, offset, buf); // BART
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_delete_avatar_hash(HANDLE hServerConn, unsigned short &seqno, char flags, unsigned short bart_type, unsigned short & id)
+{
+ unsigned short offset=0;
+
+ if (id == 0) return -1;
+ id = 0;
+
+ char bart_type_txt[8];
+ ultoa(bart_type, bart_type_txt, 10);
+ unsigned short bart_type_len = (unsigned short)strlen(bart_type_txt);
+
+ char* buf = (char*)alloca(SNAC_SIZE + 20 + bart_type_len);
+ aim_writesnac(0x13,0x0a,offset,buf, get_random()); // SSI Delete
+ aim_writeshort(bart_type_len,offset,buf); // name length
+ aim_writegeneric(bart_type_len,bart_type_txt,offset,buf); // name
+ aim_writeshort(0,offset,buf); // group id
+ aim_writeshort(id,offset,buf); // buddy id
+ aim_writeshort(0x14,offset,buf); // buddy type: Buddy Icon
+ aim_writeshort(0,offset,buf); // length of extra data
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_upload_avatar(HANDLE hServerConn, unsigned short &seqno, unsigned short bart_type, const char* avatar, unsigned short avatar_size)
+{
+ unsigned short offset=0;
+ char* buf=(char*)alloca(SNAC_SIZE+22+avatar_size);
+ aim_writesnac(0x10,0x02,offset,buf);
+ aim_writeshort(bart_type,offset,buf); // BART id
+ aim_writeshort(avatar_size,offset,buf);
+ aim_writegeneric(avatar_size,avatar,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_search_by_email(HANDLE hServerConn,unsigned short &seqno, const char* email)
+{
+ unsigned short offset=0;
+ char em_length=(char)strlen(email);
+ char* buf= (char*)alloca(SNAC_SIZE+em_length);
+ aim_writesnac(0x0a,0x02,offset,buf); // Email search
+ aim_writegeneric(em_length,email,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chatnav_request_limits(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE];
+ aim_writesnac(0x0d,0x02,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno) ? -1 : 0;
+}
+
+int CAimProto::aim_chatnav_create(HANDLE hServerConn,unsigned short &seqno, char* room, unsigned short exchage)
+{
+ //* Join Pseudo Room (Get's the info we need for the real connection)
+ unsigned short room_len = (unsigned short)strlen(room);
+
+ unsigned short offset=0;
+ char* buf=(char*)alloca(SNAC_SIZE+10+room_len+26);
+ aim_writesnac(0x0d,0x08,offset,buf);
+ aim_writeshort(exchage,offset,buf); // Exchange
+ aim_writechar(6,offset,buf); // Command Length
+ aim_writegeneric(6,"create",offset,buf); // Command
+ aim_writeshort(0xffff,offset,buf); // Last Instance
+ aim_writechar(1,offset,buf); // Detail
+ aim_writeshort(3,offset,buf); // Number of TLVs
+ aim_writetlv(0xd3,room_len,room,offset,buf); // Room Name
+ aim_writetlv(0xd6,8,"us-ascii",offset,buf); // Character Set
+ aim_writetlv(0xd7,2,"en",offset,buf); // Language Encoding
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chatnav_room_info(HANDLE hServerConn,unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance)
+{
+ unsigned short offset=0;
+ unsigned short chat_cookie_len = (unsigned short)strlen(chat_cookie);
+ char* buf=(char*)alloca(SNAC_SIZE+7+chat_cookie_len);
+ aim_writesnac(0x0d,0x04,offset,buf);
+ aim_writeshort(exchange,offset,buf); // Exchange
+ aim_writechar((unsigned char)chat_cookie_len,offset,buf); // Chat Cookie Length
+ aim_writegeneric(chat_cookie_len,chat_cookie,offset,buf); // Chat Cookie
+ aim_writeshort(instance,offset,buf); // Last Instance
+ aim_writechar(1,offset,buf); // Detail
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chat_join_room(HANDLE hServerConn,unsigned short &seqno, char* chat_cookie,
+ unsigned short exchange, unsigned short instance, unsigned short id)
+{
+ unsigned short offset=0;
+ unsigned short cookie_len = (unsigned short)strlen(chat_cookie);
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*2+cookie_len+8);
+ aim_writesnac(0x01,0x04,offset,buf,id);
+ aim_writeshort(0x0e,offset,buf); // Service request for Chat
+
+ aim_writeshort(0x01,offset,buf); // Tag
+ aim_writeshort(cookie_len+5,offset,buf); // Length
+ aim_writeshort(exchange,offset,buf); // Value - Exchange
+ aim_writechar((unsigned char)cookie_len,offset,buf); // Value - Cookie Length
+ aim_writegeneric(cookie_len,chat_cookie,offset,buf); // Value - Cookie
+ aim_writeshort(instance,offset,buf); // Value - Instance
+
+ if (!getByte(AIM_KEY_DSSL, 0))
+ aim_writetlv(0x8c,0,NULL,offset,buf); // Request SSL connection
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chat_send_message(HANDLE hServerConn, unsigned short &seqno, char *amsg)
+{
+ aimString str(amsg);
+
+ const char* charset = str.isUnicode() ? "unicode-2-0" : "us-ascii";
+ const unsigned short chrset_len = (unsigned short)strlen(charset);
+
+ const char* msg = str.getBuf();
+ const unsigned short msg_len = str.getSize();
+
+ unsigned short tlv_offset=0;
+ char* tlv_buf=(char*)alloca(TLV_HEADER_SIZE*4+chrset_len+msg_len+20);
+ aim_writetlv(0x04,13,"text/x-aolrtf",tlv_offset,tlv_buf); // Format
+ aim_writetlv(0x02,chrset_len,charset,tlv_offset,tlv_buf); // Character Set
+ aim_writetlv(0x03,2,"en",tlv_offset,tlv_buf); // Language Encoding
+ aim_writetlv(0x01,msg_len,msg,tlv_offset,tlv_buf); // Message
+
+ unsigned short offset=0;
+ char* buf=(char*)alloca(SNAC_SIZE+8+2+TLV_HEADER_SIZE*3+tlv_offset);
+ aim_writesnac(0x0e,0x05,offset,buf);
+ aim_writegeneric(8,"\0\0\0\0\0\0\0\0",offset,buf); // Message Cookie (can be random)
+ aim_writeshort(0x03,offset,buf); // Message Channel (Always 3 for chat)
+ aim_writetlv(0x01,0,NULL,offset,buf); // Public/Whisper flag
+ aim_writetlv(0x06,0,NULL,offset,buf); // Enable Reflection flag
+ aim_writetlv(0x05,tlv_offset,tlv_buf,offset,buf); // Message Information TLV
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chat_invite(HANDLE hServerConn,unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance, char* sn, char* msg)
+{
+ unsigned short offset=0;
+ unsigned short chat_cookie_len = (unsigned short)strlen(chat_cookie);
+ unsigned short sn_len = (unsigned short)strlen(sn);
+ unsigned short msg_len = (unsigned short)strlen(msg);
+ char* buf=(char*)alloca(SNAC_SIZE+64+chat_cookie_len+sn_len+msg_len);
+ aim_writesnac(0x04,0x06,offset,buf);
+ aim_writegeneric(8,"\0\0\0\0\0\0\0\0",offset,buf); // ICBM Cookie
+ aim_writeshort(2,offset,buf); // ICBM Channel
+ aim_writechar((unsigned char)sn_len,offset,buf); // Screen Name Length
+ aim_writegeneric(sn_len,sn,offset,buf); // Screen Name
+
+ aim_writeshort(0x05,offset,buf); // Rendezvous Message Data TLV
+ aim_writeshort(49+msg_len+chat_cookie_len,offset,buf); // TLV size
+
+ aim_writeshort(0,offset,buf); // Message Type (0) - Request
+ aim_writegeneric(8,"\0\0\0\0\0\0\0\0",offset,buf); // ICBM Cookie (same as above)
+ aim_writegeneric(16,AIM_CAP_CHAT,offset,buf); // Capability
+
+ aim_writetlvshort(0x0a,1,offset,buf); // Sequence Number TLV
+ aim_writetlv(0x0f,0,NULL,offset,buf); // Request Host Caps Check TLV
+ aim_writetlv(0x0c,msg_len,msg,offset,buf); // Invitation Message TLV
+
+ aim_writeshort(0x2711,offset,buf); // Capability TLV
+ aim_writeshort(chat_cookie_len+5,offset,buf); // Length
+ aim_writeshort(exchange,offset,buf); // Value - Exchange
+ aim_writechar((unsigned char)chat_cookie_len,offset,buf); // Value - Cookie Length
+ aim_writegeneric(chat_cookie_len,chat_cookie,offset,buf); // Value - Cookie
+ aim_writeshort(instance,offset,buf); // Value - Instance
+
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_chat_deny(HANDLE hServerConn,unsigned short &seqno,char* sn,char* icbm_cookie)
+{
+ unsigned short offset=0;
+ unsigned short sn_length=(unsigned short)strlen(sn);
+ char* buf=(char*)alloca(SNAC_SIZE+20+sn_length);
+ aim_writesnac(0x04,0x0b,offset,buf);
+ aim_writegeneric(8,icbm_cookie,offset,buf); // ICBM Cookie
+ aim_writeshort(2,offset,buf); // Channel
+ aim_writechar((unsigned char)sn_length,offset,buf); // Screen Name length
+ aim_writegeneric(sn_length,sn,offset,buf); // Screen Name
+ aim_writeshort(3,offset,buf); // Error code
+ aim_writeshort(2,offset,buf); // Error code
+ aim_writeshort(1,offset,buf); // Error code
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno)==0;
+}
+
+int CAimProto::aim_admin_ready(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE*4];
+ aim_writesnac(0x01,0x02,offset,buf);
+ aim_writefamily(AIM_SERVICE_GENERIC,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ aim_writefamily(AIM_SERVICE_ADMIN,offset,buf);
+ aim_writegeneric(4,AIM_TOOL_VERSION,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_admin_format_name(HANDLE hServerConn,unsigned short &seqno, const char* sn)
+{
+ unsigned short offset=0;
+ unsigned short sn_len = (unsigned short)strlen(sn);
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE+sn_len);
+ aim_writesnac(0x07,0x04,offset,buf);
+ aim_writetlv(0x01,sn_len,sn,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_admin_change_email(HANDLE hServerConn,unsigned short &seqno, const char* email)
+{
+ unsigned short offset=0;
+ unsigned short email_len = (unsigned short)strlen(email);
+ char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE+email_len);
+ aim_writesnac(0x07,0x04,offset,buf);
+ aim_writetlv(0x11,email_len,email,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_admin_change_password(HANDLE hServerConn,unsigned short &seqno, const char* cur_pw, const char* new_pw)
+{
+ unsigned short offset=0;
+ unsigned short cur_pw_len = (unsigned short)strlen(cur_pw);
+ unsigned short new_pw_len = (unsigned short)strlen(new_pw);
+ char* buf=(char*)alloca(SNAC_SIZE+2*TLV_HEADER_SIZE+cur_pw_len+new_pw_len);
+ aim_writesnac(0x07,0x04,offset,buf);
+ aim_writetlv(0x02,new_pw_len,new_pw,offset,buf);
+ aim_writetlv(0x12,cur_pw_len,cur_pw,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_admin_request_info(HANDLE hServerConn,unsigned short &seqno, const unsigned short &type)
+{
+ // types: 0x01 - nickname, 0x11 - email info, 0x13 - registration status
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE];
+ aim_writesnac(0x07,0x02,offset,buf);
+ aim_writetlv(type,0,NULL,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
+
+int CAimProto::aim_admin_account_confirm(HANDLE hServerConn,unsigned short &seqno)
+{
+ unsigned short offset=0;
+ char buf[SNAC_SIZE+TLV_HEADER_SIZE];
+ aim_writesnac(0x07,0x06,offset,buf);
+ return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
+}
diff --git a/protocols/AimOscar/src/connection.cpp b/protocols/AimOscar/src/connection.cpp
new file mode 100644
index 0000000000..81548f875b
--- /dev/null
+++ b/protocols/AimOscar/src/connection.cpp
@@ -0,0 +1,640 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+int CAimProto::LOG(const char *fmt, ...)
+{
+ va_list va;
+ char szText[1024];
+ if (!hNetlib)
+ return 0;
+ va_start(va, fmt);
+ mir_vsnprintf(szText, sizeof(szText), fmt, va);
+ va_end(va);
+ return CallService(MS_NETLIB_LOG, (WPARAM) hNetlib, (LPARAM) szText);
+}
+
+HANDLE CAimProto::aim_connect(const char* server, unsigned short port, bool use_ssl, const char* host)
+{
+ NETLIBOPENCONNECTION ncon = { 0 };
+ ncon.cbSize = sizeof(ncon);
+ ncon.szHost = server;
+ ncon.wPort = port;
+ ncon.timeout = 6;
+ ncon.flags = NLOCF_V2;
+ LOG("%s:%u", server, port);
+ HANDLE con = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM)hNetlib, (LPARAM)&ncon);
+ if (con && use_ssl)
+ {
+ NETLIBSSL ssl = {0};
+ ssl.cbSize = sizeof(ssl);
+ ssl.host = host;
+ if (!CallService(MS_NETLIB_STARTSSL, (WPARAM)con, (LPARAM)&ssl))
+ {
+ Netlib_CloseHandle(con);
+ con = NULL;
+ }
+ }
+ return con;
+}
+
+HANDLE CAimProto::aim_peer_connect(const char* ip, unsigned short port)
+{
+ NETLIBOPENCONNECTION ncon = { 0 };
+ ncon.cbSize = sizeof(ncon);
+ ncon.flags = NLOCF_V2;
+ ncon.szHost = ip;
+ ncon.wPort = port;
+ ncon.timeout = 3;
+ HANDLE con = (HANDLE) CallService(MS_NETLIB_OPENCONNECTION, (WPARAM) hNetlibPeer, (LPARAM) & ncon);
+ return con;
+}
+
+HANDLE CAimProto::aim_peer_connect(unsigned long ip, unsigned short port)
+{
+ char ips[20];
+ long_ip_to_char_ip(ip, ips);
+
+ return aim_peer_connect(ips, port);
+}
+
+void CAimProto::aim_connection_authorization(void)
+{
+ DBVARIANT dbv;
+ char *password = NULL;
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ HANDLE hServerPacketRecver = NULL;
+
+ if (m_iDesiredStatus == ID_STATUS_OFFLINE)
+ goto exit;
+
+ if (!getString(AIM_KEY_PW, &dbv))
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM) dbv.pszVal);
+ password = mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else
+ goto exit;
+
+ mir_free(username);
+ username = getSetting(AIM_KEY_SN);
+ if (username == NULL)
+ goto exit;
+
+ hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 2048 * 4);
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = 5000;
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM) & packetRecv);
+ if (recvResult == 0)
+ {
+ LOG("Connection Closed: No Error? during Connection Authorization");
+ break;
+ }
+ else if (recvResult < 0)
+ {
+ LOG("Connection Closed: Socket Error during Connection Authorization %d", WSAGetLastError());
+ break;
+ }
+ else
+ {
+ unsigned short flap_length=0;
+ for (;packetRecv.bytesUsed<packetRecv.bytesAvailable;packetRecv.bytesUsed=flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],(unsigned short)(packetRecv.bytesAvailable-packetRecv.bytesUsed));
+ if (!flap.len())
+ break;
+ flap_length+=FLAP_SIZE+flap.len();
+ if (flap.cmp(0x01))
+ {
+ if (aim_send_connection_packet(hServerConn, seqno,flap.val())==0)//cookie challenge
+ aim_authkey_request(hServerConn, seqno);//md5 authkey request
+ }
+ else if(flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(),flap.snaclen());
+ if(snac.cmp(0x0017))
+ {
+ snac_md5_authkey(snac,hServerConn,seqno, username, password);
+ int authres = snac_authorization_reply(snac);
+ switch (authres)
+ {
+ case 1:
+ mir_free(password);
+ Netlib_CloseHandle(hServerPacketRecver);
+ LOG("Connection Authorization Thread Ending: Negotiation Beginning");
+ return;
+
+ case 2:
+ sendBroadcast(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD);
+ goto exit;
+
+ case 3:
+ sendBroadcast(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER);
+ goto exit;
+ }
+ }
+ }
+ else if(flap.cmp(0x04))
+ {
+ LOG("Connection Authorization Thread Ending: Flap 0x04");
+ goto exit;
+ }
+ }
+ }
+ }
+
+exit:
+ mir_free(password);
+ if (m_iStatus!=ID_STATUS_OFFLINE) broadcast_status(ID_STATUS_OFFLINE);
+ if (hServerPacketRecver) Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(hServerConn); hServerConn=NULL;
+ LOG("Connection Authorization Thread Ending: End of Thread");
+}
+
+void __cdecl CAimProto::aim_protocol_negotiation( void* )
+{
+ HANDLE hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hServerConn, 2048 * 8);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER*1000;
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ {
+ LOG("Connection Closed: No Error during Connection Negotiation?");
+ break;
+ }
+ else if (recvResult == SOCKET_ERROR)
+ {
+ if (WSAGetLastError() == ERROR_TIMEOUT)
+ {
+ if (aim_keepalive(hServerConn,seqno) < 0)
+ break;
+ }
+ else
+ {
+ LOG("Connection Closed: Socket Error during Connection Negotiation %d", WSAGetLastError());
+ break;
+ }
+ }
+ else if(recvResult>0)
+ {
+ unsigned short flap_length=0;
+ for (;packetRecv.bytesUsed<packetRecv.bytesAvailable;packetRecv.bytesUsed=flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
+ if (!flap.len())
+ break;
+ flap_length+=FLAP_SIZE+flap.len();
+ if(flap.cmp(0x01))
+ {
+ aim_send_cookie(hServerConn,seqno,COOKIE_LENGTH,COOKIE);//cookie challenge
+ mir_free(COOKIE);
+ COOKIE=NULL;
+ COOKIE_LENGTH=0;
+ }
+ else if(flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(),flap.snaclen());
+ if(snac.cmp(0x0001))
+ {
+ snac_supported_families(snac,hServerConn,seqno);
+ snac_supported_family_versions(snac,hServerConn,seqno);
+ snac_rate_limitations(snac,hServerConn,seqno);
+ snac_service_redirect(snac);
+ snac_self_info(snac);
+ snac_error(snac);
+ }
+ else if(snac.cmp(0x0002))
+ {
+ snac_received_info(snac);
+ snac_error(snac);
+ }
+ else if(snac.cmp(0x0003))
+ {
+ snac_user_online(snac);
+ snac_user_offline(snac);
+ snac_error(snac);
+ }
+ else if(snac.cmp(0x0004))
+ {
+ snac_icbm_limitations(snac,hServerConn,seqno);
+ snac_message_accepted(snac);
+ snac_received_message(snac,hServerConn,seqno);
+ snac_typing_notification(snac);
+ snac_error(snac);
+ snac_file_decline(snac);
+ }
+ else if(snac.cmp(0x000A))
+ {
+ snac_email_search_results(snac);
+ /*
+ If there's no match (error 0x14), AIM will pop up a message.
+ Since it's annoying and there's no other errors that'll get
+ generated, I just assume leave this commented out. It's here
+ for consistency.
+ */
+ //snac_error(snac);
+ }
+ else if(snac.cmp(0x0013))
+ {
+ snac_contact_list(snac,hServerConn,seqno);
+ snac_list_modification_ack(snac);
+ snac_error(snac);
+ }
+ }
+ else if(flap.cmp(0x04))
+ {
+ sendBroadcast(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
+ LOG("Connection Negotiation Thread Ending: Flap 0x04");
+ goto exit;
+ }
+ }
+ }
+ }
+
+exit:
+ if (m_iStatus!=ID_STATUS_OFFLINE) broadcast_status(ID_STATUS_OFFLINE);
+ Netlib_CloseHandle(hServerPacketRecver); hServerPacketRecver=NULL;
+ Netlib_CloseHandle(hServerConn); hServerConn=NULL;
+ LOG("Connection Negotiation Thread Ending: End of Thread");
+ offline_contacts();
+}
+
+void __cdecl CAimProto::aim_mail_negotiation( void* )
+{
+ HANDLE hServerPacketRecver = (HANDLE) CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hMailConn, 2048 * 8);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER*1000;
+ while(m_iStatus!=ID_STATUS_OFFLINE)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ {
+ break;
+ }
+ if (recvResult == SOCKET_ERROR)
+ {
+ if (WSAGetLastError() == ERROR_TIMEOUT)
+ {
+ if (aim_keepalive(hMailConn, mail_seqno) < 0)
+ break;
+ }
+ else
+ break;
+ }
+ if(recvResult>0)
+ {
+ unsigned short flap_length=0;
+ for (;packetRecv.bytesUsed<packetRecv.bytesAvailable;packetRecv.bytesUsed=flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
+ if (!flap.len())
+ break;
+ flap_length+=FLAP_SIZE+flap.len();
+ if(flap.cmp(0x01))
+ {
+ aim_send_cookie(hMailConn,mail_seqno,MAIL_COOKIE_LENGTH,MAIL_COOKIE);//cookie challenge
+ mir_free(MAIL_COOKIE);
+ MAIL_COOKIE=NULL;
+ MAIL_COOKIE_LENGTH=0;
+ }
+ else if (flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(),flap.snaclen());
+ if (snac.cmp(0x0001))
+ {
+ snac_supported_families(snac,hMailConn,mail_seqno);
+ snac_supported_family_versions(snac,hMailConn,mail_seqno);
+ snac_mail_rate_limitations(snac,hMailConn,mail_seqno);
+ snac_error(snac);
+ }
+ else if (snac.cmp(0x0018))
+ {
+ snac_mail_response(snac);
+ }
+ }
+ else if(flap.cmp(0x04))
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ LOG("Mail Server Connection has ended");
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(hMailConn);
+ hMailConn=NULL;
+}
+
+void __cdecl CAimProto::aim_avatar_negotiation( void* )
+{
+ HANDLE hServerPacketRecver = (HANDLE) CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hAvatarConn, 2048 * 8);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = 300000;//5 minutes connected
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM) & packetRecv);
+ if (recvResult == 0)
+ break;
+
+ if (recvResult == SOCKET_ERROR)
+ break;
+
+ if (recvResult > 0)
+ {
+ unsigned short flap_length=0;
+ for (; packetRecv.bytesUsed < packetRecv.bytesAvailable; packetRecv.bytesUsed = flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
+ if (!flap.len())
+ break;
+ flap_length += FLAP_SIZE + flap.len();
+ if(flap.cmp(0x01))
+ {
+ aim_send_cookie(hAvatarConn, avatar_seqno, AVATAR_COOKIE_LENGTH, AVATAR_COOKIE);//cookie challenge
+ mir_free(AVATAR_COOKIE);
+ AVATAR_COOKIE = NULL;
+ AVATAR_COOKIE_LENGTH = 0;
+ }
+ else if(flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(), flap.snaclen());
+ if (snac.cmp(0x0001))
+ {
+ snac_supported_families(snac, hAvatarConn, avatar_seqno);
+ snac_supported_family_versions(snac, hAvatarConn, avatar_seqno);
+ snac_avatar_rate_limitations(snac, hAvatarConn, avatar_seqno);
+ snac_error(snac);
+ }
+ if (snac.cmp(0x0010))
+ {
+ snac_retrieve_avatar(snac);
+ snac_upload_reply_avatar(snac);
+ }
+ }
+ else if (flap.cmp(0x04))
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(hAvatarConn);
+ hAvatarConn=NULL;
+ ResetEvent(hAvatarEvent);
+ LOG("Avatar Server Connection has ended");
+}
+
+void __cdecl CAimProto::aim_chatnav_negotiation( void* )
+{
+ unsigned idle_chat = 0;
+ HANDLE hServerPacketRecver = (HANDLE) CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hChatNavConn, 2048 * 8);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER*1000;
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ break;
+
+ if (recvResult == SOCKET_ERROR)
+ {
+ if (WSAGetLastError() == ERROR_TIMEOUT)
+ {
+ if (chat_rooms.getCount())
+ idle_chat = 0;
+ else if (++idle_chat >= 6)
+ break;
+
+ if (aim_keepalive(hChatNavConn, chatnav_seqno) < 0)
+ break;
+ }
+ else
+ break;
+ }
+
+ if(recvResult>0)
+ {
+ unsigned short flap_length=0;
+ for (;packetRecv.bytesUsed<packetRecv.bytesAvailable;packetRecv.bytesUsed=flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
+ if (!flap.len())
+ break;
+ flap_length+=FLAP_SIZE+flap.len();
+ if(flap.cmp(0x01))
+ {
+ aim_send_cookie(hChatNavConn,chatnav_seqno,CHATNAV_COOKIE_LENGTH,CHATNAV_COOKIE);//cookie challenge
+ mir_free(CHATNAV_COOKIE);
+ CHATNAV_COOKIE=NULL;
+ CHATNAV_COOKIE_LENGTH=0;
+ }
+ else if(flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(),flap.snaclen());
+ if(snac.cmp(0x0001))
+ {
+ snac_supported_families(snac,hChatNavConn,chatnav_seqno);
+ snac_supported_family_versions(snac,hChatNavConn,chatnav_seqno);
+ snac_chatnav_rate_limitations(snac,hChatNavConn,chatnav_seqno);
+ snac_error(snac);
+ }
+ if(snac.cmp(0x000D))
+ {
+ snac_chatnav_info_response(snac,hChatNavConn,chatnav_seqno);
+ snac_error(snac);
+ }
+ }
+ else if(flap.cmp(0x04))
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(hChatNavConn);
+ hChatNavConn=NULL;
+ ResetEvent(hChatNavEvent);
+ LOG("Chat Navigation Server Connection has ended");
+}
+
+void __cdecl CAimProto::aim_chat_negotiation( void* param )
+{
+ chat_list_item *item = (chat_list_item*)param;
+ HANDLE hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)item->hconn, 2048 * 8);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = DEFAULT_KEEPALIVE_TIMER*1000;
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ break;
+
+ if (recvResult == SOCKET_ERROR)
+ {
+ if (WSAGetLastError() == ERROR_TIMEOUT)
+ {
+ if (aim_keepalive(item->hconn, item->seqno) < 0)
+ break;
+ }
+ else
+ break;
+ }
+
+ if(recvResult>0)
+ {
+ unsigned short flap_length=0;
+ for (;packetRecv.bytesUsed<packetRecv.bytesAvailable;packetRecv.bytesUsed=flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
+ if (!flap.len())
+ break;
+ flap_length+=FLAP_SIZE+flap.len();
+ if(flap.cmp(0x01))
+ {
+ aim_send_cookie(item->hconn,item->seqno,item->CHAT_COOKIE_LENGTH,item->CHAT_COOKIE);//cookie challenge
+ mir_free(item->CHAT_COOKIE);
+ item->CHAT_COOKIE=NULL;
+ item->CHAT_COOKIE_LENGTH=0;
+ }
+ else if(flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(),flap.snaclen());
+ if(snac.cmp(0x0001))
+ {
+ snac_supported_families(snac,item->hconn,item->seqno);
+ snac_supported_family_versions(snac,item->hconn,item->seqno);
+ snac_chat_rate_limitations(snac,item->hconn,item->seqno);
+ snac_error(snac);
+
+ }
+ if(snac.cmp(0x000E))
+ {
+ snac_chat_received_message(snac, item);
+ snac_chat_joined_left_users(snac, item);
+ snac_error(snac);
+ }
+ }
+ else if(flap.cmp(0x04))
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(item->hconn);
+ chat_leave(item->id);
+ remove_chat_by_ptr(item);
+ LOG("Chat Server Connection has ended");
+}
+
+void __cdecl CAimProto::aim_admin_negotiation( void* )
+{
+ HANDLE hServerPacketRecver = (HANDLE)CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)hAdminConn, 2048 * 8);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = 300000;//5 minutes connected
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM) hServerPacketRecver, (LPARAM) & packetRecv);
+ if (recvResult == 0)
+ break;
+
+ if (recvResult == SOCKET_ERROR)
+ break;
+
+ if(recvResult>0)
+ {
+ unsigned short flap_length=0;
+ for (;packetRecv.bytesUsed<packetRecv.bytesAvailable;packetRecv.bytesUsed=flap_length)
+ {
+ if (!packetRecv.buffer)
+ break;
+ FLAP flap((char*)&packetRecv.buffer[packetRecv.bytesUsed],packetRecv.bytesAvailable-packetRecv.bytesUsed);
+ if (!flap.len())
+ break;
+ flap_length+=FLAP_SIZE+flap.len();
+ if(flap.cmp(0x01))
+ {
+ aim_send_cookie(hAdminConn,admin_seqno,ADMIN_COOKIE_LENGTH,ADMIN_COOKIE);//cookie challenge
+ mir_free(ADMIN_COOKIE);
+ ADMIN_COOKIE=NULL;
+ ADMIN_COOKIE_LENGTH=0;
+ }
+ else if(flap.cmp(0x02))
+ {
+ SNAC snac(flap.val(),flap.snaclen());
+ if(snac.cmp(0x0001))
+ {
+ snac_supported_families(snac,hAdminConn,admin_seqno);
+ snac_supported_family_versions(snac,hAdminConn,admin_seqno);
+ snac_admin_rate_limitations(snac,hAdminConn,admin_seqno);
+ snac_error(snac);
+ }
+ if(snac.cmp(0x0007))
+ {
+ snac_admin_account_infomod(snac);
+ snac_admin_account_confirm(snac);
+ snac_error(snac);
+ }
+ }
+ else if(flap.cmp(0x04))
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(hAdminConn);
+ hAdminConn=NULL;
+ ResetEvent(hAdminEvent);
+ LOG("Admin Server Connection has ended");
+}
diff --git a/protocols/AimOscar/src/conv.cpp b/protocols/AimOscar/src/conv.cpp
new file mode 100644
index 0000000000..ebe531876f
--- /dev/null
+++ b/protocols/AimOscar/src/conv.cpp
@@ -0,0 +1,900 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "conv.h"
+
+#ifdef _MSC_VER
+ #pragma warning( disable: 4706 )
+#endif
+
+char* process_status_msg (const char *str, const char* sn)
+{
+ const char *src = str;
+ size_t size = strlen(src) + 1;
+ char* res = (char*)mir_alloc(size);
+ char* dest = res;
+
+ for (; *src; ++src)
+ {
+ if (src[0] == '\n' && (src == str || src[-1] != '\r'))
+ {
+ int off = dest - res;
+ res = (char*)mir_realloc(res, ++size);
+ dest = res + off;
+ *(dest++) = '\r';
+ *(dest++) = *src;
+ }
+ else if (src[0] == '%' && src[1] == 'n')
+ {
+ size_t len = strlen(sn);
+ int off = dest - res;
+ res = (char*)mir_realloc(res, size + len);
+ dest = res + off;
+ size += len;
+ memcpy(dest, sn, len);
+ dest += len;
+ ++src;
+ }
+ else if (src[0] == '%' && src[1] == 'd')
+ {
+ int off = dest - res;
+ res = (char*)mir_realloc(res, size + 20);
+ dest = res + off;
+ size += 20;
+ dest += GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, dest, 20)-1;
+ ++src;
+ }
+ else if (src[0] == '%' && src[1] == 't')
+ {
+ int off = dest - res;
+ res = (char*)mir_realloc(res, size + 20);
+ dest = res + off;
+ size += 20;
+ dest += GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, dest, 20)-1;
+ ++src;
+ }
+ else
+ *(dest++) = *src;
+ }
+ *dest = '\0';
+ return res;
+}
+
+
+void html_decode(char* str)
+{
+ char *p, *q;
+// char *rstr = (char*)mir_alloc(strlen(str)*2);
+
+ if (str == NULL) return;
+
+ for ( p=q=str; *p!='\0'; p++,q++ )
+ {
+ if ( *p == '&' )
+ {
+ if ( !strnicmp( p, "&amp;", 5 )) { *q = '&'; p += 4; }
+ else if ( !strnicmp( p, "&apos;", 6 )) { *q = '\''; p += 5; }
+ else if ( !strnicmp( p, "&gt;", 4 )) { *q = '>'; p += 3; }
+ else if ( !strnicmp( p, "&lt;", 4 )) { *q = '<'; p += 3; }
+ else if ( !strnicmp( p, "&quot;", 6 )) { *q = '"'; p += 5; }
+ else if ( *(p+1) == '#' )
+ {
+ char* s = strchr(p, ';');
+ if (s)
+ {
+ *q = (char)atoi(p+2);
+ p = s;
+ }
+ else
+ *q = *p;
+ }
+ else { *q = *p; }
+ }
+ else if ( *p == '<' )
+ {
+ if ( !strnicmp( p, "<p>", 3 )) { strcpy(q, "\r\n\r\n"); q += 3; p += 2; }
+ else if ( !strnicmp( p, "</p>", 4 )) { strcpy(q, "\r\n\r\n"); q += 3; p += 3; }
+ else if ( !strnicmp( p, "<br>", 4 )) { strcpy(q, "\r\n"); ++q; p += 3; }
+ else if ( !strnicmp( p, "<br />", 6 )) { strcpy(q, "\r\n"); ++q; p += 5; }
+ else if ( !strnicmp( p, "<hr>", 4 )) { strcpy(q, "\r\n"); ++q; p += 3; }
+ else if ( !strnicmp( p, "<hr />", 6 )) { strcpy(q, "\r\n"); ++q; p += 5; }
+/*
+ else if ( !strnicmp( p, "<b>", 3 )) { strcpy(q, "[b]"); q += 2; p += 2; }
+ else if ( !strnicmp( p, "</b>", 4 )) { strcpy(q, "[/b]"); q += 3; p += 3; }
+ else if ( !strnicmp( p, "<u>", 3 )) { strcpy(q, "[u]"); q += 2; p += 2; }
+ else if ( !strnicmp( p, "</u>", 4 )) { strcpy(q, "[/u]"); q += 3; p += 3; }
+ else if ( !strnicmp( p, "<i>", 3 )) { strcpy(q, "[i]"); q += 2; p += 2; }
+ else if ( !strnicmp( p, "</i>", 4 )) { strcpy(q, "[/i]"); q += 3; p += 3; }
+ else if ( !strnicmp( p, "<s>", 3 )) { strcpy(q, "[s]"); q += 2; p += 2; }
+ else if ( !strnicmp( p, "</s>", 4 )) { strcpy(q, "[/s]"); q += 3; p += 3; }
+ else if ( !strnicmp( p, "<a href", 7 )) {
+ strcpy(q, "[url"); q += 4; p += 7;
+ while (*p != '>' && *p) *(q++) = *(p++);
+ *q = ']'; --p;
+ }
+ else if ( !strnicmp( p, "<font", 5 )) {
+ char *l = strchr(p, '>');
+
+ strcpy(q, "[url"); q += 4; p += 7;
+ while (*p != '>' && *p) *(q++) = *(p++);
+ *q = ']'; --p;
+ }
+*/
+ else {
+ char *l = strchr(p, '>');
+ if (l) { p = l; --q; } else *q = *p;
+ }
+ }
+ else
+ *q = *p;
+ }
+ *q = '\0';
+}
+
+
+char* html_encode(const char* str)
+{
+ char* s, *q;
+ const char *p;
+ int c;
+
+ if (str == NULL) return NULL;
+
+ for ( c=0, p=str; *p!='\0'; p++ )
+ {
+ switch ( *p )
+ {
+ case '&' : c += 5; break;
+ case '\'': c += 6; break;
+ case '>' : c += 4; break;
+ case '<' : c += 4; break;
+ case '"' : c += 6; break;
+ case '\n': c += 4; break;
+ default: c++; break;
+ }
+ }
+
+ s = (char*)mir_alloc(c + 27);
+ strcpy(s, "<HTML><BODY>");
+ for ( p=str,q=s+12; *p!='\0'; p++ )
+ {
+ switch ( *p )
+ {
+ case '&' : memcpy( q, "&amp;", 5 ); q += 5; break;
+// case '\'': memcpy( q, "&apos;", 6 ); q += 6; break;
+ case '>' : memcpy( q, "&gt;", 4 ); q += 4; break;
+ case '<' : memcpy( q, "&lt;", 4 ); q += 4; break;
+ case '"' : memcpy( q, "&quot;", 6 ); q += 6; break;
+ case '\r': break;
+ case '\n': memcpy( q, "<BR>", 4 ); q += 4; break;
+ default: *q = *p; ++q; break;
+ }
+ }
+ strcpy(q, "</BODY></HTML>");
+
+ return s;
+}
+
+char* html_to_bbcodes(char *src)
+{
+ char *ptr;
+ char *ptrl;
+ char *rptr;
+ char* dest = mir_strdup(src);
+ while ((ptr = strstr(dest, "<B>")) != NULL || (ptr = strstr(dest, "<b>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+1) = 'b';
+ *(ptr+2) = ']';
+ if ((ptr = strstr(dest, "</B>")) != NULL || (ptr = strstr(dest, "</b>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+2) = 'b';
+ *(ptr+3) = ']';
+ }
+ else
+ {
+ dest=(char*)mir_realloc(dest,strlen(dest)+6);
+ memcpy(&dest[strlen(dest)],"[/b]",5);
+ }
+ }
+ while ((ptr = strstr(dest, "<I>")) != NULL || (ptr = strstr(dest, "<i>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+1) = 'i';
+ *(ptr+2) = ']';
+ if ((ptr = strstr(dest, "</I>")) != NULL || (ptr = strstr(dest, "</i>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+2) = 'i';
+ *(ptr+3) = ']';
+ }
+ else
+ {
+ dest=(char*)mir_realloc(dest,strlen(dest)+6);
+ memcpy(&dest[strlen(dest)],"[/i]",5);
+ }
+ }
+ while ((ptr = strstr(dest, "<U>")) != NULL || (ptr = strstr(dest, "<u>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+1) = 'u';
+ *(ptr+2) = ']';
+ if ((ptr = strstr(dest, "</U>")) != NULL || (ptr = strstr(dest, "</u>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+2) = 'u';
+ *(ptr+3) = ']';
+ }
+ else
+ {
+ dest=(char*)mir_realloc(dest,strlen(dest)+6);
+ memcpy(&dest[strlen(dest)],"[/u]",5);
+ }
+ }
+ while ((ptr = strstr(dest, "<S>")) != NULL || (ptr = strstr(dest, "<s>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+1) = 's';
+ *(ptr+2) = ']';
+ if ((ptr = strstr(dest, "</S>")) != NULL || (ptr = strstr(dest, "</s>")) != NULL)
+ {
+ *ptr = '[';
+ *(ptr+2) = 's';
+ *(ptr+3) = ']';
+ }
+ else
+ {
+ dest=(char*)mir_realloc(dest,strlen(dest)+6);
+ memcpy(&dest[strlen(dest)],"[/s]",5);
+ }
+ }
+ rptr = dest;
+ while (ptr = strstr(rptr,"<A HREF"))
+ {
+ char* begin=ptr;
+ ptrl = ptr + 4;
+ memcpy(ptrl,"[url=",5);
+ memmove(ptr, ptrl, strlen(ptrl) + 1);
+ if ((ptr = strstr(ptrl,">")))
+ {
+ ptr-=1;
+ memmove(ptr, ptr+1, strlen(ptr+1) + 1);
+ *(ptr)=']';
+ ptrl-=1;
+ char* s1 = strstr(ptrl,"</A");
+ char* s2 = strstr(rptr,"<A HREF");
+ if (s1&&s1<s2||s1&&!s2)
+ {
+ ptr=s1;
+ ptr=strip_tag_within(begin,ptr);
+ memmove(ptr+2, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/url]",6);
+ }
+ else if(s2&&s2<s1||s2&&!s1)
+ {
+ ptr=s2;
+ ptr=strip_tag_within(begin,ptr);
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ memmove(ptr+6, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/url]",6);
+ }
+ else
+ {
+ strip_tag_within(begin,&dest[strlen(dest)]);
+ //int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=dest;
+ memcpy(&ptr[strlen(ptr)],"[/url]",7);
+ }
+ }
+ else
+ rptr++;
+ }
+ rptr = dest;
+ while (ptr = strstr(rptr,"<a href"))
+ {
+ char* begin=ptr;
+ ptrl = ptr + 4;
+ memcpy(ptrl,"[url=",5);
+ memmove(ptr, ptrl, strlen(ptrl) + 1);
+ if ((ptr = strstr(ptrl,">")))
+ {
+ ptr-=1;
+ memmove(ptr, ptr+1, strlen(ptr+1) + 1);
+ *(ptr)=']';
+ ptrl-=1;
+ char* s1 = strstr(ptrl,"</a");
+ char* s2 = strstr(ptrl,"<a href");
+ if (s1&&s1<s2||s1&&!s2)
+ {
+ ptr=s1;
+ ptr=strip_tag_within(begin,ptr);
+ memmove(ptr+2, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/url]",6);
+ }
+ else if(s2&&s2<s1||s2&&!s1)
+ {
+ ptr=s2;
+ ptr=strip_tag_within(begin,ptr);
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ memmove(ptr+6, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/url]",6);
+ }
+ else
+ {
+ strip_tag_within(begin,&dest[strlen(dest)]);
+ //int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=dest;
+ memcpy(&ptr[strlen(ptr)],"[/url]",7);
+ }
+ }
+ else
+ rptr++;
+ }
+ rptr = dest;
+ while (ptr = strstr(rptr, "<FONT COLOR=\""))
+ {
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ ptrl = ptr + 6;
+ memcpy(ptrl,"[color=",7);
+ memmove(ptr, ptrl, strlen(ptrl) + 1);
+ if ((ptr = strstr(ptrl, ">")))
+ {
+ memmove(ptrl+7,ptr,strlen(ptr)+1);
+ *(ptrl+7)=']';
+ ptr=ptrl+7;
+ char* s1 = strstr(ptr,"</FONT");
+ char* s2 = strstr(ptr,"<FONT COLOR=\"");
+ if (s1&&s1<s2||s1&&!s2)
+ {
+ ptr=s1;
+ memmove(ptr+1, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/color]",8);
+ }
+ else if(s2&&s2<s1||s2&&!s1)
+ {
+ ptr=s2;
+ memmove(ptr+8, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/color]",8);
+ }
+ else
+ {
+ ptr=dest;
+ memcpy(&ptr[strlen(ptr)],"[/color]",9);
+ }
+ }
+ else
+ rptr++;
+ }
+ rptr = dest;
+ while (ptr = strstr(rptr, "<font color=\""))
+ {
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ ptrl = ptr + 6;
+ memcpy(ptrl,"[color=",7);
+ memmove(ptr, ptrl, strlen(ptrl) + 1);
+ if ((ptr = strstr(ptrl, ">")))
+ {
+ memmove(ptrl+7,ptr,strlen(ptr)+1);
+ *(ptrl+7)=']';
+ ptr=ptrl+7;
+ char* s1 = strstr(ptr,"</font");
+ char* s2 = strstr(ptr,"<font color=\"");
+ if (s1&&s1<s2||s1&&!s2)
+ {
+ ptr=s1;
+ memmove(ptr+1, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/color]",8);
+ }
+ else if(s2&&s2<s1||s2&&!s1)
+ {
+ ptr=s2;
+ memmove(ptr+8, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"[/color]",8);
+ }
+ else
+ {
+ ptr=dest;
+ memcpy(&ptr[strlen(ptr)],"[/color]",9);
+ }
+ }
+ else
+ rptr++;
+ }
+ rptr = dest;
+ while ((ptr = strstr(rptr, "<FONT COLOR=")) || (ptr = strstr(rptr, "<font color=")))
+ {
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ ptrl = ptr + 5;
+ memcpy(ptrl,"[color=",7);
+ memmove(ptr, ptrl, strlen(ptrl) + 1);
+ if ((ptr = strstr(ptrl, ">")))
+ {
+ *(ptr)=']';
+ if ((ptrl = strstr(ptr, "</FONT")) || (ptrl = strstr(ptr, "</font")))
+ {
+ memmove(ptrl+1, ptrl, strlen(ptrl) + 1);
+ memcpy(ptrl,"[/color]",8);
+ }
+ else
+ {
+ memcpy(&dest[strlen(dest)],"[/color]",9);
+ }
+ }
+ else
+ rptr++;
+ }
+/*
+ rptr = dest;
+ while ((ptr = strstr(rptr, "aim:")) || (ptr = strstr(rptr, "AIM:")))
+ {
+ int addr=ptr-rptr;
+ int len=0;
+ for (len
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ ptrl = ptr + 5;
+ memcpy(ptrl,"[url=",7);
+ memmove(ptr, ptrl, strlen(ptrl) + 1);
+ }
+*/
+ return dest;
+}
+
+char* bbcodes_to_html(const char *src)
+{
+ char *ptr;
+ char *rptr;
+ char* dest = mir_strdup(src);
+ while ((ptr = strstr(dest, "[b]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+1) = 'b';
+ *(ptr+2) = '>';
+ }
+ while ((ptr = strstr(dest, "[/b]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+2) = 'b';
+ *(ptr+3) = '>';
+ }
+ while ((ptr = strstr(dest, "[i]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+1) = 'i';
+ *(ptr+2) = '>';
+ }
+ while ((ptr = strstr(dest, "[/i]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+2) = 'i';
+ *(ptr+3) = '>';
+ }
+ while ((ptr = strstr(dest, "[u]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+1) = 'u';
+ *(ptr+2) = '>';
+ }
+ while ((ptr = strstr(dest, "[/u]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+2) = 'u';
+ *(ptr+3) = '>';
+ }
+ while ((ptr = strstr(dest, "[s]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+1) = 's';
+ *(ptr+2) = '>';
+ }
+ while ((ptr = strstr(dest, "[/s]")) != NULL)
+ {
+ *ptr = '<';
+ *(ptr+2) = 's';
+ *(ptr+3) = '>';
+ }
+ rptr = dest;
+ while ((ptr = strstr(rptr, "[color=")))
+ {
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ memmove(ptr+5, ptr, strlen(ptr) + 1);
+ memcpy(ptr,"<font ",6);
+ if ((ptr = strstr(ptr,"]")))
+ {
+ *(ptr)='>';
+ if ((ptr = strstr(ptr,"[/color]")))
+ {
+ memcpy(ptr,"</font>",7);
+ memmove(ptr+7,ptr+8,strlen(ptr+8)+1);
+ }
+ }
+ else
+ rptr++;
+ }
+ while ((ptr = strstr(rptr, "[url=")))
+ {
+ int addr=ptr-rptr;
+ dest=(char*)mir_realloc(dest,strlen(dest)+8);
+ rptr=dest;
+ ptr=rptr+addr;
+ memmove(ptr+3, ptr, strlen(ptr)+1);
+ memcpy(ptr,"<a href",7);
+ if ((ptr = strstr(ptr, "]")))
+ {
+ *(ptr)='>';
+ if ((ptr = strstr(ptr, "[/url]")))
+ {
+ memcpy(ptr,"</a>",4);
+ memmove(ptr+4,ptr+6,strlen(ptr+6)+1);
+ }
+ }
+ else
+ rptr++;
+ }
+ return dest;
+}
+
+void strip_tag(char* begin, char* end)
+{
+ memmove(begin,end+1,strlen(end+1)+1);
+}
+
+//strip a tag within a string
+char* strip_tag_within(char* begin, char* end)
+{
+ while(char* sub_begin=strchr(begin,'<'))
+ {
+ if(sub_begin<end)//less than the original ending
+ {
+ char* sub_end=strchr(begin,'>');
+ strip_tag(sub_begin,sub_end);
+ end=end-(sub_end-sub_begin)-1;
+ }
+ else
+ break;
+ }
+ return end;
+}
+
+char* rtf_to_html(HWND hwndDlg,int DlgItem)
+{
+ char* buf=(char*)mir_alloc(4024);
+ size_t pos=0;
+ int start=0;
+ int end=1;
+ BOOL Bold=false;
+ BOOL Italic=false;
+ BOOL Underline=false;
+ char Face[32]="";
+ COLORREF Color;
+ COLORREF BackColor;
+ int Size=0;
+ GETTEXTLENGTHEX tl;
+ tl.flags=GTL_DEFAULT;
+ tl.codepage=CP_ACP;
+
+ int oldstart = 0, oldend = 0;
+ SendDlgItemMessage(hwndDlg, DlgItem, EM_GETSEL, (WPARAM)&oldstart, (LPARAM)&oldend);
+
+ int length=SendDlgItemMessage(hwndDlg, DlgItem, EM_GETTEXTLENGTHEX,(WPARAM)&tl,0);
+ while(start<length)
+ {
+ SendDlgItemMessage(hwndDlg, DlgItem, EM_SETSEL, start, end);
+ CHARFORMAT2A cfOld;
+ cfOld.cbSize = sizeof(cfOld);
+ cfOld.dwMask = CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_SIZE|CFM_COLOR|CFM_BACKCOLOR|CFM_FACE;
+ SendDlgItemMessageA(hwndDlg, DlgItem, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
+ BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
+ BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
+ COLORREF isColor=cfOld.crTextColor;
+ COLORREF isBackColor=cfOld.crBackColor;
+ int isSize;
+ if(cfOld.yHeight==38*20)
+ isSize=7;
+ else if(cfOld.yHeight==24*20)
+ isSize=6;
+ else if(cfOld.yHeight==18*20)
+ isSize=5;
+ else if(cfOld.yHeight==14*20)
+ isSize=4;
+ else if(cfOld.yHeight==12*20)
+ isSize=3;
+ else if(cfOld.yHeight==10*20)
+ isSize=2;
+ else if(cfOld.yHeight==8*20)
+ isSize=1;
+ else
+ isSize=3;
+ TCHAR text[3] =_T("");
+ SendDlgItemMessage(hwndDlg, DlgItem, EM_GETSELTEXT, 0, (LPARAM)&text);
+ if(Bold!=isBold)
+ {
+ Bold=isBold;
+ if(isBold)
+ {
+ strcpy(&buf[pos],"<b>");
+ pos+=3;
+ }
+ else
+ {
+ if(start!=0)
+ {
+ strcpy(&buf[pos],"</b>");
+ pos+=4;
+ }
+ }
+ }
+ if(Italic!=isItalic)
+ {
+ Italic=isItalic;
+ if(isItalic)
+ {
+ strcpy(&buf[pos],"<i>");
+ pos+=3;
+ }
+ else
+ {
+ if(start!=0)
+ {
+ strcpy(&buf[pos],"</i>");
+ pos+=4;
+ }
+ }
+ }
+ if(Underline!=isUnderline)
+ {
+ Underline=isUnderline;
+ if(isUnderline)
+ {
+ strcpy(&buf[pos],"<u>");
+ pos+=3;
+ }
+ else
+ {
+ if(start!=0)
+ {
+ strcpy(&buf[pos],"</u>");
+ pos+=4;
+ }
+ }
+ }
+ if ( Size != isSize || Color != isColor || BackColor != isBackColor || lstrcmpA( Face, cfOld.szFaceName ))
+ {
+ Size=isSize;
+ Color=isColor;
+ BackColor=isBackColor;
+ strcpy(Face,cfOld.szFaceName);
+ if(start!=0)
+ {
+ strcpy(&buf[pos],"</font>");
+ pos+=7;
+ }
+ strcpy(&buf[pos],"<font");
+ pos+=5;
+ strcpy(&buf[pos]," face=\"");
+ pos+=7;
+ strcpy(&buf[pos],Face);
+ pos+=strlen(Face);
+ strcpy(&buf[pos],"\"");
+ pos++;
+ if (!(cfOld.dwEffects & CFE_AUTOBACKCOLOR))
+ {
+ strcpy(&buf[pos]," back=#");
+ pos+=6;
+ char chBackColor[7];
+ _itoa((_htonl(BackColor)>>8),chBackColor,16);
+ size_t len=strlen(chBackColor);
+ if(len<6)
+ {
+ memmove(chBackColor+(6-len),chBackColor,len+1);
+ for(int i=0;i<6;i++)
+ chBackColor[i]='0';
+ }
+ strcpy(&buf[pos],chBackColor);
+ pos+=6;
+ }
+ if (!(cfOld.dwEffects & CFE_AUTOCOLOR))
+ {
+ strcpy(&buf[pos]," color=#");
+ pos+=8;
+ char chColor[7];
+ _itoa((_htonl(Color)>>8),chColor,16);
+ size_t len=strlen(chColor);
+ if(len<6)
+ {
+ memmove(chColor+(6-len),chColor,len+1);
+ for(int i=0;i<6;i++)
+ chColor[i]='0';
+ }
+ strcpy(&buf[pos],chColor);
+ pos+=6;
+ }
+ strcpy(&buf[pos]," size=");
+ pos+=6;
+ char chSize[2];
+ _itoa(Size,chSize,10);
+ strcpy(&buf[pos],chSize);
+ pos++;
+
+ strcpy(&buf[pos],">");
+ pos++;
+ }
+ if(text[0]=='\r')
+ {
+ strcpy(&buf[pos],"<br>");
+ pos+=4;
+ }
+ else
+ {
+ char* txt = mir_utf8encodeT(text);
+ strcpy(&buf[pos], txt);
+ pos += strlen(txt);
+ mir_free(txt);
+ }
+ start++;
+ end++;
+ }
+ if(Bold)
+ {
+ strcpy(&buf[pos],"</b>");
+ pos+=4;
+ }
+ if(Italic)
+ {
+ strcpy(&buf[pos],"</i>");
+ pos+=4;
+ }
+ if(Underline)
+ {
+ strcpy(&buf[pos],"</u>");
+ pos+=4;
+ }
+ strcpy(&buf[pos],"</font>");
+ pos+=7;
+
+ SendDlgItemMessage(hwndDlg, DlgItem, EM_SETSEL, oldstart, oldend);
+
+ return buf;
+}
+
+void wcs_htons(wchar_t * ch)
+{
+ if (ch == NULL) return;
+ for(size_t i=0;i<wcslen(ch);i++)
+ ch[i]=_htons(ch[i]);
+}
+
+char* bytes_to_string(char* bytes, int num_bytes)
+{
+ if (num_bytes == 0) return NULL;
+
+ char* string = (char*)mir_alloc(num_bytes*2+1);
+ for(int i=0;i<num_bytes;i++)
+ {
+ char store[2];
+ unsigned char bit=(bytes[i]&0xF0)>>4;
+ _itoa(bit,store,16);
+ memcpy(&string[i*2],store,1);
+ bit=(bytes[i]&0x0F);
+ _itoa(bit,store,16);
+ memcpy(&string[i*2+1],store,1);
+ }
+ string[num_bytes*2]='\0';
+ return string;
+}
+
+void string_to_bytes(char* string, char* bytes)
+{
+ char sbyte[3];
+ sbyte[2]='\0';
+ size_t length=strlen(string);
+ for (size_t i=0; i<length; i+=2)
+ {
+ sbyte[0]=string[i];
+ sbyte[1]=string[i+1];
+ bytes[i/2]=(char)strtol(sbyte,NULL,16);
+ }
+}
+
+bool is_utf(const char* msg)
+{
+ bool res = false;
+ if (msg)
+ {
+ for (unsigned i=0; !res; ++i)
+ {
+ char c = msg[i];
+ if (c == 0) break;
+ res = (c & 0x80) != 0;
+ }
+ }
+ return res;
+}
+
+char* get_fname(char* path)
+{
+ char* pszFile = strrchr(path, '\\');
+ if (pszFile) pszFile++; else pszFile = path;
+
+ return pszFile;
+}
+
+TCHAR* get_dir(TCHAR* path)
+{
+ TCHAR *cpath = mir_tstrdup(path);
+
+ TCHAR* swd = _tcsrchr(cpath, '\\');
+ if (swd) swd[1] = 0; else cpath[0] = 0;
+
+ return cpath;
+}
+
+aimString::aimString(char* str)
+{
+ if (str == NULL)
+ {
+ szString = NULL;
+ size = 0;
+ unicode = false;
+ }
+ else
+ {
+ unicode = is_utf(str);
+ if (unicode)
+ {
+ wszString = mir_utf8decodeW(str);
+ wcs_htons(wszString);
+ size = wcslen(wszString) * sizeof(wchar_t);
+ }
+ else
+ {
+ szString = mir_utf8decodeA(str);
+ size = strlen(szString);
+ }
+ }
+}
+
+#ifdef _MSC_VER
+ #pragma warning( default: 4706 )
+#endif
diff --git a/protocols/AimOscar/src/conv.h b/protocols/AimOscar/src/conv.h
new file mode 100644
index 0000000000..b7490cf63e
--- /dev/null
+++ b/protocols/AimOscar/src/conv.h
@@ -0,0 +1,56 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef CONV_H
+#define CONV_H
+
+char* process_status_msg (const char *src, const char* sn);
+void html_decode(char* str);
+char* html_encode(const char *src);
+char* html_to_bbcodes(char *src);
+char* bbcodes_to_html(const char *src);
+void strip_tag(char* begin, char* end);
+char* strip_tag_within(char* begin, char* end);
+char* rtf_to_html(HWND hwndDlg,int DlgItem);
+void wcs_htons(wchar_t * ch);
+char* bytes_to_string(char* bytes, int num_bytes);
+void string_to_bytes(char* string, char* bytes);
+bool is_utf(const char* msg);
+char* get_fname(char* path);
+TCHAR* get_dir(TCHAR* path);
+
+struct aimString
+{
+ union
+ {
+ char* szString;
+ wchar_t* wszString;
+ };
+ size_t size;
+ bool unicode;
+
+ aimString(char* str);
+ ~aimString() { mir_free(szString); }
+
+ bool isUnicode(void) { return unicode; }
+ unsigned short getSize(void) { return (unsigned short)size; }
+ unsigned short getTermSize(void) { return (unsigned short)(size + (unicode ? sizeof(wchar_t) : sizeof(char))); }
+ char* getBuf(void) { return szString; }
+};
+
+#endif
diff --git a/protocols/AimOscar/src/defines.h b/protocols/AimOscar/src/defines.h
new file mode 100644
index 0000000000..95e756d119
--- /dev/null
+++ b/protocols/AimOscar/src/defines.h
@@ -0,0 +1,353 @@
+#ifndef DEFINES_H
+#define DEFINES_H
+#if defined __GNUC__
+#pragma GCC system_header
+#endif
+#define _CRT_SECURE_NO_DEPRECATE
+#pragma warning (disable : 4996)
+//System includes
+#include <windows.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+#include <process.h>
+#include <prsht.h>
+#include <richedit.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <vssym32.h>
+#include <winuser.h>
+//Miranda IM includes
+#pragma warning( disable: 4100 )
+#pragma warning( disable: 4244 )
+#pragma warning( disable: 4201 )
+#include <newpluginapi.h>
+#include <statusmodes.h>
+#include <m_button.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include "m_cluiframes.h"
+#include <m_database.h>
+#include <m_idle.h>
+#include <m_langpack.h>
+#include <m_message.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <statusmodes.h>
+#include <m_system.h>
+#include <m_userinfo.h>
+#include <m_addcontact.h>
+#include <m_icolib.h>
+#pragma warning( default: 4100 )
+#pragma warning( default: 4244 )
+#pragma warning( default: 4201 )
+//independent includes
+#include "strl.h"
+#include "flap.h"
+#include "snac.h"
+#include "tlv.h"
+//rest o includes
+#include "avatars.h"
+#include "away.h"
+#include "utility.h"
+#include "client.h"
+#include "connection.h"
+#include "conv.h"
+#include "direct_connect.h"
+#include "error.h"
+#include "file.h"
+#include "links.h"
+#include "packets.h"
+#include "popup.h"
+#include "proxy.h"
+#include "resource.h"
+#include "services.h"
+#include "server.h"
+#include "theme.h"
+#include "thread.h"
+#include "windows.h"
+//Packet Stuff
+#define MSG_LEN 4089
+//Extended Status Icon Numbers
+#define ACCOUNT_TYPE_UNCONFIRMED 1
+#define ACCOUNT_TYPE_CONFIRMED 2
+#define ACCOUNT_TYPE_ICQ 3
+#define ACCOUNT_TYPE_AOL 4
+#define ACCOUNT_TYPE_ADMIN 5
+#define EXTENDED_STATUS_BOT 1
+#define EXTENDED_STATUS_HIPTOP 2
+//Popup flags
+#define MAIL_POPUP 4
+//Main Option Window Keys
+#define AIM_KEY_SN "SN"
+#define AIM_KEY_NK "Nick"
+#define AIM_KEY_PW "Password"
+#define AIM_KEY_HN "hostname"
+#define AIM_KEY_DC "DelConf"//delivery confirmation
+#define AIM_KEY_FP "ForceProxyTransfer"
+#define AIM_KEY_GP "FileTransferGracePeriod"//in seconds default 60
+#define AIM_KEY_KA "KeepAlive"//in seconds default 60
+#define AIM_KEY_HF "HiptopFake"
+#define AIM_KEY_AT "DisableATIcons"
+#define AIM_KEY_ES "DisableESIcons"
+#define AIM_KEY_DM "DisableModeMsg"
+#define AIM_KEY_FI "FormatIncoming"//html->bbcodes
+#define AIM_KEY_FO "FormatOutgoing"//bbcodes->html
+#define AIM_KEY_FR "FirstRun"
+#define AIM_KEY_II "InstantIdle"
+#define AIM_KEY_IIT "InstantIdleTS"
+#define AIM_KEY_CM "CheckMail"
+#define AIM_KEY_DA "DisableAvatars"
+
+//Other plugin Option Keys
+#define OTH_KEY_AI "AwayIgnore"
+#define OTH_KEY_AD "AwayDefault"
+#define OTH_KEY_AM "AwayMsg"
+#define OTH_KEY_OI "OccupiedIgnore"
+#define OTH_KEY_OD "OccupiedDefault"
+#define OTH_KEY_OM "OccupiedMsg"
+#define OTH_KEY_NI "NaIgnore"
+#define OTH_KEY_ND "NaDefault"
+#define OTH_KEY_NM "NaMsg"
+#define OTH_KEY_DI "DndIgnore"
+#define OTH_KEY_DD "DndDefault"
+#define OTH_KEY_DM "DndMsg"
+#define OTH_KEY_PI "OtpIgnore"
+#define OTH_KEY_PD "OtpDefault"
+#define OTH_KEY_PM "OtpMsg"
+#define OTH_KEY_LI "OtlIgnore"
+#define OTH_KEY_LD "OtlDefault"
+#define OTH_KEY_LM "OtlMsg"
+
+#define OTH_KEY_SM "StatusMsg"
+#define OTH_KEY_GP "Group"
+//Module Name Key
+#define MOD_KEY_SA "SRAway"
+#define MOD_KEY_CL "CList"
+//Settings Keys
+#define AIM_KEY_PR "Profile"
+#define AIM_KEY_LA "LastAwayChange"
+#define AIM_MOD_IG "ID2Group"
+#define AIM_MOD_GI "Group2ID"
+#define AIM_KEY_AL "AIMLinks"// aim: links support
+//Contact Keys
+#define AIM_KEY_BI "BuddyId"
+#define AIM_KEY_GI "GroupId"
+#define AIM_KEY_ST "Status"
+#define AIM_KEY_IT "IdleTS"
+#define AIM_KEY_OT "LogonTS"
+#define AIM_KEY_AC "AccType"//account type
+#define AIM_KEY_ET "ESType"//Extended Status type
+#define AIM_KEY_MV "MirVer"
+#define AIM_KEY_US "Utf8Support"
+#define AIM_KEY_NL "NotOnList"
+#define AIM_KEY_LM "LastMessage"
+#define AIM_KEY_NC "NewContact"
+#define AIM_KEY_AH "AvatarHash"
+//File Transfer Keys
+#define AIM_KEY_FT "FileTransfer"//1= sending 0=receiving
+#define AIM_KEY_CK "Cookie"
+#define AIM_KEY_CK2 "Cookie2"
+#define AIM_KEY_FN "FileName"
+#define AIM_KEY_FS "FileSize"
+#define AIM_KEY_FD "FileDesc"
+#define AIM_KEY_IP "IP"
+#define AIM_KEY_PS "ProxyStage"
+#define AIM_KEY_PC "PortCheck"
+#define AIM_KEY_DH "DCHandle"
+//Old Keys
+#define OLD_KEY_PW "password"
+#define OLD_KEY_DM "AutoResponse"
+
+//Some Defaults for various things
+#define DEFAULT_KEEPALIVE_TIMER 60// 1000 milliseconds * 60 = 60 secs
+#define DEFAULT_GRACE_PERIOD 60
+#define AIM_DEFAULT_GROUP "miranda merged"
+#define AIM_DEFAULT_SERVER "login.oscar.aol.com:5190"
+#define SYSTEM_BUDDY "aolsystemmsg"
+#define DEFAULT_AWAY_MSG "I am away from my computer right now."
+//Md5 Roasting stuff
+#define AIM_MD5_STRING "AOL Instant Messenger (SM)"
+#define MD5_HASH_LENGTH 16
+//Aim Version Stuff
+#define AIM_CLIENT_ID_NUMBER "\x01\x09"
+#define AIM_CLIENT_MAJOR_VERSION "\0\x05"
+#define AIM_CLIENT_MINOR_VERSION "\0\x09"
+#define AIM_CLIENT_LESSER_VERSION "\0\0"
+#define AIM_CLIENT_BUILD_NUMBER "\x0b\xdc"
+#define AIM_CLIENT_DISTRIBUTION_NUMBER "\0\0\0\xd2"
+#define AIM_LANGUAGE "en"
+#define AIM_COUNTRY "us"
+#define AIM_MSG_TYPE "text/x-aolrtf; charset=\"us-ascii\""
+#define AIM_TOOL_VERSION "\x01\x10\x08\xf1"
+extern char* AIM_CLIENT_ID_STRING; //Client id EXTERN
+//Supported Clients
+#define CLIENT_UNKNOWN "?"
+#define CLIENT_AIM5 "AIM 5.x"
+#define CLIENT_AIM4 "AIM 4.x"
+#define CLIENT_AIMEXPRESS "AIM Express"
+#define CLIENT_AIM_TRITON "AIM Triton"
+#define CLIENT_AIMTOC "AIM TOC"
+#define CLIENT_GAIM "Gaim"
+#define CLIENT_ADIUM "Adium X"
+#define CLIENT_GPRS "GPRS"
+#define CLIENT_ICHAT "iChat"
+#define CLIENT_IM2 "IM2"
+#define CLIENT_KOPETE "Kopete"
+#define CLIENT_MEEBO "Meebo"
+#define CLIENT_MICQ "mICQ"
+#define CLIENT_AIMOSCAR "Miranda IM %d.%d.%d.%d(AimOSCAR v%d.%d.%d.%d)"
+#define CLIENT_OSCARJ "Miranda IM %d.%d.%d.%d(ICQ v0.%d.%d.%d)"
+#define CLIENT_NAIM "naim"
+#define CLIENT_QIP "qip"
+#define CLIENT_SIM "SIM"
+#define CLIENT_SMS "SMS"
+#define CLIENT_TERRAIM "TerraIM"
+#define CLIENT_TRILLIAN_PRO "Trillian Pro"
+#define CLIENT_TRILLIAN "Trillian"
+//Aim Caps
+#define AIM_CAPS_LENGTH 16
+#define AIM_CAP_ICHAT "\x09\x46\x00\x00\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWN3 "\x09\x46\x01\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWNA "\x09\x46\x01\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWNB "\x09\x46\x01\xff\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_HIPTOP "\x09\x46\x13\x23\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_VOICE_CHAT "\x09\x46\x13\x41\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_DIRECT_PLAY "\x09\x46\x13\x42\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_SEND_FILES "\x09\x46\x13\x43\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_ROUTER_FIND "\x09\x46\x13\x44\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"//icq?
+#define AIM_CAP_DIRECT_IM "\x09\x46\x13\x45\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_AVATARS "\x09\x46\x13\x46\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_ADDINS "\x09\x46\x13\x47\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_RECEIVE_FILES "\x09\x46\x13\x48\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_CHANNEL_TWO "\x09\x46\x13\x49\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"//icq? channel 2 extended, TLV(0x2711) based messages
+#define AIM_CAP_GAMES "\x09\x46\x13\x4A\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_LIST_TRANSFER "\x09\x46\x13\x4B\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_ICQ_SUPPORT "\x09\x46\x13\x4D\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UTF8 "\x09\x46\x13\x4E\x4C\x7F\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWN4 "\x09\x46\xf0\x03\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWN1 "\x09\x46\xf0\x04\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_UNKNOWNC "\x09\x46\xf0\x05\x4c\x7f\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_CHAT "\x74\x8F\x24\x20\x62\x87\x11\xD1\x82\x22\x44\x45\x53\x54\0\0"
+#define AIM_CAP_IM2 "\x74\xed\xc3\x36\x44\xdf\x48\x5b\x8b\x1c\x67\x1a\x1f\x86\x09\x9f"
+#define AIM_CAP_TRILLIAN "\xF2\xE7\xC7\xF4\xFE\xAD\x4D\xFB\xB2\x35\x36\x79\x8B\xDF\0\0"
+extern char AIM_CAP_MIRANDA[]; //Miranda cap EXTERN
+//Aim Services
+#define AIM_SERVICE_GENERIC "\0\x01\0\x04"//version 4
+#define AIM_SERVICE_SSI "\0\x13\0\x03"//version 3
+#define AIM_SERVICE_LOCATION "\0\x02\0\x01"//version 1
+#define AIM_SERVICE_BUDDYLIST "\0\x03\0\x01"//version 1
+#define AIM_SERVICE_MESSAGING "\0\x04\0\x01"//version 1
+#define AIM_SERVICE_INVITATION "\0\x06\0\x01"//version 1
+#define AIM_SERVICE_POPUP "\0\x08\0\x01"//version 1
+#define AIM_SERVICE_BOS "\0\x09\0\x01"//version 1
+#define AIM_SERVICE_AVATAR "\0\x10\0\x01"//version 1
+#define AIM_SERVICE_USERLOOKUP "\0\x0A\0\x01"//version 1
+#define AIM_SERVICE_STATS "\0\x0B\0\x01"//version 1
+#define AIM_SERVICE_MAIL "\0\x18\0\x01"//version 1
+#define AIM_SERVICE_RATES "\0\x01\0\x02\0\x03\0\x04\0\x05"
+//Aim Statuses
+#define AIM_STATUS_WEBAWARE "\0\x01"
+#define AIM_STATUS_SHOWIP "\0\x02"
+#define AIM_STATUS_BIRTHDAY "\0\x08"
+#define AIM_STATUS_WEBFRONT "\0\x20"
+#define AIM_STATUS_DCAUTH "\x10\0"
+#define AIM_STATUS_DCCONT "\x20\0"
+#define AIM_STATUS_NULL "\0\0"
+#define AIM_STATUS_ONLINE "\0\0"
+#define AIM_STATUS_AWAY "\0\x01"
+#define AIM_STATUS_DND "\0\x02"
+#define AIM_STATUS_NA "\0\x04"
+#define AIM_STATUS_OCCUPIED "\0\x10"
+#define AIM_STATUS_FREE4CHAT "\0\x20"
+#define AIM_STATUS_INVISIBLE "\x01\0"
+
+#define HOOKEVENT_SIZE 10
+#define SERVICES_SIZE 30
+class oscar_data
+{
+public:
+ char *username;
+ char *password;
+ unsigned short seqno;//main connection sequence number
+ int state;//status of the connection; e.g. whether connected or not
+ int packet_offset;//current offset of main connection client to server packet
+ unsigned int status;//current status
+ int initial_status;//start up status
+ char* szModeMsg;//away message
+ unsigned short port;
+
+ //Some bools to keep track of different things
+ bool request_HTML_profile;
+ bool extra_icons_loaded;
+ bool freeing_DirectBoundPort;
+ bool shutting_down;
+ bool idle;
+ bool instantidle;
+ bool checking_mail;
+ bool list_received;
+ HANDLE hKeepAliveEvent;
+
+ HINSTANCE hInstance;//plugin handle instance
+
+ //Some main connection stuff
+ HANDLE hServerConn;//handle to the main connection
+ HANDLE hServerPacketRecver;//handle to the listening device
+ HANDLE hNetlib;//handle to netlib
+ unsigned long InternalIP;// our ip
+ unsigned short LocalPort;// our port
+
+ //Peer connection stuff
+ HANDLE hNetlibPeer;//handle to the peer netlib
+ HANDLE hDirectBoundPort;//direct connection listening port
+ HANDLE current_rendezvous_accept_user;//hack
+
+ //Handles for the context menu items
+ HANDLE hHTMLAwayContextMenuItem;
+ HANDLE hAddToServerListContextMenuItem;
+
+ //hook event size stuff
+ HANDLE hookEvent[HOOKEVENT_SIZE];
+ unsigned int hookEvent_size;//current hookevent size
+
+ //services size stuff
+ HANDLE services[SERVICES_SIZE];
+ unsigned int services_size;//current services size
+
+ //Some mail connection stuff
+ HANDLE hMailConn;
+ unsigned short mail_seqno;
+ int mail_packet_offset;
+
+ //avatar connection stuff
+ HANDLE hAvatarConn;
+ unsigned short avatar_seqno;
+ HANDLE hAvatarEvent;
+ bool AvatarLimitThread;
+
+ //away message retrieval stuff
+ HANDLE hAwayMsgEvent;
+
+ //Some Icon handles
+ HANDLE bot_icon;
+ HANDLE icq_icon;
+ HANDLE aol_icon;
+ HANDLE hiptop_icon;
+ HANDLE admin_icon;
+ HANDLE confirmed_icon;
+ HANDLE unconfirmed_icon;
+} extern conn;
+
+void InitIcons(void);
+HICON LoadIconEx(const char* name);
+HANDLE GetIconHandle(const char* name);
+void ReleaseIconEx(const char* name);
+
+#endif
diff --git a/protocols/AimOscar/src/direct_connect.cpp b/protocols/AimOscar/src/direct_connect.cpp
new file mode 100644
index 0000000000..4552b461cf
--- /dev/null
+++ b/protocols/AimOscar/src/direct_connect.cpp
@@ -0,0 +1,88 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+void __cdecl CAimProto::aim_dc_helper(void* param) //only called when we are initiating a direct connection with someone else
+{
+ file_transfer *ft = (file_transfer*)param;
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, ft, 0);
+
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = 350000;
+
+ HANDLE hServerPacketRecver = (HANDLE) CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)ft->hConn, 2048 * 4);
+
+ int result;
+ if (ft->sending)//we are sending
+ result = sending_file(ft, hServerPacketRecver, packetRecv);
+ else
+ result = receiving_file(ft, hServerPacketRecver, packetRecv);
+
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(ft->hConn);
+ ft->hConn = NULL;
+
+ if (result == 0)
+ {
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0);
+ }
+ else
+ {
+ if (!ft->requester && result == 1 && !Miranda_Terminated())
+ {
+ ft->accepted = false;
+ HANDLE hConn = aim_peer_connect(AIM_PROXY_SERVER, get_default_port());
+ if (hConn)
+ {
+ LOG("Connected to proxy ip because we want to use a proxy for the file transfer.");
+ ft->requester = true;
+ ft->hConn = hConn;
+ ForkThread(&CAimProto::aim_proxy_helper, ft);
+ return;
+ }
+ }
+ aim_file_ad(hServerConn, seqno, ft->sn, ft->icbm_cookie, true, 0);
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+ }
+
+ ft_list.remove_by_ft(ft);
+}
+
+void aim_direct_connection_initiated(HANDLE hNewConnection, DWORD, void* extra)//for receiving stuff via dc
+{
+ CAimProto* ppro = (CAimProto*)extra;
+ file_transfer *ft;
+
+ NETLIBCONNINFO connInfo = { sizeof(connInfo) };
+ CallService(MS_NETLIB_GETCONNECTIONINFO, (WPARAM)hNewConnection, (LPARAM)&connInfo);
+
+ ppro->LOG("Buddy connected: %s", connInfo.szIpPort);
+
+ // okay someone connected to us or we initiated the connection- we need to figure out who they are and if they belong
+ ft = ppro->ft_list.find_by_port(connInfo.wPort);
+ if (ft)
+ {
+ ft->hConn = hNewConnection;
+ ppro->aim_dc_helper(ft);
+ }
+ else
+ Netlib_CloseHandle(hNewConnection);
+}
diff --git a/protocols/AimOscar/src/direct_connect.h b/protocols/AimOscar/src/direct_connect.h
new file mode 100644
index 0000000000..4b164f9181
--- /dev/null
+++ b/protocols/AimOscar/src/direct_connect.h
@@ -0,0 +1,24 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef DIRECT_CONNECT_H
+#define DIRECT_CONNECT_H
+
+void aim_direct_connection_initiated(HANDLE hNewConnection, DWORD dwRemoteIP, void* extra);
+
+#endif
diff --git a/protocols/AimOscar/src/error.cpp b/protocols/AimOscar/src/error.cpp
new file mode 100644
index 0000000000..9fccb6c4d4
--- /dev/null
+++ b/protocols/AimOscar/src/error.cpp
@@ -0,0 +1,289 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+void CAimProto::login_error(unsigned short error)
+{
+ switch(error)
+ {
+ case 0x0004:
+ ShowPopup(LPGEN("Invalid Screen Name or password."), ERROR_POPUP);
+ break;
+
+ case 0x0005:
+ ShowPopup(LPGEN("Mismatched Screen Name or password."), ERROR_POPUP);
+ break;
+
+ case 0x0018:
+ ShowPopup(LPGEN("You are connecting too frequently. Try waiting 10 minutes to reconnect."), ERROR_POPUP);
+ break;
+
+ default:
+ ShowPopup(LPGEN("Unknown error occured when attempting to connect."), ERROR_POPUP);
+ break;
+ }
+}
+
+void CAimProto::get_error(unsigned short error)
+{
+ switch(error)
+ {
+ case 0x01:
+ ShowPopup(LPGEN("Invalid SNAC header."), ERROR_POPUP);
+ break;
+
+ case 0x02:
+ ShowPopup(LPGEN("Server rate limit exceeded."), ERROR_POPUP);
+ break;
+
+ case 0x03:
+ ShowPopup(LPGEN("Client rate limit exceeded"), ERROR_POPUP);
+ break;
+
+ case 0x04:
+ ShowPopup(LPGEN("Recipient is not logged in."), ERROR_POPUP);
+ break;
+
+ case 0x05:
+ ShowPopup(LPGEN("Requested service is unavailable."), ERROR_POPUP);
+ break;
+
+ case 0x06:
+ ShowPopup(LPGEN("Requested service is not defined."), ERROR_POPUP);
+ break;
+
+ case 0x07:
+ ShowPopup(LPGEN("You sent obsolete SNAC."), ERROR_POPUP);
+ break;
+
+ case 0x08:
+ ShowPopup(LPGEN("Not supported by server."), ERROR_POPUP);
+ break;
+
+ case 0x09:
+ ShowPopup(LPGEN("Not supported by the client."), ERROR_POPUP);
+ break;
+
+ case 0x0a:
+ ShowPopup(LPGEN("Refused by client."), ERROR_POPUP);
+ break;
+
+ case 0x0b:
+ ShowPopup(LPGEN("Reply too big."), ERROR_POPUP);
+ break;
+
+ case 0x0c:
+ ShowPopup(LPGEN("Response lost."), ERROR_POPUP);
+ break;
+
+ case 0x0d:
+ ShowPopup(LPGEN("Request denied."), ERROR_POPUP);
+ break;
+
+ case 0x0e:
+ ShowPopup(LPGEN("Incorrect SNAC format."), ERROR_POPUP);
+ break;
+
+ case 0x0f:
+ ShowPopup(LPGEN("Insufficient rights."), ERROR_POPUP);
+ break;
+
+ case 0x10:
+ ShowPopup(LPGEN("Recipient blocked."), ERROR_POPUP);
+ break;
+
+ case 0x11:
+ ShowPopup(LPGEN("Sender too evil."), ERROR_POPUP);
+ break;
+
+ case 0x12:
+ ShowPopup(LPGEN("Receiver too evil."), ERROR_POPUP);
+ break;
+
+ case 0x13:
+ ShowPopup(LPGEN("User temporarily unavailable."), ERROR_POPUP);
+ break;
+
+ case 0x14:
+ ShowPopup(LPGEN("No Match."), ERROR_POPUP);
+ break;
+
+ case 0x15:
+ ShowPopup(LPGEN("List overflow."), ERROR_POPUP);
+ break;
+
+ case 0x16:
+ ShowPopup(LPGEN("Request ambiguous."), ERROR_POPUP);
+ break;
+
+ case 0x17:
+ ShowPopup(LPGEN("Server queue full."), ERROR_POPUP);
+ break;
+
+ case 0x18:
+ ShowPopup(LPGEN("Not while on AOL."), ERROR_POPUP);
+ break;
+ }
+}
+
+void CAimProto::admin_error(unsigned short error)
+{
+ switch(error)
+ {
+ case 0x01:
+ ShowPopup(LPGEN("Check your Screen Name."), ERROR_POPUP);
+ break;
+
+ case 0x02:
+ ShowPopup(LPGEN("Check your Password."), ERROR_POPUP);
+ break;
+
+ case 0x03:
+ ShowPopup(LPGEN("Check your Email Address."), ERROR_POPUP);
+ break;
+
+ case 0x04:
+ ShowPopup(LPGEN("Service temporarily unavailable."), ERROR_POPUP);
+ break;
+
+ case 0x05:
+ ShowPopup(LPGEN("Field change temporarily unavailable."), ERROR_POPUP);
+ break;
+
+ case 0x06:
+ ShowPopup(LPGEN("Invalid Screen Name."), ERROR_POPUP);
+ break;
+
+ case 0x07:
+ ShowPopup(LPGEN("Invalid Password."), ERROR_POPUP);
+ break;
+
+ case 0x08:
+ ShowPopup(LPGEN("Invalid Email."), ERROR_POPUP);
+ break;
+
+ case 0x09:
+ ShowPopup(LPGEN("Invalid Registration Preference."), ERROR_POPUP);
+ break;
+
+ case 0x0a:
+ ShowPopup(LPGEN("Invalid Old Password."), ERROR_POPUP);
+ break;
+
+ case 0x0b:
+ ShowPopup(LPGEN("Invalid Screen Name Length."), ERROR_POPUP);
+ break;
+
+ case 0x0c:
+ ShowPopup(LPGEN("Invalid Password Length."), ERROR_POPUP);
+ break;
+
+ case 0x0d:
+ ShowPopup(LPGEN("Invalid Email Length."), ERROR_POPUP);
+ break;
+
+ case 0x0e:
+ ShowPopup(LPGEN("Invalid Old Password Length."), ERROR_POPUP);
+ break;
+
+ case 0x0f:
+ ShowPopup(LPGEN("Need Old Password."), ERROR_POPUP);
+ break;
+
+ case 0x10:
+ ShowPopup(LPGEN("Read Only Field."), ERROR_POPUP);
+ break;
+
+ case 0x11:
+ ShowPopup(LPGEN("Write Only Field."), ERROR_POPUP);
+ break;
+
+ case 0x12:
+ ShowPopup(LPGEN("Unsupported Type."), ERROR_POPUP);
+ break;
+
+ case 0x13:
+ ShowPopup(LPGEN("An Error has occured."), ERROR_POPUP);
+ break;
+
+ case 0x14:
+ ShowPopup(LPGEN("Incorrect SNAC format."), ERROR_POPUP);
+ break;
+
+ case 0x15:
+ ShowPopup(LPGEN("Invalid Account."), ERROR_POPUP);
+ break;
+
+ case 0x16:
+ ShowPopup(LPGEN("Delete Account."), ERROR_POPUP);
+ break;
+
+ case 0x17:
+ ShowPopup(LPGEN("Expired Account."), ERROR_POPUP);
+ break;
+
+ case 0x18:
+ ShowPopup(LPGEN("No Database access."), ERROR_POPUP);
+ break;
+
+ case 0x19:
+ ShowPopup(LPGEN("Invalid Database fields."), ERROR_POPUP);
+ break;
+
+ case 0x1a:
+ ShowPopup(LPGEN("Bad Database status."), ERROR_POPUP);
+ break;
+
+ case 0x1b:
+ ShowPopup(LPGEN("Migration Cancel."), ERROR_POPUP);
+ break;
+
+ case 0x1c:
+ ShowPopup(LPGEN("Internal Error."), ERROR_POPUP);
+ break;
+
+ case 0x1d:
+ ShowPopup(LPGEN("There is already a Pending Request for this Screen Name."), ERROR_POPUP);
+ break;
+
+ case 0x1e:
+ ShowPopup(LPGEN("Not DT status."), ERROR_POPUP);
+ break;
+
+ case 0x1f:
+ ShowPopup(LPGEN("Outstanding Confirmation."), ERROR_POPUP);
+ break;
+
+ case 0x20:
+ ShowPopup(LPGEN("No Email Address."), ERROR_POPUP);
+ break;
+
+ case 0x21:
+ ShowPopup(LPGEN("Over Limit."), ERROR_POPUP);
+ break;
+
+ case 0x22:
+ ShowPopup(LPGEN("Email Host Fail."), ERROR_POPUP);
+ break;
+
+ case 0x23:
+ ShowPopup(LPGEN("DNS Fail."), ERROR_POPUP);
+ break;
+ }
+}
diff --git a/protocols/AimOscar/src/file.cpp b/protocols/AimOscar/src/file.cpp
new file mode 100644
index 0000000000..7af67727e8
--- /dev/null
+++ b/protocols/AimOscar/src/file.cpp
@@ -0,0 +1,592 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "file.h"
+
+#pragma pack(push, 1)
+struct oft2//oscar file transfer 2 class- See On_Sending_Files_via_OSCAR.pdf
+{
+ char protocol_version[4];//4
+ unsigned short length;//6
+ unsigned short type;//8
+ unsigned char icbm_cookie[8];//16
+ unsigned short encryption;//18
+ unsigned short compression;//20
+ unsigned short total_files;//22
+ unsigned short num_files_left;//24
+ unsigned short total_parts;//26
+ unsigned short parts_left;//28
+ unsigned long total_size;//32
+ unsigned long size;//36
+ unsigned long mod_time;//40
+ unsigned long checksum;//44
+ unsigned long recv_RFchecksum;//48
+ unsigned long RFsize;//52
+ unsigned long creation_time;//56
+ unsigned long RFchecksum;//60
+ unsigned long recv_bytes;//64
+ unsigned long recv_checksum;//68
+ unsigned char idstring[32];//100
+ unsigned char flags;//101
+ unsigned char list_name_offset;//102
+ unsigned char list_size_offset;//103
+ unsigned char dummy[69];//172
+ unsigned char mac_info[16];//188
+ unsigned short encoding;//190
+ unsigned short sub_encoding;//192
+ unsigned char filename[64];//256
+ };
+
+#pragma pack(pop)
+
+bool send_init_oft2(file_transfer *ft, char* file)
+{
+ aimString astr(file);
+
+ unsigned short len = max(0x100, 0xc0 + astr.getTermSize());
+
+ oft2 *oft = (oft2*)alloca(len);
+ memset(oft, 0, len);
+
+ memcpy(oft->protocol_version, "OFT2", 4);
+ oft->length = _htons(len);
+ oft->type = 0x0101;
+ oft->total_files = _htons(ft->pfts.totalFiles);
+ oft->num_files_left = _htons(ft->pfts.totalFiles - ft->pfts.currentFileNumber);
+ oft->total_parts = _htons(1);
+ oft->parts_left = _htons(1);
+ oft->total_size = _htonl(ft->pfts.totalBytes);
+ oft->size = _htonl(ft->pfts.currentFileSize);
+ oft->mod_time = _htonl(ft->pfts.currentFileTime);
+ oft->checksum = _htonl(aim_oft_checksum_file(ft->pfts.tszCurrentFile));
+ oft->recv_RFchecksum = 0x0000FFFF;
+ oft->RFchecksum = 0x0000FFFF;
+ oft->recv_checksum = 0x0000FFFF;
+ memcpy(oft->idstring, "Cool FileXfer", 13);
+ oft->flags = 0x20;
+ oft->list_name_offset = 0x1c;
+ oft->list_size_offset = 0x11;
+ oft->encoding = _htons(astr.isUnicode() ? 2 : 0);
+ memcpy(oft->filename, astr.getBuf(), astr.getTermSize());
+
+ if (!ft->requester || ft->pfts.currentFileNumber)
+ memcpy(oft->icbm_cookie, ft->icbm_cookie, 8);
+
+ return Netlib_Send(ft->hConn, (char*)oft, len, 0) > 0;
+}
+
+void CAimProto::report_file_error(TCHAR *fname)
+{
+ TCHAR errmsg[512];
+ TCHAR* error = mir_a2t(_strerror(NULL));
+ mir_sntprintf(errmsg, SIZEOF(errmsg), TranslateT("Failed to open file: %s : %s"), fname, error);
+ mir_free(error);
+ ShowPopup((char*)errmsg, ERROR_POPUP | TCHAR_POPUP);
+}
+
+bool setup_next_file_send(file_transfer *ft)
+{
+ TCHAR *file;
+ struct _stati64 statbuf;
+ for (;;)
+ {
+ file = ft->pfts.ptszFiles[ft->cf];
+ if (file == NULL) return false;
+
+ if (_tstati64(file, &statbuf) == 0 && (statbuf.st_mode & _S_IFDIR) == 0)
+ break;
+
+ ++ft->cf;
+ }
+
+ ft->pfts.tszCurrentFile = file;
+ ft->pfts.currentFileSize = statbuf.st_size;
+ ft->pfts.currentFileTime = statbuf.st_mtime;
+ ft->pfts.currentFileProgress = 0;
+
+ char* fnamea;
+ char* fname = mir_utf8encodeT(file);
+ if (ft->pfts.totalFiles > 1 && ft->file[0])
+ {
+ size_t dlen = strlen(ft->file);
+ if (strncmp(fname, ft->file, dlen) == 0 && fname[dlen] == '\\')
+ {
+ fnamea = &fname[dlen+1];
+ for (char *p = fnamea; *p; ++p) { if (*p == '\\') *p = 1; }
+ }
+ else
+ fnamea = get_fname(fname);
+ }
+ else
+ fnamea = get_fname(fname);
+
+ send_init_oft2(ft, fnamea);
+
+ mir_free(fname);
+ return true;
+}
+
+int CAimProto::sending_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv)
+{
+ LOG("P2P: Entered file sending thread.");
+
+ bool failed = true;
+ bool failed_conn = false;
+
+ if (!setup_next_file_send(ft)) return 2;
+
+ LOG("Sent file information to buddy.");
+ //start listen for packets stuff
+
+ for (;;)
+ {
+ int recvResult = packetRecv.bytesAvailable - packetRecv.bytesUsed;
+ if (recvResult <= 0)
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ {
+ LOG("P2P: File transfer connection Error: 0");
+ break;
+ }
+ if (recvResult == SOCKET_ERROR)
+ {
+ failed_conn = true;
+ LOG("P2P: File transfer connection Error: -1");
+ break;
+ }
+ if (recvResult > 0)
+ {
+ if (recvResult < 0x100) continue;
+
+ oft2* recv_ft = (oft2*)&packetRecv.buffer[packetRecv.bytesUsed];
+
+ unsigned short pkt_len = _htons(recv_ft->length);
+ if (recvResult < pkt_len) continue;
+
+ packetRecv.bytesUsed += pkt_len;
+ unsigned short type = _htons(recv_ft->type);
+ if (type == 0x0202 || type == 0x0207)
+ {
+ LOG("P2P: Buddy Accepts our file transfer.");
+
+ int fid = _topen(ft->pfts.tszCurrentFile, _O_RDONLY | _O_BINARY, _S_IREAD);
+ if (fid < 0)
+ {
+ report_file_error(ft->pfts.tszCurrentFile);
+ return 2;
+ }
+
+ if (ft->pfts.currentFileProgress) _lseeki64(fid, ft->pfts.currentFileProgress, SEEK_SET);
+
+ NETLIBSELECT tSelect = {0};
+ tSelect.cbSize = sizeof(tSelect);
+ tSelect.hReadConns[0] = ft->hConn;
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
+
+ clock_t lNotify = clock();
+ for (;;)
+ {
+ char buffer[4096];
+ int bytes = _read(fid, buffer, sizeof(buffer));
+ if (bytes <= 0) break;
+
+ if (Netlib_Send(ft->hConn, buffer, bytes, MSG_NODUMP) <= 0) break;
+ ft->pfts.currentFileProgress += bytes;
+ ft->pfts.totalProgress += bytes;
+
+ if (clock() >= lNotify)
+ {
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
+ if (CallService(MS_NETLIB_SELECT, 0, (LPARAM)&tSelect)) break;
+
+ lNotify = clock() + 500;
+ }
+ }
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
+ LOG("P2P: Finished sending file bytes.");
+ _close(fid);
+ }
+ else if (type == 0x0204)
+ {
+ // Handle file skip case
+ if (ft->pfts.currentFileProgress == 0)
+ {
+ ft->pfts.totalProgress += ft->pfts.currentFileSize;
+ }
+
+ LOG("P2P: Buddy says they got the file successfully");
+ if ((ft->pfts.currentFileNumber + 1) < ft->pfts.totalFiles)
+ {
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
+ ++ft->pfts.currentFileNumber; ++ft->cf;
+
+ if (!setup_next_file_send(ft))
+ {
+ report_file_error(ft->pfts.tszCurrentFile);
+ return 2;
+ }
+ }
+ else
+ {
+ failed = _htonl(recv_ft->recv_bytes) != ft->pfts.currentFileSize;
+ break;
+ }
+ }
+ else if (type == 0x0205)
+ {
+ oft2* recv_ft = (oft2*)packetRecv.buffer;
+ recv_ft->type = _htons(0x0106);
+
+ ft->pfts.currentFileProgress = _htonl(recv_ft->recv_bytes);
+ if (aim_oft_checksum_file(ft->pfts.tszCurrentFile, ft->pfts.currentFileProgress) != _htonl(recv_ft->recv_checksum))
+ {
+ ft->pfts.currentFileProgress = 0;
+ recv_ft->recv_bytes = 0;
+ }
+
+ LOG("P2P: Buddy wants us to start sending at a specified file point. (%I64u)", ft->pfts.currentFileProgress);
+ if (Netlib_Send(ft->hConn, (char*)recv_ft, _htons(recv_ft->length), 0) <= 0) break;
+
+ ft->pfts.totalProgress += ft->pfts.currentFileProgress;
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
+ }
+ }
+ }
+
+ ft->success = !failed;
+ return failed ? (failed_conn ? 1 : 2) : 0;
+}
+
+int CAimProto::receiving_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv)
+{
+ LOG("P2P: Entered file receiving thread.");
+ bool failed = true;
+ bool failed_conn = false;
+ bool accepted_file = false;
+ int fid = -1;
+
+ oft2 *oft = NULL;
+
+ ft->pfts.tszWorkingDir = mir_utf8decodeT(ft->file);
+
+ //start listen for packets stuff
+ for (;;)
+ {
+ int recvResult = packetRecv.bytesAvailable - packetRecv.bytesUsed;
+ if (recvResult <= 0)
+ recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ {
+ LOG("P2P: File transfer connection Error: 0");
+ break;
+ }
+ if (recvResult == SOCKET_ERROR)
+ {
+ failed_conn = true;
+ LOG("P2P: File transfer connection Error: -1");
+ break;
+ }
+ if (recvResult > 0)
+ {
+ if (!accepted_file)
+ {
+ if (recvResult < 0x100) continue;
+
+ oft2* recv_ft = (oft2*)&packetRecv.buffer[packetRecv.bytesUsed];
+ unsigned short pkt_len = _htons(recv_ft->length);
+
+ if (recvResult < pkt_len) continue;
+ packetRecv.bytesUsed += pkt_len;
+
+ unsigned short type = _htons(recv_ft->type);
+ if (type == 0x0101)
+ {
+ LOG("P2P: Buddy Ready to begin transfer.");
+ oft = (oft2*)mir_realloc(oft, pkt_len);
+ memcpy(oft, recv_ft, pkt_len);
+ memcpy(oft->icbm_cookie, ft->icbm_cookie, 8);
+
+ int buflen = pkt_len - 0x100 + 64;
+ char *buf = (char*)mir_calloc(buflen + 2);
+ unsigned short enc;
+
+ ft->pfts.currentFileSize = _htonl(recv_ft->size);
+ ft->pfts.totalBytes = _htonl(recv_ft->total_size);
+ ft->pfts.currentFileTime = _htonl(recv_ft->mod_time);
+ memcpy(buf, recv_ft->filename, buflen);
+ enc = _htons(recv_ft->encoding);
+
+ TCHAR *name;
+ if (enc == 2)
+ {
+ wchar_t* wbuf = (wchar_t*)buf;
+ wcs_htons(wbuf);
+ for (wchar_t *p = wbuf; *p; ++p) { if (*p == 1) *p = '\\'; }
+ name = mir_u2t(wbuf);
+ }
+ else
+ {
+ for (char *p = buf; *p; ++p) { if (*p == 1) *p = '\\'; }
+ name = mir_a2t(buf);
+ }
+
+ mir_free(buf);
+
+ TCHAR fname[256];
+ mir_sntprintf(fname, SIZEOF(fname), _T("%s%s"), ft->pfts.tszWorkingDir, name);
+ mir_free(name);
+ mir_free(ft->pfts.tszCurrentFile);
+ ft->pfts.tszCurrentFile = mir_tstrdup(fname);
+
+ ResetEvent(ft->hResumeEvent);
+ if (sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&ft->pfts))
+ WaitForSingleObject(ft->hResumeEvent, INFINITE);
+
+ if (ft->pfts.tszCurrentFile)
+ {
+ TCHAR* dir = get_dir(ft->pfts.tszCurrentFile);
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)dir);
+ mir_free(dir);
+
+ oft->type = _htons(ft->pfts.currentFileProgress ? 0x0205 : 0x0202);
+
+ const int flag = ft->pfts.currentFileProgress ? 0 : _O_TRUNC;
+ fid = _topen(ft->pfts.tszCurrentFile, _O_CREAT | _O_WRONLY | _O_BINARY | flag, _S_IREAD | _S_IWRITE);
+
+ if (fid < 0)
+ {
+ report_file_error(fname);
+ break;
+ }
+
+ accepted_file = ft->pfts.currentFileProgress == 0;
+
+ if (ft->pfts.currentFileProgress)
+ {
+ bool the_same;
+ oft->recv_bytes = _htonl(ft->pfts.currentFileProgress);
+ oft->recv_checksum = _htonl(aim_oft_checksum_file(ft->pfts.tszCurrentFile));
+ the_same = oft->size == oft->recv_bytes && oft->checksum == oft->recv_checksum;
+ if (the_same)
+ {
+ ft->pfts.totalProgress += ft->pfts.currentFileProgress;
+ oft->type = _htons(0x0204);
+ _close(fid);
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
+ ++ft->pfts.currentFileNumber;
+ ft->pfts.currentFileProgress = 0;
+ }
+ }
+ }
+ else
+ {
+ oft->type = _htons(0x0204);
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
+ ++ft->pfts.currentFileNumber;
+ ft->pfts.currentFileProgress = 0;
+ }
+
+ if (Netlib_Send(ft->hConn, (char*)oft, pkt_len, 0) == SOCKET_ERROR)
+ break;
+
+ if (ft->pfts.currentFileNumber >= ft->pfts.totalFiles && _htons(oft->type) == 0x0204)
+ {
+ failed = false;
+ break;
+ }
+ }
+ else if (type == 0x0106)
+ {
+ oft = (oft2*)mir_realloc(oft, pkt_len);
+ memcpy(oft, recv_ft, pkt_len);
+
+ ft->pfts.currentFileProgress = _htonl(oft->recv_bytes);
+ ft->pfts.totalProgress += ft->pfts.currentFileProgress;
+
+ _lseeki64(fid, ft->pfts.currentFileProgress, SEEK_SET);
+ accepted_file = true;
+
+ oft->type = _htons(0x0207);
+ if (Netlib_Send(ft->hConn, (char*)oft, pkt_len, 0) == SOCKET_ERROR)
+ break;
+ }
+ else
+ break;
+ }
+ else
+ {
+ packetRecv.bytesUsed = packetRecv.bytesAvailable;
+ _write(fid, packetRecv.buffer, packetRecv.bytesAvailable);
+ ft->pfts.currentFileProgress += packetRecv.bytesAvailable;
+ ft->pfts.totalProgress += packetRecv.bytesAvailable;
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
+ if (ft->pfts.currentFileSize == ft->pfts.currentFileProgress)
+ {
+ oft->type = _htons(0x0204);
+ oft->recv_bytes = _htonl(ft->pfts.currentFileProgress);
+ oft->recv_checksum = _htonl(aim_oft_checksum_file(ft->pfts.tszCurrentFile));
+
+ LOG("P2P: We got the file successfully");
+ Netlib_Send(ft->hConn, (char*)oft, _htons(oft->length), 0);
+ if (_htons(oft->num_files_left) == 1)
+ {
+ failed = false;
+ break;
+ }
+ else
+ {
+ accepted_file = false;
+ _close(fid);
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0);
+ ++ft->pfts.currentFileNumber;
+ ft->pfts.currentFileProgress = 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (accepted_file) _close(fid);
+ mir_free(oft);
+
+ ft->success = !failed;
+ return failed ? (failed_conn ? 1 : 2) : 0;
+}
+
+void CAimProto::shutdown_file_transfers(void)
+{
+ for(int i=0; i<ft_list.getCount(); ++i)
+ {
+ file_transfer& ft = ft_list[i];
+ if (ft.hConn)
+ Netlib_Shutdown(ft.hConn);
+ }
+}
+
+ft_list_type::ft_list_type() : OBJLIST <file_transfer>(10) {};
+
+file_transfer* ft_list_type::find_by_cookie(char* cookie, HANDLE hContact)
+{
+ for (int i = 0; i < getCount(); ++i)
+ {
+ file_transfer *ft = items[i];
+ if (ft->hContact == hContact && memcmp(ft->icbm_cookie, cookie, 8) == 0)
+ return ft;
+ }
+ return NULL;
+}
+
+file_transfer* ft_list_type::find_by_port(unsigned short port)
+{
+ for (int i = getCount(); i--; )
+ {
+ file_transfer *ft = items[i];
+ if (ft->requester && ft->local_port == port)
+ return ft;
+ }
+ return NULL;
+}
+
+
+bool ft_list_type::find_by_ft(file_transfer *ft)
+{
+ for (int i = 0; i < getCount(); ++i)
+ {
+ if (items[i] == ft) return true;
+ }
+ return false;
+}
+
+void ft_list_type::remove_by_ft(file_transfer *ft)
+{
+ for (int i = 0; i < getCount(); ++i)
+ {
+ if (items[i] == ft)
+ {
+ remove(i);
+ break;
+ }
+ }
+}
+
+file_transfer::file_transfer(HANDLE hCont, char* nick, char* cookie)
+{
+ memset(this, 0, sizeof(*this));
+
+ pfts.cbSize = sizeof(pfts);
+ pfts.flags = PFTS_TCHAR;
+ pfts.hContact = hCont;
+
+ hContact = hCont;
+ sn = mir_strdup(nick);
+
+ if (cookie)
+ memcpy(icbm_cookie, cookie, 8);
+ else
+ CallService(MS_UTILS_GETRANDOM, 8, (LPARAM)icbm_cookie);
+
+ hResumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+file_transfer::~file_transfer()
+{
+ stop_listen();
+
+ mir_free(file);
+ mir_free(message);
+ mir_free(sn);
+
+ mir_free(pfts.tszWorkingDir);
+ if (!sending) mir_free(pfts.tszCurrentFile);
+
+ if (success && pfts.ptszFiles)
+ {
+ for (int i = 0; pfts.ptszFiles[i]; i++)
+ mir_free(pfts.ptszFiles[i]);
+
+ mir_free(pfts.ptszFiles);
+ }
+ CloseHandle(hResumeEvent);
+}
+
+void file_transfer::listen(CAimProto* ppro)
+{
+ if (hDirectBoundPort) return;
+
+ NETLIBBIND nlb = {0};
+ nlb.cbSize = sizeof(nlb);
+ nlb.pfnNewConnectionV2 = aim_direct_connection_initiated;
+ nlb.pExtra = ppro;
+ hDirectBoundPort = (HANDLE)CallService(MS_NETLIB_BINDPORT, (WPARAM)ppro->hNetlibPeer, (LPARAM)&nlb);
+ local_port = hDirectBoundPort ? nlb.wPort : 0;
+}
+
+void file_transfer::stop_listen(void)
+{
+ if (hDirectBoundPort)
+ {
+ Netlib_CloseHandle(hDirectBoundPort);
+ hDirectBoundPort = NULL;
+ local_port = 0;
+ }
+}
diff --git a/protocols/AimOscar/src/file.h b/protocols/AimOscar/src/file.h
new file mode 100644
index 0000000000..591e86b75b
--- /dev/null
+++ b/protocols/AimOscar/src/file.h
@@ -0,0 +1,81 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef FILE_H
+#define FILE_H
+
+struct CAimProto;
+
+struct file_transfer
+{
+ HANDLE hContact;
+ char* sn;
+
+ char icbm_cookie[8];
+
+ HANDLE hConn;
+ HANDLE hResumeEvent;
+ HANDLE hDirectBoundPort;
+
+ char* file;
+ char* message;
+
+ PROTOFILETRANSFERSTATUS pfts;
+
+ unsigned long cf;
+
+ //below is for when receiving only
+ unsigned long local_ip;
+ unsigned long verified_ip;
+ unsigned long proxy_ip;
+ unsigned short port;
+ unsigned short max_ver;
+
+ unsigned short req_num;
+ unsigned short local_port;
+
+ bool peer_force_proxy;
+ bool me_force_proxy;
+ bool sending;
+ bool accepted;
+ bool requester;
+ bool success;
+
+ file_transfer(HANDLE hCont, char* nick, char* cookie);
+ ~file_transfer();
+
+ void listen(CAimProto* ppro);
+ void stop_listen(void);
+
+};
+
+struct ft_list_type : OBJLIST <file_transfer>
+{
+ ft_list_type();
+
+ file_transfer* find_by_handle(HANDLE hContact);
+ file_transfer* find_by_cookie(char* cookie, HANDLE hContact);
+ file_transfer* find_by_port(unsigned short port);
+
+ bool find_by_ft(file_transfer *ft);
+
+ void remove_by_ft(file_transfer *ft);
+};
+
+
+#endif
diff --git a/protocols/AimOscar/src/flap.cpp b/protocols/AimOscar/src/flap.cpp
new file mode 100644
index 0000000000..f652aff710
--- /dev/null
+++ b/protocols/AimOscar/src/flap.cpp
@@ -0,0 +1,60 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "flap.h"
+
+FLAP::FLAP(char* buf,int num_bytes)
+{
+ if(FLAP_SIZE>num_bytes)
+ {
+ length_=0;
+ }
+ else
+ {
+ length_=_htons((*(unsigned short*)&buf[4]));
+ if(FLAP_SIZE+length_>num_bytes)
+ {
+ length_=0;
+ }
+ else
+ {
+ type_=buf[1];
+ value_=&buf[FLAP_SIZE];
+ }
+ }
+}
+unsigned short FLAP::len()
+{
+ return length_;
+}
+unsigned short FLAP::snaclen()
+{
+ return length_-10;
+}
+int FLAP::cmp(unsigned short type)
+{
+ if(type_==type)
+ return 1;
+ else
+ return 0;
+}
+char* FLAP::val()
+{
+ return value_;
+}
diff --git a/protocols/AimOscar/src/flap.h b/protocols/AimOscar/src/flap.h
new file mode 100644
index 0000000000..ad31616ed2
--- /dev/null
+++ b/protocols/AimOscar/src/flap.h
@@ -0,0 +1,39 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef FLAP_H
+#define FLAP_H
+
+#include "packets.h"
+
+#define FLAP_SIZE 6
+
+class FLAP
+{
+private:
+ unsigned char type_;
+ unsigned short length_;
+ char* value_;
+public:
+ FLAP(char* buf,int num_bytes);
+ unsigned short len();
+ unsigned short snaclen();
+ int cmp(unsigned short type);
+ char* val();
+};
+
+#endif
diff --git a/protocols/AimOscar/src/links.cpp b/protocols/AimOscar/src/links.cpp
new file mode 100644
index 0000000000..c4eec4ae69
--- /dev/null
+++ b/protocols/AimOscar/src/links.cpp
@@ -0,0 +1,195 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2010 Boris Krasnovskiy
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aim.h"
+#include "links.h"
+#include "m_assocmgr.h"
+
+static HANDLE hServiceParseLink;
+
+extern OBJLIST<CAimProto> g_Instances;
+
+
+static int SingleHexToDecimal(TCHAR c)
+{
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+ return -1;
+}
+
+static TCHAR* url_decode(TCHAR* str)
+{
+ TCHAR* s = str, *d = str;
+
+ while(*s)
+ {
+ if (*s == '%')
+ {
+ int digit1 = SingleHexToDecimal(s[1]);
+ if (digit1 != -1)
+ {
+ int digit2 = SingleHexToDecimal(s[2]);
+ if (digit2 != -1)
+ {
+ s += 3;
+ *d++ = (TCHAR)((digit1 << 4) | digit2);
+ continue;
+ }
+ }
+ }
+ *d++ = *s++;
+ }
+
+ *d = 0;
+ return str;
+}
+
+static INT_PTR ServiceParseAimLink(WPARAM /*wParam*/,LPARAM lParam)
+{
+ if (lParam == 0) return 1; /* sanity check */
+
+ TCHAR *arg = (TCHAR*)lParam;
+
+ /* skip leading prefix */
+ arg = _tcschr(arg, ':');
+ if (arg == NULL) return 1; /* parse failed */
+
+ for (++arg; *arg == '/'; ++arg);
+
+ arg = NEWTSTR_ALLOCA(arg);
+
+ if (g_Instances.getCount() == 0) return 0;
+
+ CAimProto *proto = &g_Instances[0];
+ for (int i = 0; i < g_Instances.getCount(); ++i)
+ {
+ if (g_Instances[i].m_iStatus != ID_STATUS_OFFLINE && g_Instances[i].m_iStatus != ID_STATUS_CONNECTING)
+ {
+ proto = &g_Instances[i];
+ break;
+ }
+ }
+ if (proto == NULL) return 1;
+
+ /*
+ add user: aim:addbuddy?screenname=NICK&groupname=GROUP
+ send message: aim:goim?screenname=NICK&message=MSG
+ open chatroom: aim:gochat?roomname=ROOM&exchange=NUM
+ */
+ /* add a contact to the list */
+ if (!_tcsnicmp(arg, _T("addbuddy?"), 9))
+ {
+ TCHAR *tok, *tok2;
+ char *sn = NULL, *group = NULL;
+
+ for (tok = arg + 8; tok != NULL; tok = tok2)
+ {
+ tok2 = _tcschr(++tok, '&'); /* first token */
+ if (tok2) *tok2 = 0;
+ if (!_tcsnicmp(tok, _T("screenname="), 11) && *(tok + 11) != 0)
+ sn = mir_t2a(url_decode(tok + 11));
+ if (!_tcsnicmp(tok, _T("groupname="), 10) && *(tok + 10) != 0)
+ group = mir_utf8encodeT(url_decode(tok + 10)); /* group is currently ignored */
+ }
+ if (sn == NULL)
+ {
+ mir_free(group);
+ return 1;
+ }
+
+ if (!proto->contact_from_sn(sn)) /* does not yet check if sn is current user */
+ {
+ HANDLE hContact = proto->contact_from_sn(sn, true);
+ proto->add_contact_to_group(hContact, group && group[0] ? group : AIM_DEFAULT_GROUP);
+ }
+ mir_free(group);
+ mir_free(sn);
+ return 0;
+ }
+ /* send a message to a contact */
+ else if (!_tcsnicmp(arg, _T("goim?"), 5))
+ {
+ TCHAR *tok, *tok2, *msg = NULL;
+ char *sn = NULL;
+
+ for (tok = arg + 4; tok != NULL; tok = tok2)
+ {
+ tok2 = _tcschr(++tok, '&'); /* first token */
+ if (tok2) *tok2=0;
+ if (!_tcsnicmp(tok, _T("screenname="), 11) && *(tok + 11) != 0)
+ sn = mir_t2a(url_decode(tok + 11));
+ if (!_tcsnicmp(tok, _T("message="), 8) && *(tok + 8) != 0)
+ msg = url_decode(tok + 8);
+ }
+ if (sn == NULL) return 1; /* parse failed */
+
+ HANDLE hContact = proto->contact_from_sn(sn, true, true);
+ if (hContact)
+ CallService(MS_MSG_SENDMESSAGET, (WPARAM)hContact, (LPARAM)msg);
+
+ mir_free(sn);
+ return 0;
+ }
+ /* open a chatroom */
+ else if (!_tcsnicmp(arg, _T("gochat?"), 7))
+ {
+ TCHAR *tok, *tok2;
+ char *rm = NULL;
+ int exchange = 0;
+
+ for (tok = arg + 6; tok != NULL; tok = tok2)
+ {
+ tok2 = _tcschr(++tok, '&'); /* first token */
+ if (tok2) *tok2 = 0;
+ if (!_tcsnicmp(tok, _T("roomname="), 9) && *(tok + 9) != 0)
+ {
+ rm = mir_t2a(url_decode(tok + 9));
+ for (char *ch = rm; *ch; ++ch)
+ if (*ch == '+') *ch = ' ';
+ }
+ if (!_tcsnicmp(tok, _T("exchange="), 9))
+ exchange = _ttoi(tok + 9);
+ }
+ if (rm == NULL || exchange <= 0)
+ {
+ mir_free(rm);
+ return 1;
+ }
+
+ chatnav_param* par = new chatnav_param(rm, (unsigned short)exchange);
+ proto->ForkThread(&CAimProto::chatnav_request_thread, par);
+
+ mir_free(rm);
+ return 0;
+ }
+ return 1; /* parse failed */
+}
+
+void aim_links_init(void)
+{
+ static const char szService[] = "AIM/ParseAimLink";
+
+ hServiceParseLink = CreateServiceFunction(szService, ServiceParseAimLink);
+ AssocMgr_AddNewUrlTypeT("aim:", TranslateT("AIM Link Protocol"), hInstance, IDI_AOL, szService, 0);
+}
+
+void aim_links_destroy(void)
+{
+ DestroyServiceFunction(hServiceParseLink);
+}
diff --git a/protocols/AimOscar/src/links.h b/protocols/AimOscar/src/links.h
new file mode 100644
index 0000000000..2aac49447b
--- /dev/null
+++ b/protocols/AimOscar/src/links.h
@@ -0,0 +1,24 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef LINKS_H
+#define LINKS_H
+
+void aim_links_init();
+void aim_links_destroy();
+
+#endif
diff --git a/protocols/AimOscar/src/packets.cpp b/protocols/AimOscar/src/packets.cpp
new file mode 100644
index 0000000000..91065138fa
--- /dev/null
+++ b/protocols/AimOscar/src/packets.cpp
@@ -0,0 +1,123 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "packets.h"
+
+int aim_writesnac(unsigned short service, unsigned short subgroup,unsigned short &offset, char* out, unsigned short id)
+{
+ snac_header *snac = (snac_header*)&out[offset];
+ snac->service=_htons(service);
+ snac->subgroup=_htons(subgroup);
+ snac->flags=0;
+ snac->request_id[0]=_htons(id);
+ snac->request_id[1]=_htons(subgroup);
+ offset+=sizeof(snac_header);
+ return 0;
+}
+
+int aim_writetlv(unsigned short type,unsigned short length, const char* value,unsigned short &offset,char* out)
+{
+ TLV tlv(type,length,value);
+ offset += tlv.whole(&out[offset]);
+ return 0;
+}
+
+int aim_writetlvchar(unsigned short type, unsigned char value, unsigned short &offset, char* out)
+{
+ return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
+}
+
+
+int aim_writetlvshort(unsigned short type, unsigned short value, unsigned short &offset, char* out)
+{
+ value = _htons(value);
+ return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
+}
+
+
+int aim_writetlvlong(unsigned short type, unsigned long value, unsigned short &offset, char* out)
+{
+ value = _htonl(value);
+ return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
+}
+
+int aim_writetlvlong64(unsigned short type, unsigned __int64 value, unsigned short &offset, char* out)
+{
+ value = _htonl64(value);
+ return aim_writetlv(type, sizeof(value), (char*)&value, offset, out);
+}
+
+
+int CAimProto::aim_sendflap(HANDLE hServerConn, char type,unsigned short length,const char *buf, unsigned short &seqno)
+{
+ EnterCriticalSection(&SendingMutex);
+ const int slen = FLAP_SIZE + length;
+ char* obuf = (char*)alloca(slen);
+ flap_header *flap = (flap_header*)obuf;
+ flap->ast = '*';
+ flap->type = type;
+ flap->seqno = _htons(seqno++);
+ flap->len = _htons(length);
+ memcpy(&obuf[FLAP_SIZE], buf, length);
+ int rlen= Netlib_Send(hServerConn, obuf, slen, 0);
+ if (rlen == SOCKET_ERROR) seqno--;
+ LeaveCriticalSection(&SendingMutex);
+ return rlen >= 0 ? 0 : -1;
+}
+
+void aim_writefamily(const char *buf,unsigned short &offset,char* out)
+{
+ memcpy(&out[offset],buf,4);
+ offset+=4;
+}
+
+void aim_writechar(unsigned char val, unsigned short &offset,char* out)
+{
+ out[offset++] = val;
+}
+
+void aim_writeshort(unsigned short val, unsigned short &offset,char* out)
+{
+ out[offset++] = (char)(val >> 8);
+ out[offset++] = (char)(val & 0xFF);
+}
+
+void aim_writelong(unsigned long val, unsigned short &offset,char* out)
+{
+ out[offset++] = (char)(val >> 24);
+ out[offset++] = (char)((val >> 16) & 0xFF);
+ out[offset++] = (char)((val >> 8) & 0xFF);
+ out[offset++] = (char)(val & 0xFF);
+}
+
+void aim_writegeneric(unsigned short size,const char *buf,unsigned short &offset,char* out)
+{
+ memcpy(&out[offset],buf,size);
+ offset+=size;
+}
+
+void aim_writebartid(unsigned short type, unsigned char flags, unsigned short size,const char *buf,unsigned short &offset,char* out)
+{
+ out[offset++]=(unsigned char)(type >> 8);
+ out[offset++]=(unsigned char)(type & 0xff);
+ out[offset++]=flags;
+ out[offset++]=(char)size;
+ memcpy(&out[offset],buf,size);
+ offset+=size;
+}
diff --git a/protocols/AimOscar/src/packets.h b/protocols/AimOscar/src/packets.h
new file mode 100644
index 0000000000..e7c4de6cf0
--- /dev/null
+++ b/protocols/AimOscar/src/packets.h
@@ -0,0 +1,66 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2010 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef PACKETS_H
+#define PACKETS_H
+
+struct flap_header
+{
+ unsigned char ast;
+ unsigned char type;
+ unsigned short seqno;
+ unsigned short len;
+};
+struct snac_header
+{
+ unsigned short service;
+ unsigned short subgroup;
+ unsigned short flags;
+ unsigned short request_id[2];
+};
+
+inline unsigned short _htons(unsigned short s)
+{
+ return s>>8|s<<8;
+}
+
+inline unsigned long _htonl(unsigned long s)
+{
+ return s<<24|(s&0xff00)<<8|((s>>8)&0xff00)|s>>24;
+}
+
+inline unsigned __int64 _htonl64(unsigned __int64 s)
+{
+ return (unsigned __int64)_htonl(s & 0xffffffff) << 32 | _htonl(s >> 32);
+}
+
+
+int aim_writesnac(unsigned short service, unsigned short subgroup,unsigned short &offset,char* out, unsigned short id=0);
+int aim_writetlv(unsigned short type,unsigned short size, const char* value,unsigned short &offset,char* out);
+int aim_writetlvchar(unsigned short type, unsigned char value, unsigned short &offset, char* out);
+int aim_writetlvshort(unsigned short type, unsigned short value, unsigned short &offset, char* out);
+int aim_writetlvlong(unsigned short type, unsigned long value, unsigned short &offset, char* out);
+int aim_writetlvlong64(unsigned short type, unsigned __int64 value, unsigned short &offset, char* out);
+void aim_writefamily(const char *buf,unsigned short &offset,char* out);
+void aim_writegeneric(unsigned short size,const char *buf,unsigned short &offset,char* out);
+void aim_writebartid(unsigned short type, unsigned char flags, unsigned short size,const char *buf,unsigned short &offset,char* out);
+void aim_writechar(unsigned char val, unsigned short &offset,char* out);
+void aim_writeshort(unsigned short val, unsigned short &offset,char* out);
+void aim_writelong(unsigned long val, unsigned short &offset,char* out);
+
+#endif
diff --git a/protocols/AimOscar/src/popup.cpp b/protocols/AimOscar/src/popup.cpp
new file mode 100644
index 0000000000..96c2a936b4
--- /dev/null
+++ b/protocols/AimOscar/src/popup.cpp
@@ -0,0 +1,114 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+struct CAimPopupData
+{
+ CAimPopupData(CAimProto* _ppro, char* _url) :
+ ppro(_ppro),
+ url(mir_strdup(_url))
+ {}
+
+ ~CAimPopupData()
+ { mir_free(url); }
+
+ CAimProto* ppro;
+ char* url;
+};
+
+LRESULT CALLBACK PopupWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch(message)
+ {
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED)
+ {
+ CAimPopupData* p = (CAimPopupData*)PUGetPluginData(hWnd);
+ if (p->url != NULL)
+ ShellExecuteA(NULL, "open", p->url, NULL, NULL, SW_SHOW);
+
+ PUDeletePopUp(hWnd);
+ return 0;
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp(hWnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ CAimPopupData* p = (CAimPopupData*)PUGetPluginData(hWnd);
+ ReleaseIconEx("aim");
+ delete p;
+ break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void CAimProto::ShowPopup(const char* msg, int flags, char* url)
+{
+ POPUPDATAT ppd = {0};
+
+ mir_sntprintf(ppd.lptzContactName, SIZEOF(ppd.lptzContactName), TranslateT("%s Protocol"), m_tszUserName);
+
+ if (flags & ERROR_POPUP)
+ {
+ if (flags & TCHAR_POPUP)
+ {
+ char* errmsg = mir_t2a((TCHAR*)msg);
+ LOG(errmsg);
+ mir_free(errmsg);
+ }
+ else
+ LOG(msg);
+ }
+
+ TCHAR *msgt = (flags & TCHAR_POPUP) ? mir_tstrdup((TCHAR*)msg) : mir_a2t(msg);
+ mir_sntprintf(ppd.lptzText, SIZEOF(ppd.lptzText), _T("%s"), TranslateTS(msgt));
+ mir_free(msgt);
+
+ if (!ServiceExists(MS_POPUP_ADDPOPUPT))
+ {
+ if (flags & MAIL_POPUP)
+ {
+ size_t len = _tcslen(ppd.lptzText);
+ mir_sntprintf(&ppd.lptzText[len], SIZEOF(ppd.lptzText) - len, _T(" %s"), TranslateT("Open mail account?"));
+ if (MessageBox(NULL, ppd.lptzText, ppd.lptzContactName, MB_YESNO | MB_ICONINFORMATION) == IDYES)
+ ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOW);
+ }
+ else
+ {
+ MessageBox(NULL, ppd.lptzText, ppd.lptzContactName, MB_OK | MB_ICONINFORMATION);
+ }
+ }
+ else
+ {
+ ppd.PluginWindowProc = PopupWindowProc;
+ ppd.lchIcon = LoadIconEx("aim");
+ if (flags & MAIL_POPUP)
+ {
+ ppd.PluginData = new CAimPopupData(this, url);
+ ppd.iSeconds = -1;
+ }
+ else
+ ppd.PluginData = new CAimPopupData(this, NULL);
+
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
+ }
+}
diff --git a/protocols/AimOscar/src/proto.cpp b/protocols/AimOscar/src/proto.cpp
new file mode 100644
index 0000000000..09f7ba4ab1
--- /dev/null
+++ b/protocols/AimOscar/src/proto.cpp
@@ -0,0 +1,913 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+#include "m_genmenu.h"
+
+CAimProto::CAimProto(const char* aProtoName, const TCHAR* aUserName)
+ : chat_rooms(5)
+{
+ m_iVersion = 2;
+ m_tszUserName = mir_tstrdup(aUserName);
+ m_szModuleName = mir_strdup(aProtoName);
+ m_szProtoName = mir_strdup(aProtoName);
+ _strlwr(m_szProtoName);
+ m_szProtoName[0] = (char)toupper(m_szProtoName[0]);
+ LOG("Setting protocol/module name to '%s/%s'", m_szProtoName, m_szModuleName);
+
+ //create some events
+ hAvatarEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ hChatNavEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ hAdminEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ InitializeCriticalSection(&SendingMutex);
+ InitializeCriticalSection(&connMutex);
+
+ CreateProtoService(PS_CREATEACCMGRUI, &CAimProto::SvcCreateAccMgrUI);
+
+ CreateProtoService(PS_GETMYAWAYMSG, &CAimProto::GetMyAwayMsg);
+
+ CreateProtoService(PS_GETAVATARINFOT, &CAimProto::GetAvatarInfo);
+ CreateProtoService(PS_GETMYAVATART, &CAimProto::GetAvatar);
+ CreateProtoService(PS_SETMYAVATART, &CAimProto::SetAvatar);
+ CreateProtoService(PS_GETAVATARCAPS, &CAimProto::GetAvatarCaps);
+
+ CreateProtoService(PS_JOINCHAT, &CAimProto::OnJoinChat);
+ CreateProtoService(PS_LEAVECHAT, &CAimProto::OnLeaveChat);
+
+ HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CAimProto::OnPreBuildContactMenu);
+ HookProtoEvent(ME_CLIST_GROUPCHANGE, &CAimProto::OnGroupChange);
+ HookProtoEvent(ME_OPT_INITIALISE, &CAimProto::OnOptionsInit);
+
+ init_custom_folders();
+ offline_contacts();
+
+ TCHAR descr[MAX_PATH];
+
+ NETLIBUSER nlu = {0};
+ nlu.cbSize = sizeof(nlu);
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR;
+ nlu.szSettingsModule = m_szModuleName;
+ mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName);
+ nlu.ptszDescriptiveName = descr;
+ hNetlib = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+
+ char szP2P[128];
+ mir_snprintf(szP2P, sizeof(szP2P), "%sP2P", m_szModuleName);
+ nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_TCHAR;
+ mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s Client-to-client connection"), m_tszUserName);
+ nlu.szSettingsModule = szP2P;
+ nlu.minIncomingPorts = 1;
+ hNetlibPeer = (HANDLE) CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+}
+
+CAimProto::~CAimProto()
+{
+ RemoveMainMenus();
+ RemoveContactMenus();
+
+ if(hServerConn)
+ Netlib_CloseHandle(hServerConn);
+ if(hAvatarConn && hAvatarConn != (HANDLE)1)
+ Netlib_CloseHandle(hAvatarConn);
+ if(hChatNavConn && hChatNavConn != (HANDLE)1)
+ Netlib_CloseHandle(hChatNavConn);
+ if(hAdminConn && hAdminConn != (HANDLE)1)
+ Netlib_CloseHandle(hAdminConn);
+
+ close_chat_conn();
+
+ Netlib_CloseHandle(hNetlib);
+ Netlib_CloseHandle(hNetlibPeer);
+
+ DeleteCriticalSection(&SendingMutex);
+ DeleteCriticalSection(&connMutex);
+
+ CloseHandle(hAvatarEvent);
+ CloseHandle(hChatNavEvent);
+ CloseHandle(hAdminEvent);
+
+ ft_list.destroy();
+
+ for (int i=0; i<9; ++i)
+ mir_free(modeMsgs[i]);
+
+ mir_free(pref2_flags);
+ mir_free(pref2_set_flags);
+
+ mir_free(COOKIE);
+ mir_free(MAIL_COOKIE);
+ mir_free(AVATAR_COOKIE);
+ mir_free(CHATNAV_COOKIE);
+ mir_free(ADMIN_COOKIE);
+ mir_free(username);
+
+ mir_free(m_szModuleName);
+ mir_free(m_tszUserName);
+ mir_free(m_szProtoName);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// OnModulesLoadedEx - performs hook registration
+
+int CAimProto::OnModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ HookProtoEvent(ME_USERINFO_INITIALISE, &CAimProto::OnUserInfoInit);
+ HookProtoEvent(ME_IDLE_CHANGED, &CAimProto::OnIdleChanged);
+ HookProtoEvent(ME_MSG_WINDOWEVENT, &CAimProto::OnWindowEvent);
+
+ chat_register();
+ InitContactMenus();
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// AddToList - adds a contact to the contact list
+
+HANDLE CAimProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
+{
+ if (state != 1) return 0;
+ TCHAR *id = psr->id ? psr->id : psr->nick;
+ char *sn = psr->flags & PSR_UNICODE ? mir_u2a((wchar_t*)id) : mir_strdup((char*)id);
+ HANDLE hContact = contact_from_sn(sn, true, (flags & PALF_TEMPORARY) != 0);
+ mir_free(sn);
+ return hContact; //See authrequest for serverside addition
+}
+
+HANDLE __cdecl CAimProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent)
+{
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// AuthAllow - processes the successful authorization
+
+int CAimProto::Authorize(HANDLE hDbEvent)
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// AuthDeny - handles the unsuccessful authorization
+
+int CAimProto::AuthDeny(HANDLE hDbEvent, const TCHAR* szReason)
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// PSR_AUTH
+
+int __cdecl CAimProto::AuthRecv(HANDLE hContact, PROTORECVEVENT* evt)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// PSS_AUTHREQUEST
+
+int __cdecl CAimProto::AuthRequest(HANDLE hContact, const TCHAR* szMessage)
+{
+ //Not a real authrequest- only used b/c we don't know the group until now.
+ if (state != 1)
+ return 1;
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0])
+ {
+ add_contact_to_group(hContact, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// ChangeInfo
+
+HANDLE __cdecl CAimProto::ChangeInfo(int iInfoType, void* pInfoData)
+{
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// FileAllow - starts a file transfer
+
+HANDLE __cdecl CAimProto::FileAllow(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath)
+{
+ file_transfer *ft = (file_transfer*)hTransfer;
+ if (ft && ft_list.find_by_ft(ft))
+ {
+ char *path = mir_utf8encodeT(szPath);
+
+ if (ft->pfts.totalFiles > 1 && ft->file[0])
+ {
+ size_t path_len = strlen(path);
+ size_t len = strlen(ft->file) + 2;
+
+ path = (char*)mir_realloc(path, path_len + len);
+ mir_snprintf(&path[path_len], len, "%s\\", ft->file);
+ }
+
+ mir_free(ft->file);
+ ft->file = path;
+
+ ForkThread(&CAimProto::accept_file_thread, ft);
+ return ft;
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// FileCancel - cancels a file transfer
+
+int __cdecl CAimProto::FileCancel(HANDLE hContact, HANDLE hTransfer)
+{
+ file_transfer *ft = (file_transfer*)hTransfer;
+ if (!ft_list.find_by_ft(ft)) return 0;
+
+ LOG("We are cancelling a file transfer.");
+
+ aim_chat_deny(hServerConn, seqno, ft->sn, ft->icbm_cookie);
+
+ if (ft->hConn)
+ {
+ Netlib_Shutdown(ft->hConn);
+ SetEvent(ft->hResumeEvent);
+ }
+ else
+ ft_list.remove_by_ft(ft);
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// FileDeny - denies a file transfer
+
+int __cdecl CAimProto::FileDeny(HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* /*szReason*/)
+{
+ file_transfer *ft = (file_transfer*)hTransfer;
+ if (!ft_list.find_by_ft(ft)) return 0;
+
+ LOG("We are denying a file transfer.");
+
+ aim_chat_deny(hServerConn, seqno, ft->sn, ft->icbm_cookie);
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// FileResume - processes file renaming etc
+
+int __cdecl CAimProto::FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename)
+{
+ file_transfer *ft = (file_transfer*)hTransfer;
+ if (!ft_list.find_by_ft(ft)) return 0;
+
+ switch (*action)
+ {
+ case FILERESUME_RESUME:
+ {
+ struct _stati64 statbuf;
+ _tstati64(ft->pfts.tszCurrentFile, &statbuf);
+ ft->pfts.currentFileProgress = statbuf.st_size;
+ }
+ break;
+
+ case FILERESUME_RENAME:
+ mir_free(ft->pfts.tszCurrentFile);
+ ft->pfts.tszCurrentFile = mir_tstrdup(*szFilename);
+ break;
+
+ case FILERESUME_OVERWRITE:
+ ft->pfts.currentFileProgress = 0;
+ break;
+
+ case FILERESUME_SKIP:
+ mir_free(ft->pfts.tszCurrentFile);
+ ft->pfts.tszCurrentFile = NULL;
+ break;
+
+ default:
+ aim_file_ad(hServerConn, seqno, ft->sn, ft->icbm_cookie, true, ft->max_ver);
+ break;
+ }
+ SetEvent(ft->hResumeEvent);
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// GetCaps - return protocol capabilities bits
+
+DWORD_PTR __cdecl CAimProto::GetCaps(int type, HANDLE hContact)
+{
+ switch (type)
+ {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_MODEMSG | PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_FILE;
+
+ case PFLAGNUM_2:
+#ifdef ALLOW_BUSY
+ return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_ONTHEPHONE | PF2_LIGHTDND;
+#else
+ return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_ONTHEPHONE;
+#endif
+
+ case PFLAGNUM_3:
+#ifdef ALLOW_BUSY
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE | PF2_LIGHTDND;
+#else
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE;
+#endif
+
+ case PFLAGNUM_4:
+ return PF4_SUPPORTTYPING | PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_FORCEADDED |
+ PF4_SUPPORTIDLE | PF4_AVATARS | PF4_IMSENDUTF | PF4_IMSENDOFFLINE;
+
+ case PFLAGNUM_5:
+ return PF2_ONTHEPHONE;
+
+ case PFLAG_MAXLENOFMESSAGE:
+ return MAX_MESSAGE_LENGTH;
+
+ case PFLAG_UNIQUEIDTEXT:
+ return (DWORD_PTR) "Screen Name";
+
+ case PFLAG_UNIQUEIDSETTING:
+ return (DWORD_PTR) AIM_KEY_SN;
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// GetIcon - loads an icon for the contact list
+
+HICON __cdecl CAimProto::GetIcon(int iconIndex)
+{
+ if (LOWORD(iconIndex) == PLI_PROTOCOL)
+ {
+ if (iconIndex & PLIF_ICOLIBHANDLE)
+ return (HICON)GetIconHandle("aim");
+
+ bool big = (iconIndex & PLIF_SMALL) == 0;
+ HICON hIcon = LoadIconEx("aim", big);
+
+ if (iconIndex & PLIF_ICOLIB)
+ return hIcon;
+
+ hIcon = CopyIcon(hIcon);
+ ReleaseIconEx("aim", big);
+ return hIcon;
+ }
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// GetInfo - retrieves a contact info
+
+int __cdecl CAimProto::GetInfo(HANDLE hContact, int infoType)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SearchBasic - searches the contact by JID
+
+void __cdecl CAimProto::basic_search_ack_success(void* p)
+{
+ char *sn = normalize_name((char*)p);
+ if (sn) // normalize it
+ {
+ if (strlen(sn) > 32)
+ {
+ sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ }
+ else
+ {
+ PROTOSEARCHRESULT psr = {0};
+ psr.cbSize = sizeof(psr);
+ psr.id = (TCHAR*)sn;
+ sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr);
+ sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ }
+ }
+ mir_free(sn);
+ mir_free(p);
+}
+
+HANDLE __cdecl CAimProto::SearchBasic(const PROTOCHAR* szId)
+{
+ if (state != 1)
+ return 0;
+
+ //duplicating the parameter so that it isn't deleted before it's needed- e.g. this function ends before it's used
+ ForkThread(&CAimProto::basic_search_ack_success, mir_t2a(szId));
+ return (HANDLE)1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SearchByEmail - searches the contact by its e-mail
+
+HANDLE __cdecl CAimProto::SearchByEmail(const PROTOCHAR* email)
+{
+ // Maximum email size should really be 320, but the char string is limited to 255.
+ if (state != 1 || email == NULL || _tcslen(email) >= 254)
+ return NULL;
+
+ char* szEmail = mir_t2a(email);
+ aim_search_by_email(hServerConn, seqno, szEmail);
+ mir_free(szEmail);
+ return (HANDLE)1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SearchByName - searches the contact by its first or last name, or by a nickname
+
+HANDLE __cdecl CAimProto::SearchByName(const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName)
+{
+ return NULL;
+}
+
+HWND __cdecl CAimProto::SearchAdvanced(HWND owner)
+{
+ return NULL;
+}
+
+HWND __cdecl CAimProto::CreateExtendedSearchUI(HWND owner)
+{
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// RecvContacts
+
+int __cdecl CAimProto::RecvContacts(HANDLE hContact, PROTORECVEVENT*)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// RecvFile
+
+int __cdecl CAimProto::RecvFile(HANDLE hContact, PROTOFILEEVENT* evt)
+{
+ return Proto_RecvFile(hContact, evt);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// RecvMsg
+
+int __cdecl CAimProto::RecvMsg(HANDLE hContact, PROTORECVEVENT* pre)
+{
+ char *omsg = pre->szMessage;
+ char *bbuf = NULL;
+ if (getByte(AIM_KEY_FI, 1))
+ {
+ LOG("Converting from html to bbcodes then stripping leftover html.");
+ pre->szMessage = bbuf = html_to_bbcodes(pre->szMessage);
+ }
+ LOG("Stripping html.");
+ html_decode(pre->szMessage);
+
+ INT_PTR res = Proto_RecvMessage(hContact, pre);
+ mir_free(bbuf);
+ pre->szMessage = omsg;
+ return ( int )res;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// RecvUrl
+
+int __cdecl CAimProto::RecvUrl(HANDLE hContact, PROTORECVEVENT*)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SendContacts
+
+int __cdecl CAimProto::SendContacts(HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SendFile - sends a file
+
+HANDLE __cdecl CAimProto::SendFile(HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles)
+{
+ if (state != 1) return 0;
+
+ if (hContact && szDescription && ppszFiles)
+ {
+ DBVARIANT dbv;
+ if (!getString(hContact, AIM_KEY_SN, &dbv))
+ {
+ file_transfer *ft = new file_transfer(hContact, dbv.pszVal, NULL);
+
+ bool isDir = false;
+ int count = 0;
+ while (ppszFiles[count] != NULL)
+ {
+ struct _stati64 statbuf;
+ if (_tstati64(ppszFiles[count++], &statbuf) == 0)
+ {
+ if (statbuf.st_mode & _S_IFDIR)
+ {
+ if (ft->pfts.totalFiles == 0) isDir = true;
+ }
+ else
+ {
+ ft->pfts.totalBytes += statbuf.st_size;
+ ++ft->pfts.totalFiles;
+ }
+ }
+ }
+
+ if (ft->pfts.totalFiles == 0)
+ {
+ delete ft;
+ return NULL;
+ }
+
+ ft->pfts.flags |= PFTS_SENDING;
+ ft->pfts.ptszFiles = ppszFiles;
+
+ ft->file = ft->pfts.totalFiles == 1 || isDir ? mir_utf8encodeT(ppszFiles[0]) : (char*)mir_calloc(1);
+ ft->sending = true;
+ ft->message = szDescription[0] ? mir_utf8encodeT(szDescription) : NULL;
+ ft->me_force_proxy = getByte(AIM_KEY_FP, 0) != 0;
+ ft->requester = true;
+
+ ft_list.insert(ft);
+
+ if (ft->me_force_proxy)
+ {
+ LOG("We are forcing a proxy file transfer.");
+ ForkThread(&CAimProto::accept_file_thread, ft);
+ }
+ else
+ {
+ ft->listen(this);
+ aim_send_file(hServerConn, seqno, detected_ip, ft->local_port, false, ft);
+ }
+
+ DBFreeVariant(&dbv);
+
+ return ft;
+ }
+ }
+
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SendMessage - sends a message
+
+void __cdecl CAimProto::msg_ack_success(void* param)
+{
+ msg_ack_param *msg_ack = (msg_ack_param*)param;
+
+ Sleep(150);
+ sendBroadcast(msg_ack->hContact, ACKTYPE_MESSAGE,
+ msg_ack->success ? ACKRESULT_SUCCESS : ACKRESULT_FAILED,
+ (HANDLE)msg_ack->id, (LPARAM)msg_ack->msg);
+
+ mir_free(msg_ack);
+}
+
+
+int __cdecl CAimProto::SendMsg(HANDLE hContact, int flags, const char* pszSrc)
+{
+ if (pszSrc == NULL) return 0;
+
+ if (state != 1)
+ {
+ msg_ack_param *msg_ack = (msg_ack_param*)mir_calloc(sizeof(msg_ack_param));
+ msg_ack->hContact = hContact;
+ msg_ack->msg = "Message cannot be sent, when protocol offline";
+ ForkThread(&CAimProto::msg_ack_success, msg_ack);
+ }
+
+ char *sn = getSetting(hContact, AIM_KEY_SN);
+ if (sn == NULL)
+ {
+ msg_ack_param *msg_ack = (msg_ack_param*)mir_calloc(sizeof(msg_ack_param));
+ msg_ack->hContact = hContact;
+ msg_ack->msg = "Screen Name for the contact not available";
+ ForkThread(&CAimProto::msg_ack_success, msg_ack);
+ }
+
+ char* msg;
+ if (flags & PREF_UNICODE)
+ {
+ const char* p = strchr(pszSrc, '\0');
+ if (p != pszSrc)
+ {
+ while (*(++p) == '\0');
+ }
+ msg = mir_utf8encodeW((wchar_t*)p);
+ }
+ else if (flags & PREF_UTF)
+ msg = mir_strdup(pszSrc);
+ else
+ msg = mir_utf8encode(pszSrc);
+
+ char* smsg = html_encode(msg);
+ mir_free(msg);
+
+ if (getByte(AIM_KEY_FO, 1))
+ {
+ msg = bbcodes_to_html(smsg);
+ mir_free(smsg);
+ }
+ else
+ msg = smsg;
+
+ bool blast = getBool(hContact, AIM_KEY_BLS, false);
+ int res = aim_send_message(hServerConn, seqno, sn, msg, false, blast);
+
+ mir_free(msg);
+ mir_free(sn);
+
+ if (!res || blast || 0 == getByte(AIM_KEY_DC, 1))
+ {
+ msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param));
+ msg_ack->hContact = hContact;
+ msg_ack->msg = NULL;
+ msg_ack->id = res;
+ msg_ack->success = res != 0;
+ ForkThread(&CAimProto::msg_ack_success, msg_ack);
+ }
+
+ return res;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SendUrl
+
+int __cdecl CAimProto::SendUrl(HANDLE hContact, int flags, const char* url)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SetApparentMode - sets the visibility m_iStatus
+
+int __cdecl CAimProto::SetApparentMode(HANDLE hContact, int mode)
+{
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SetStatus - sets the protocol m_iStatus
+
+int __cdecl CAimProto::SetStatus(int iNewStatus)
+{
+ switch (iNewStatus)
+ {
+ case ID_STATUS_FREECHAT:
+ iNewStatus = ID_STATUS_ONLINE;
+ break;
+
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ case ID_STATUS_ONTHEPHONE:
+#ifdef ALLOW_BUSY
+ iNewStatus = ID_STATUS_OCCUPIED;
+ break;
+#endif
+
+ case ID_STATUS_OUTTOLUNCH:
+ case ID_STATUS_NA:
+ iNewStatus = ID_STATUS_AWAY;
+ break;
+ }
+
+ if (iNewStatus == m_iStatus)
+ return 0;
+
+ if (iNewStatus == ID_STATUS_OFFLINE)
+ {
+ broadcast_status(ID_STATUS_OFFLINE);
+ return 0;
+ }
+
+ m_iDesiredStatus = iNewStatus;
+ if (m_iStatus == ID_STATUS_OFFLINE)
+ {
+ broadcast_status(ID_STATUS_CONNECTING);
+ ForkThread(&CAimProto::start_connection, (void*)iNewStatus);
+ }
+ else if (m_iStatus > ID_STATUS_OFFLINE)
+ {
+ switch(iNewStatus)
+ {
+ case ID_STATUS_ONLINE:
+ aim_set_status(hServerConn, seqno, AIM_STATUS_ONLINE);
+ broadcast_status(ID_STATUS_ONLINE);
+ break;
+
+ case ID_STATUS_INVISIBLE:
+ aim_set_status(hServerConn, seqno, AIM_STATUS_INVISIBLE);
+ broadcast_status(ID_STATUS_INVISIBLE);
+ break;
+
+ case ID_STATUS_OCCUPIED:
+ aim_set_status(hServerConn, seqno, AIM_STATUS_BUSY | AIM_STATUS_AWAY);
+ broadcast_status(ID_STATUS_OCCUPIED);
+ break;
+
+ case ID_STATUS_AWAY:
+ aim_set_status(hServerConn, seqno, AIM_STATUS_AWAY);
+ broadcast_status(ID_STATUS_AWAY);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// GetAwayMsg - returns a contact's away message
+
+void __cdecl CAimProto::get_online_msg_thread(void* arg)
+{
+ Sleep(150);
+
+ const HANDLE hContact = arg;
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, MOD_KEY_CL, OTH_KEY_SM, &dbv)) {
+ sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ else sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)0);
+}
+
+HANDLE __cdecl CAimProto::GetAwayMsg(HANDLE hContact)
+{
+ if (state != 1)
+ return 0;
+
+ int status = getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE);
+ switch (status) {
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONLINE:
+ ForkThread(&CAimProto::get_online_msg_thread, hContact);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return (HANDLE)1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// PSR_AWAYMSG
+
+int __cdecl CAimProto::RecvAwayMsg(HANDLE hContact, int statusMode, PROTORECVEVENT* pre)
+{
+ sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)pre->szMessage);
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// PSS_AWAYMSG
+
+int __cdecl CAimProto::SendAwayMsg(HANDLE hContact, HANDLE hProcess, const char* msg)
+{
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SetAwayMsg - sets the away m_iStatus message
+
+int __cdecl CAimProto::SetAwayMsg(int status, const TCHAR* msg)
+{
+ char** msgptr = get_status_msg_loc(status);
+ if (msgptr == NULL) return 1;
+
+ char* nmsg = mir_utf8encodeT(msg);
+ mir_free(*msgptr); *msgptr = nmsg;
+
+ switch (status)
+ {
+ case ID_STATUS_FREECHAT:
+ status = ID_STATUS_ONLINE;
+ break;
+
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ case ID_STATUS_ONTHEPHONE:
+#ifdef ALLOW_BUSY
+ status = ID_STATUS_OCCUPIED;
+ break;
+#endif
+
+ case ID_STATUS_OUTTOLUNCH:
+ case ID_STATUS_NA:
+ status = ID_STATUS_AWAY;
+ break;
+ }
+
+ if (state == 1 && status == m_iStatus)
+ {
+ if (!_strcmps(last_status_msg, nmsg))
+ return 0;
+
+ mir_free(last_status_msg);
+ last_status_msg = mir_strdup(nmsg);
+ aim_set_statusmsg(hServerConn, seqno, nmsg);
+ aim_set_away(hServerConn, seqno, nmsg,
+ status == ID_STATUS_AWAY || status == ID_STATUS_OCCUPIED);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// UserIsTyping - sends a UTN notification
+
+int __cdecl CAimProto::UserIsTyping(HANDLE hContact, int type)
+{
+ if (state != 1) return 0;
+
+ if (getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE)
+ return 0;
+
+ DBVARIANT dbv;
+ if (!getBool(hContact, AIM_KEY_BLS, false) && !getString(hContact, AIM_KEY_SN, &dbv))
+ {
+ if (type == PROTOTYPE_SELFTYPING_ON)
+ aim_typing_notification(hServerConn, seqno, dbv.pszVal, 0x0002);
+ else if (type == PROTOTYPE_SELFTYPING_OFF)
+ aim_typing_notification(hServerConn, seqno, dbv.pszVal, 0x0000);
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnEvent - maintain protocol events
+
+int __cdecl CAimProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam)
+{
+ switch (eventType)
+ {
+ case EV_PROTO_ONLOAD:
+ return OnModulesLoaded(0, 0);
+
+// case EV_PROTO_ONEXIT:
+// return OnPreShutdown(0, 0);
+
+ case EV_PROTO_ONMENU:
+ InitMainMenus();
+ break;
+
+ case EV_PROTO_ONOPTIONS:
+ return OnOptionsInit(wParam, lParam);
+
+ case EV_PROTO_ONERASE:
+ {
+ char szDbsettings[64];
+ mir_snprintf(szDbsettings, sizeof(szDbsettings), "%sP2P", m_szModuleName);
+ CallService(MS_DB_MODULE_DELETE, 0, (LPARAM)szDbsettings);
+ break;
+ }
+
+ case EV_PROTO_ONRENAME:
+ if (hMenuRoot)
+ {
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof(CLISTMENUITEM);
+ clmi.flags = CMIM_NAME | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
+ clmi.ptszName = m_tszUserName;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuRoot, (LPARAM)&clmi);
+ }
+ break;
+
+ case EV_PROTO_ONCONTACTDELETED:
+ return OnContactDeleted(wParam, lParam);
+
+ case EV_PROTO_DBSETTINGSCHANGED:
+ return OnDbSettingChanged(wParam, lParam);
+ }
+ return 1;
+}
diff --git a/protocols/AimOscar/src/proto.h b/protocols/AimOscar/src/proto.h
new file mode 100644
index 0000000000..bb4dc3c601
--- /dev/null
+++ b/protocols/AimOscar/src/proto.h
@@ -0,0 +1,502 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _AIM_PROTO_H_
+#define _AIM_PROTO_H_
+
+#include "m_protoint.h"
+
+struct CAimProto;
+typedef void ( __cdecl CAimProto::*AimThreadFunc )( void* );
+typedef int ( __cdecl CAimProto::*AimEventFunc )( WPARAM, LPARAM );
+typedef INT_PTR ( __cdecl CAimProto::*AimServiceFunc )( WPARAM, LPARAM );
+typedef INT_PTR ( __cdecl CAimProto::*AimServiceFuncParam )( WPARAM, LPARAM, LPARAM );
+
+struct CAimProto : public PROTO_INTERFACE, public MZeroedObject
+{
+ CAimProto( const char*, const TCHAR* );
+ ~CAimProto();
+
+ //====================================================================================
+ // PROTO_INTERFACE
+ //====================================================================================
+
+ virtual HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr );
+ virtual HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent );
+
+ virtual int __cdecl Authorize( HANDLE hDbEvent );
+ virtual int __cdecl AuthDeny( HANDLE hDbEvent, const TCHAR* szReason );
+ virtual int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* );
+ virtual int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage );
+
+ virtual HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData );
+
+ virtual HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath );
+ virtual int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer );
+ virtual int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason );
+ virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const PROTOCHAR** szFilename );
+
+ virtual DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact = NULL );
+ virtual HICON __cdecl GetIcon( int iconIndex );
+ virtual int __cdecl GetInfo( HANDLE hContact, int infoType );
+
+ virtual HANDLE __cdecl SearchBasic( const PROTOCHAR* id );
+ virtual HANDLE __cdecl SearchByEmail( const PROTOCHAR* email );
+ virtual HANDLE __cdecl SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName );
+ virtual HWND __cdecl SearchAdvanced( HWND owner );
+ virtual HWND __cdecl CreateExtendedSearchUI( HWND owner );
+
+ virtual int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* );
+ virtual int __cdecl RecvFile( HANDLE hContact, PROTOFILEEVENT* );
+ virtual int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* );
+ virtual int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* );
+
+ virtual int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList );
+ virtual HANDLE __cdecl SendFile( HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles );
+ virtual int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg );
+ virtual int __cdecl SendUrl( HANDLE hContact, int flags, const char* url );
+
+ virtual int __cdecl SetApparentMode( HANDLE hContact, int mode );
+ virtual int __cdecl SetStatus( int iNewStatus );
+
+ virtual HANDLE __cdecl GetAwayMsg( HANDLE hContact );
+ virtual int __cdecl RecvAwayMsg( HANDLE hContact, int mode, PROTORECVEVENT* evt );
+ virtual int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg );
+ virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg );
+
+ virtual int __cdecl UserIsTyping( HANDLE hContact, int type );
+
+ virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam );
+
+ //====| Services |====================================================================
+ INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam);
+
+ INT_PTR __cdecl GetAvatarInfo(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl GetMyAwayMsg(WPARAM wParam,LPARAM lParam);
+
+ INT_PTR __cdecl GetAvatar(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl SetAvatar(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl GetAvatarCaps(WPARAM wParam, LPARAM lParam);
+
+ INT_PTR __cdecl ManageAccount(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl InstantIdle(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl JoinChatUI(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl GetHTMLAwayMsg(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl GetProfile(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl EditProfile(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl AddToServerList(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl BlockBuddy(WPARAM wParam, LPARAM lParam);
+
+ INT_PTR __cdecl OnJoinChat(WPARAM wParam, LPARAM lParam);
+ INT_PTR __cdecl OnLeaveChat(WPARAM wParam, LPARAM lParam);
+
+ //====| Events |======================================================================
+ int __cdecl OnContactDeleted(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnGroupChange(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnIdleChanged(WPARAM wParam, LPARAM lParam);
+ int __cdecl OnWindowEvent(WPARAM wParam, LPARAM lParam);
+ int __cdecl OnModulesLoaded( WPARAM wParam, LPARAM lParam );
+ int __cdecl OnOptionsInit(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnPreBuildContactMenu(WPARAM wParam,LPARAM lParam);
+// int __cdecl OnPreShutdown(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnDbSettingChanged(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnUserInfoInit(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnGCEvent(WPARAM wParam,LPARAM lParam);
+ int __cdecl OnGCMenuHook(WPARAM wParam,LPARAM lParam);
+
+ //====| Data |========================================================================
+ CRITICAL_SECTION SendingMutex;
+ CRITICAL_SECTION connMutex;
+
+ char* COOKIE;
+ int COOKIE_LENGTH;
+ char* MAIL_COOKIE;
+ int MAIL_COOKIE_LENGTH;
+ char* AVATAR_COOKIE;
+ int AVATAR_COOKIE_LENGTH;
+ char* CHATNAV_COOKIE;
+ int CHATNAV_COOKIE_LENGTH;
+ char* ADMIN_COOKIE;
+ int ADMIN_COOKIE_LENGTH;
+
+ char *username;
+ unsigned short seqno;//main connection sequence number
+ int state;//m_iStatus of the connection; e.g. whether connected or not
+ unsigned short port;
+
+ //Some bools to keep track of different things
+ bool request_HTML_profile;
+ bool request_away_message;
+ bool extra_icons_loaded;
+ bool idle;
+ bool instantidle;
+ bool list_received;
+
+ //Some main connection stuff
+ HANDLE hServerConn;//handle to the main connection
+ HANDLE hNetlib;//handle to netlib
+ unsigned long internal_ip; // our ip
+ unsigned long detected_ip; // our ip
+ unsigned short local_port; // our port
+
+ //Peer connection stuff
+ HANDLE hNetlibPeer;//handle to the peer netlib
+ HANDLE hDirectBoundPort;//direct connection listening port
+
+ //Handles for the context menu items
+ HGENMENU hMenuRoot;
+ HGENMENU hHTMLAwayContextMenuItem;
+ HGENMENU hAddToServerListContextMenuItem;
+ HGENMENU hReadProfileMenuItem;
+ HGENMENU hBlockContextMenuItem;
+ HGENMENU hMainMenu[3];
+
+ //Some mail connection stuff
+ HANDLE hMailConn;
+ unsigned short mail_seqno;
+
+ //avatar connection stuff
+ bool init_cst_fld_ran;
+ unsigned short avatar_seqno;
+ unsigned short avatar_id_sm;
+ unsigned short avatar_id_lg;
+ HANDLE hAvatarConn;
+ HANDLE hAvatarEvent;
+ HANDLE hAvatarsFolder;
+
+ ft_list_type ft_list;
+
+ //chatnav connection stuff
+ unsigned short chatnav_seqno;
+ HANDLE hChatNavConn;
+ HANDLE hChatNavEvent;
+ char MAX_ROOMS;
+
+ OBJLIST<chat_list_item> chat_rooms;
+
+ //admin connection stuff
+ unsigned short admin_seqno;
+ HANDLE hAdminConn;
+ HANDLE hAdminEvent;
+
+ // privacy settings
+ unsigned long pd_flags;
+ unsigned short pd_info_id;
+ char pd_mode;
+
+ // prefernces
+ unsigned short pref1_id;
+ unsigned long pref1_flags;
+ unsigned long pref1_set_flags;
+ unsigned long pref2_len;
+ unsigned long pref2_set_len;
+ char *pref2_flags;
+ char *pref2_set_flags;
+
+ BdList allow_list;
+ BdList block_list;
+
+ BdList group_list;
+
+ //away message retrieval stuff
+ char *modeMsgs[9];
+ char *last_status_msg;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // avatars.cpp
+
+ char *hash_sm, *hash_lg;
+
+ void __cdecl avatar_request_thread( void* param );
+ void __cdecl avatar_upload_thread( void* param );
+
+ void avatar_request_handler(HANDLE hContact, char* hash, unsigned char type);
+ void avatar_retrieval_handler(const char* sn, const char* hash, const char* data, int data_len);
+ int get_avatar_filename(HANDLE hContact, TCHAR* pszDest, size_t cbLen, const TCHAR *ext);
+ void init_custom_folders(void);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // away.cpp
+
+ void __cdecl get_online_msg_thread( void* arg );
+
+ int aim_set_away(HANDLE hServerConn, unsigned short &seqno, const char *msg, bool set);//user info
+ int aim_set_statusmsg(HANDLE hServerConn,unsigned short &seqno,const char *msg);//user info
+ int aim_set_status(HANDLE hServerConn,unsigned short &seqno,unsigned long status_type);
+ int aim_query_away_message(HANDLE hServerConn,unsigned short &seqno,const char* sn);
+
+ char** get_status_msg_loc(int status);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // chat.cpp
+
+ void __cdecl chatnav_request_thread( void* param );
+
+ void chat_register(void);
+ void chat_start(const char* id, unsigned short exchange);
+ void chat_event(const char* id, const char* sn, int evt, const TCHAR* msg = NULL);
+ void chat_leave(const char* id);
+
+ chat_list_item* find_chat_by_cid(unsigned short cid);
+ chat_list_item* find_chat_by_id(char* id);
+ chat_list_item* find_chat_by_conn(HANDLE conn);
+ void remove_chat_by_ptr(chat_list_item* item);
+ void shutdown_chat_conn(void);
+ void close_chat_conn(void);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // client.cpp
+
+ int aim_send_connection_packet(HANDLE hServerConn,unsigned short &seqno,char *buf);
+ int aim_authkey_request(HANDLE hServerConn,unsigned short &seqno);
+ int aim_auth_request(HANDLE hServerConn,unsigned short &seqno,const char* key,const char* language,
+ const char* country, const char* username, const char* password);
+ int aim_send_cookie(HANDLE hServerConn,unsigned short &seqno,int cookie_size,char * cookie);
+ int aim_send_service_request(HANDLE hServerConn,unsigned short &seqno);
+ int aim_new_service_request(HANDLE hServerConn,unsigned short &seqno,unsigned short service);
+ int aim_request_rates(HANDLE hServerConn,unsigned short &seqno);
+ int aim_request_icbm(HANDLE hServerConn,unsigned short &seqno);
+ int aim_request_offline_msgs(HANDLE hServerConn,unsigned short &seqno);
+ int aim_set_icbm(HANDLE hServerConn,unsigned short &seqno);
+ int aim_set_profile(HANDLE hServerConn,unsigned short &seqno,char* amsg);//user info
+ int aim_request_list(HANDLE hServerConn,unsigned short &seqno);
+ int aim_activate_list(HANDLE hServerConn,unsigned short &seqno);
+ int aim_accept_rates(HANDLE hServerConn,unsigned short &seqno);
+ int aim_set_caps(HANDLE hServerConn,unsigned short &seqno);
+ int aim_client_ready(HANDLE hServerConn,unsigned short &seqno);
+ int aim_mail_ready(HANDLE hServerConn,unsigned short &seqno);
+ int aim_avatar_ready(HANDLE hServerConn,unsigned short &seqno);
+ int aim_chatnav_ready(HANDLE hServerConn,unsigned short &seqno);
+ int aim_chat_ready(HANDLE hServerConn,unsigned short &seqno);
+ int aim_send_message(HANDLE hServerConn,unsigned short &seqno,const char* sn,char* amsg,bool auto_response, bool blast);
+ int aim_query_profile(HANDLE hServerConn,unsigned short &seqno,char* sn);
+ int aim_delete_contact(HANDLE hServerConn,unsigned short &seqno,char* sn,unsigned short item_id,unsigned short group_id,unsigned short list, bool nil);
+ int aim_add_contact(HANDLE hServerConn,unsigned short &seqno,const char* sn,unsigned short item_id,unsigned short group_id,unsigned short list,char* nick=NULL, char* note=NULL);
+ int aim_mod_group(HANDLE hServerConn,unsigned short &seqno,const char* name,unsigned short group_id,char* members,unsigned short members_length);
+ int aim_mod_buddy(HANDLE hServerConn,unsigned short &seqno,const char* sn,unsigned short buddy_id,unsigned short group_id,char* nick,char* note);
+ int aim_ssi_update(HANDLE hServerConn, unsigned short &seqno, bool start);
+ int aim_ssi_update_preferences(HANDLE hServerConn, unsigned short &seqno);
+ int aim_keepalive(HANDLE hServerConn,unsigned short &seqno);
+ int aim_send_file(HANDLE hServerConn,unsigned short &seqno,unsigned long ip, unsigned short port, bool force_proxy, file_transfer *ft);//used when requesting a regular file transfer
+ int aim_file_ad(HANDLE hServerConn,unsigned short &seqno,char* sn,char* icbm_cookie,bool deny,unsigned short max_ver);
+ int aim_typing_notification(HANDLE hServerConn,unsigned short &seqno,char* sn,unsigned short type);
+ int aim_set_idle(HANDLE hServerConn,unsigned short &seqno,unsigned long seconds);
+ int aim_request_mail(HANDLE hServerConn,unsigned short &seqno);
+ int aim_activate_mail(HANDLE hServerConn,unsigned short &seqno);
+ int aim_request_avatar(HANDLE hServerConn,unsigned short &seqno,const char* sn, unsigned short bart_type, const char* hash, unsigned short hash_size);//family 0x0010
+ int aim_set_avatar_hash(HANDLE hServerConn,unsigned short &seqno, char flags, unsigned short bart_type, unsigned short &id, char size, const char* hash);
+ int aim_delete_avatar_hash(HANDLE hServerConn,unsigned short &seqno, char flags, unsigned short bart_type, unsigned short &id);
+ int aim_upload_avatar(HANDLE hServerConn,unsigned short &seqno, unsigned short bart_type, const char* avatar, unsigned short avatar_size);
+ int aim_search_by_email(HANDLE hServerConn,unsigned short &seqno, const char* email);
+ int aim_set_pd_info(HANDLE hServerConn, unsigned short &seqno);
+ int aim_block_buddy(HANDLE hServerConn, unsigned short &seqno, bool remove, const char* sn, unsigned short item_id);
+ int aim_chatnav_request_limits(HANDLE hServerConn,unsigned short &seqno);
+ int aim_chatnav_create(HANDLE hServerConn,unsigned short &seqno, char* room, unsigned short exchage);
+ int aim_chatnav_room_info(HANDLE hServerConn,unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance);
+ int aim_chat_join_room(HANDLE hServerConn,unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance,unsigned short id);
+ int aim_chat_send_message(HANDLE hServerConn,unsigned short &seqno, char *amsg);
+ int aim_chat_invite(HANDLE hServerConn,unsigned short &seqno, char* chat_cookie, unsigned short exchange, unsigned short instance, char* sn, char* msg);
+ int aim_chat_deny(HANDLE hServerConn,unsigned short &seqno,char* sn,char* icbm_cookie);
+ int aim_admin_ready(HANDLE hServerConn,unsigned short &seqno);
+ int aim_admin_format_name(HANDLE hServerConn,unsigned short &seqno, const char* sn);
+ int aim_admin_change_password(HANDLE hServerConn,unsigned short &seqno, const char* cur_pw, const char* new_pw);
+ int aim_admin_change_email(HANDLE hServerConn,unsigned short &seqno, const char* email);
+ int aim_admin_request_info(HANDLE hServerConn,unsigned short &seqno, const unsigned short &type);
+ int aim_admin_account_confirm(HANDLE hServerConn,unsigned short &seqno);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // connection.cpp
+
+ void aim_connection_authorization( void );
+
+ void __cdecl aim_protocol_negotiation( void* );
+ void __cdecl aim_mail_negotiation( void* );
+ void __cdecl aim_avatar_negotiation( void* );
+ void __cdecl aim_chatnav_negotiation( void* );
+ void __cdecl aim_chat_negotiation( void* );
+ void __cdecl aim_admin_negotiation( void* );
+
+ int LOG(const char *fmt, ...);
+ HANDLE aim_connect(const char* server, unsigned short port, bool use_ssl, const char* host = NULL);
+ HANDLE aim_peer_connect(const char* ip, unsigned short port);
+ HANDLE aim_peer_connect(unsigned long ip, unsigned short port);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // direct_connect.cpp
+
+ void __cdecl aim_dc_helper( void* );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // error.cpp
+
+ void login_error(unsigned short error);
+ void get_error(unsigned short error);
+ void admin_error(unsigned short error);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // file.cpp
+
+ int sending_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv);
+ int receiving_file(file_transfer *ft, HANDLE hServerPacketRecver, NETLIBPACKETRECVER &packetRecv);
+ void report_file_error(TCHAR* fname);
+ void shutdown_file_transfers(void);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // packets.cpp
+
+ int aim_sendflap(HANDLE conn, char type,unsigned short length,const char *buf, unsigned short &seqno);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // proto.cpp
+
+ void __cdecl basic_search_ack_success( void* p );
+ void __cdecl email_search_ack_success( void* p );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // proxy.cpp
+
+ void __cdecl aim_proxy_helper( void* );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // server.cpp
+
+ void snac_md5_authkey(SNAC &snac,HANDLE hServerConn,unsigned short &seqno, const char* username, const char* password);
+ int snac_authorization_reply(SNAC &snac);
+ void snac_supported_families(SNAC &snac, HANDLE hServerConn,unsigned short &seqno);
+ void snac_supported_family_versions(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);//family 0x0001
+ void snac_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);//family 0x0001
+ void snac_mail_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);// family 0x0001
+ void snac_avatar_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);// family 0x0001
+ void snac_chatnav_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);// family 0x0001
+ void snac_chat_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);// family 0x0001
+ void snac_admin_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);// family 0x0001
+ void snac_service_redirect(SNAC &snac);// family 0x0001
+ void snac_self_info(SNAC &snac);//family 0x0001
+ void snac_icbm_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);//family 0x0004
+ void snac_user_online(SNAC &snac);
+ void snac_user_offline(SNAC &snac);
+ void snac_error(SNAC &snac);//family 0x0003 or x0004
+ void snac_contact_list(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);
+ void snac_message_accepted(SNAC &snac);//family 0x004
+ void snac_received_message(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);//family 0x0004
+ void snac_file_decline(SNAC &snac);//family 0x0004
+ void snac_received_info(SNAC &snac);//family 0x0002
+ void snac_typing_notification(SNAC &snac);//family 0x004
+ void snac_list_modification_ack(SNAC &snac);//family 0x0013
+ void snac_mail_response(SNAC &snac);//family 0x0018
+ void snac_retrieve_avatar(SNAC &snac);//family 0x0010
+ void snac_upload_reply_avatar(SNAC &snac);//family 0x0010
+ void snac_email_search_results(SNAC &snac);//family 0x000A
+ void snac_chatnav_info_response(SNAC &snac,HANDLE hServerConn,unsigned short &seqno);//family 0x000D
+ void snac_chat_joined_left_users(SNAC &snac,chat_list_item* item);//family 0x000E
+ void snac_chat_received_message(SNAC &snac,chat_list_item* item);//family 0x000E
+ void snac_admin_account_infomod(SNAC &snac);//family 0x0007
+ void snac_admin_account_confirm(SNAC &snac);//family 0x0007
+
+ void process_ssi_list(SNAC &snac, int &offset);
+ void modify_ssi_list(SNAC &snac, int &offset);
+ void delete_ssi_list(SNAC &snac, int &offset);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // themes.cpp
+
+ void InitMainMenus(void);
+ void InitContactMenus(void);
+ void RemoveMainMenus(void);
+ void RemoveContactMenus(void);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // thread.cpp
+
+ void __cdecl accept_file_thread( void* );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // utilities.cpp
+
+ struct msg_ack_param { HANDLE hContact; const char *msg; int id; bool success; };
+
+ void __cdecl msg_ack_success(void*);
+ void __cdecl start_connection(void*);
+
+ void broadcast_status(int status);
+ bool wait_conn(HANDLE& hConn, HANDLE& hEvent, unsigned short service);
+ bool is_my_contact(HANDLE hContact);
+ HANDLE find_chat_contact(const char * room);
+ HANDLE contact_from_sn(const char* sn, bool addIfNeeded = false, bool temporary = false);
+ void add_contact_to_group(HANDLE hContact, const char* group);
+ void set_local_nick(HANDLE hContact, char* nick, char* note);
+ void upload_nicks(void);
+ void update_server_group(const char* group, unsigned short group_id);
+ void offline_contacts(void);
+ void offline_contact(HANDLE hContact, bool remove_settings);
+ unsigned short get_default_port(void);
+
+ int open_contact_file(const char* sn, const TCHAR* file, const char* mode, TCHAR* &path, bool contact_dir);
+ void write_away_message(const char* sn, const char* msg, bool utf);
+ void write_profile(const char* sn, const char* msg, bool utf);
+
+ unsigned short getBuddyId(HANDLE hContact, int i);
+ unsigned short getGroupId(HANDLE hContact, int i);
+ void setBuddyId(HANDLE hContact, int i, unsigned short id);
+ void setGroupId(HANDLE hContact, int i, unsigned short id);
+ int deleteBuddyId(HANDLE hContact, int i);
+ int deleteGroupId(HANDLE hContact, int i);
+
+ unsigned short search_for_free_item_id(HANDLE hbuddy);
+ unsigned short* get_members_of_group(unsigned short group_id, unsigned short& size);
+
+ void ShowPopup( const char* msg, int flags, char* url = 0 );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ HANDLE CreateProtoEvent(const char* szEvent);
+ void CreateProtoService(const char* szService, AimServiceFunc serviceProc);
+ void CreateProtoServiceParam(const char* szService, AimServiceFuncParam serviceProc, LPARAM lParam);
+ void HookProtoEvent(const char* szEvent, AimEventFunc pFunc);
+ void ForkThread(AimThreadFunc, void*);
+
+ int deleteSetting(HANDLE hContact, const char* setting);
+
+ bool getBool(HANDLE hContact, const char* name, bool defaultValue);
+ int getByte(const char* name, BYTE defaultValue );
+ int getByte(HANDLE hContact, const char* name, BYTE defaultValue);
+ int getDword(const char* name, DWORD defaultValue);
+ int getDword(HANDLE hContact, const char* name, DWORD defaultValue);
+ int getString(const char* name, DBVARIANT*);
+ int getString(HANDLE hContact, const char* name, DBVARIANT*);
+ int getTString(const char* name, DBVARIANT*);
+ int getTString(HANDLE hContact, const char* name, DBVARIANT*);
+ WORD getWord(const char* name, WORD defaultValue);
+ WORD getWord(HANDLE hContact, const char* name, WORD defaultValue);
+ char* getSetting(HANDLE hContact, const char* setting);
+ char* getSetting(const char* setting);
+
+ void setByte(const char* name, BYTE value);
+ void setByte(HANDLE hContact, const char* name, BYTE value);
+ void setDword(const char* name, DWORD value);
+ void setDword(HANDLE hContact, const char* name, DWORD value);
+ void setString(const char* name, const char* value);
+ void setString(HANDLE hContact, const char* name, const char* value);
+ void setTString(const char* name, const TCHAR* value);
+ void setTString(HANDLE hContact, const char* name, const TCHAR* value);
+ void setWord(const char* name, WORD value);
+ void setWord(HANDLE hContact, const char* name, WORD value);
+
+ int sendBroadcast(HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam);
+};
+
+#endif
diff --git a/protocols/AimOscar/src/proxy.cpp b/protocols/AimOscar/src/proxy.cpp
new file mode 100644
index 0000000000..b5ce8fef31
--- /dev/null
+++ b/protocols/AimOscar/src/proxy.cpp
@@ -0,0 +1,174 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "proxy.h"
+
+void __cdecl CAimProto::aim_proxy_helper(void* param)
+{
+ file_transfer *ft = (file_transfer*)param;
+
+ if (ft->requester)
+ {
+ if (proxy_initialize_send(ft->hConn, username, ft->icbm_cookie))
+ return;//error
+ }
+ else
+ {
+ if (proxy_initialize_recv(ft->hConn, username, ft->icbm_cookie, ft->port))
+ return;//error
+ }
+
+ //start listen for packets stuff
+ NETLIBPACKETRECVER packetRecv = {0};
+ packetRecv.cbSize = sizeof(packetRecv);
+ packetRecv.dwTimeout = INFINITE;
+
+ HANDLE hServerPacketRecver = (HANDLE) CallService(MS_NETLIB_CREATEPACKETRECVER, (WPARAM)ft->hConn, 2048 * 4);
+ for (;;)
+ {
+ int recvResult = CallService(MS_NETLIB_GETMOREPACKETS, (WPARAM)hServerPacketRecver, (LPARAM)&packetRecv);
+ if (recvResult == 0)
+ {
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+ break;
+ }
+ if (recvResult == SOCKET_ERROR)
+ {
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+ break;
+ }
+ if (recvResult > 0)
+ {
+ unsigned short length = _htons(*(unsigned short*)&packetRecv.buffer[0]);
+ packetRecv.bytesUsed = length + 2;
+ unsigned short type = _htons(*(unsigned short*)&packetRecv.buffer[4]);
+ if (type == 0x0001)
+ {
+ unsigned short error = _htons(*(unsigned short*)&packetRecv.buffer[12]);
+ switch (error)
+ {
+ case 0x000D:
+ ShowPopup("Proxy Server File Transfer Error: Bad Request.", ERROR_POPUP);
+ break;
+
+ case 0x0010:
+ ShowPopup("Proxy Server File Transfer Error: Initial Request Timed Out.", ERROR_POPUP);
+ break;
+
+ case 0x001A:
+ ShowPopup("Proxy Server File Transfer Error: Accept Period Timed Out.", ERROR_POPUP);
+ break;
+
+ case 0x000e:
+ ShowPopup("Proxy Server File Transfer Error: Incorrect command syntax.", ERROR_POPUP);
+ break;
+
+ case 0x0016:
+ ShowPopup("Proxy Server File Transfer Error: Unknown command issued.", ERROR_POPUP);
+ break;
+ }
+
+ }
+ else if (type == 0x0003)
+ {
+ unsigned short port = _htons(*(unsigned short*)&packetRecv.buffer[12]);
+ unsigned long ip = _htonl(*(unsigned long*)&packetRecv.buffer[14]);
+
+ aim_send_file(hServerConn, seqno, ip, port, true, ft);
+ LOG("Stage %d Proxy ft and we are not the sender.", ft->req_num);
+ }
+ else if (type == 0x0005)
+ {
+ if (!ft->requester)
+ {
+ aim_file_ad(hServerConn, seqno, ft->sn, ft->icbm_cookie, false, ft->max_ver);
+ ft->accepted = true;
+ }
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, ft, 0);
+
+ int i;
+ for (i = 21; --i; )
+ {
+ if (Miranda_Terminated()) return;
+ Sleep(100);
+ if (ft->accepted) break;
+ }
+ if (i == 0)
+ {
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+ break;
+ }
+
+ packetRecv.dwTimeout = 350000;
+
+ int result;
+ if (ft->sending)//we are sending
+ result = sending_file(ft, hServerPacketRecver, packetRecv);
+ else
+ result = receiving_file(ft, hServerPacketRecver, packetRecv);
+
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, result ? ACKRESULT_FAILED : ACKRESULT_SUCCESS, ft, 0);
+ break;
+ }
+ }
+ }
+ Netlib_CloseHandle(hServerPacketRecver);
+ Netlib_CloseHandle(ft->hConn);
+
+ ft_list.remove_by_ft(ft);
+}
+
+
+int proxy_initialize_send(HANDLE connection, char* sn, char* cookie)
+{
+ const char sn_length = (char)strlen(sn);
+ const int len = sn_length + 21 + TLV_HEADER_SIZE + AIM_CAPS_LENGTH;
+
+ char* buf= (char*)alloca(len);
+ unsigned short offset=0;
+
+ aim_writeshort(len-2, offset, buf);
+ aim_writegeneric(10, "\x04\x4a\0\x02\0\0\0\0\0\0", offset, buf);
+ aim_writechar((unsigned char)sn_length, offset, buf); // screen name len
+ aim_writegeneric(sn_length, sn, offset, buf); // screen name
+ aim_writegeneric(8, cookie, offset, buf); // icbm cookie
+ aim_writetlv(1, AIM_CAPS_LENGTH, AIM_CAP_FILE_TRANSFER, offset, buf);
+
+ return Netlib_Send(connection, buf, offset, 0) >= 0 ? 0 : -1;
+}
+
+int proxy_initialize_recv(HANDLE connection,char* sn, char* cookie,unsigned short port_check)
+{
+ const char sn_length = (char)strlen(sn);
+ const int len = sn_length + 23 + TLV_HEADER_SIZE + AIM_CAPS_LENGTH;
+
+ char* buf= (char*)alloca(len);
+ unsigned short offset=0;
+
+ aim_writeshort(len-2, offset, buf);
+ aim_writegeneric(10, "\x04\x4a\0\x04\0\0\0\0\0\0", offset, buf);
+ aim_writechar((unsigned char)sn_length, offset, buf); // screen name len
+ aim_writegeneric(sn_length, sn, offset, buf); // screen name
+ aim_writeshort(port_check, offset, buf);
+ aim_writegeneric(8, cookie, offset, buf); // icbm cookie
+ aim_writetlv(1, AIM_CAPS_LENGTH, AIM_CAP_FILE_TRANSFER, offset, buf);
+
+ return Netlib_Send(connection, buf, offset, 0) >= 0 ? 0 : -1;
+}
diff --git a/protocols/AimOscar/src/proxy.h b/protocols/AimOscar/src/proxy.h
new file mode 100644
index 0000000000..8a05a3405a
--- /dev/null
+++ b/protocols/AimOscar/src/proxy.h
@@ -0,0 +1,24 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef PROXY_H
+#define PROXY_H
+
+int proxy_initialize_send(HANDLE connection,char* sn, char* cookie);
+int proxy_initialize_recv(HANDLE connection,char* sn, char* cookie,unsigned short port_check);
+
+#endif
diff --git a/protocols/AimOscar/src/resource.h b/protocols/AimOscar/src/resource.h
new file mode 100644
index 0000000000..2b9ad87095
--- /dev/null
+++ b/protocols/AimOscar/src/resource.h
@@ -0,0 +1,123 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by aim.rc
+//
+#define IDC_SAVECHANGES 3
+#define IDC_CONFIRM 4
+#define IDD_INFO 6
+#define IDD_AIMACCOUNT 7
+#define IDD_AIM 8
+#define IDD_IDLE 9
+#define IDI_AIM 10
+#define IDI_ICQ 11
+#define IDI_ADD 12
+#define IDI_PROFILE 13
+#define IDI_MAIL 14
+#define IDI_HIPTOP 21
+#define IDI_BOT 22
+#define IDI_ADMIN 23
+#define IDI_CONFIRMED 24
+#define IDI_UNCONFIRMED 25
+#define IDI_AWAY 26
+#define IDI_IDLE 27
+#define IDI_AOL 28
+#define IDI_FOREGROUNDCOLOR 31
+#define IDI_BACKGROUNDCOLOR 32
+#define IDD_PRIVACY 36
+#define IDD_CHAT 37
+#define IDI_BLOCK 38
+#define IDD_ADMIN 39
+#define IDD_CHATROOM_INVITE 40
+#define IDI_BOLD 41
+#define IDD_CHATROOM_INVITE_REQ 41
+#define IDI_NBOLD 42
+#define IDI_ITALIC 43
+#define IDI_NITALIC 44
+#define IDI_UNDERLINE 45
+#define IDI_NUNDERLINE 46
+#define IDI_SUBSCRIPT 53
+#define IDI_NSUBSCRIPT 54
+#define IDI_SUPERSCRIPT 55
+#define IDI_NSUPERSCRIPT 56
+#define IDI_NORMALSCRIPT 57
+#define IDI_NNORMALSCRIPT 58
+#define IDC_DETAILS 125
+#define IDC_OPTIONS 126
+#define IDC_EXPERT 127
+#define IDC_BOLD 129
+#define IDC_ITALIC 130
+#define IDC_UNDERLINE 131
+#define IDC_SUPERSCRIPT 132
+#define IDC_SUBSCRIPT 133
+#define IDC_NORMALSCRIPT 134
+#define IDC_FOREGROUNDCOLORPICKER 135
+#define IDC_FOREGROUNDCOLOR 136
+#define IDC_BACKGROUNDCOLORPICKER 137
+#define IDC_BACKGROUNDCOLOR 138
+#define IDC_TYPEFACE 139
+#define IDC_FONTSIZE 141
+#define IDC_SVRRESET 142
+#define IDC_NEWAIMACCOUNTLINK 143
+#define IDC_ALLOWALL 144
+#define IDC_ALLOWCONT 145
+#define IDC_ALLOWBELOW 146
+#define IDC_BLOCKALL 147
+#define IDC_BLOCKBELOW 148
+#define IDC_ALLOWLIST 149
+#define IDC_BLOCKLIST 150
+#define IDC_ALLOWEDIT 151
+#define IDC_ALLOWADD 152
+#define IDC_BLOCKEDIT 153
+#define IDC_BLOCKADD 154
+#define IDC_ALLOWREMOVE 155
+#define IDC_BLOCKREMOVE 156
+#define IDC_ROOM 157
+#define IDC_CEMAIL 158
+#define IDC_MSG 158
+#define IDC_FNAME 159
+#define IDC_NPW1 161
+#define IDC_NPW2 162
+#define IDC_CPW 164
+#define IDC_PINFO 165
+#define IDC_SCREENNAME 169
+#define IDC_CCLIST 173
+#define IDC_EDITSCR 174
+#define IDC_ADDSCR 175
+#define IDC_ROOMNAME 176
+#define IDC_SN 1030
+#define IDC_NK 1040
+#define IDC_PW 1050
+#define IDC_HN 1060
+#define IDC_PN 1061
+#define IDC_DM 1100
+#define IDC_DC 1110
+#define IDC_FP 1120
+#define IDC_AT 1130
+#define IDC_ES 1140
+#define IDC_FI 1150
+#define IDC_FO 1160
+#define IDC_DA 1161
+#define IDC_DSSL 1162
+#define IDC_FSC 1163
+#define IDC_HF 1170
+#define IDC_SIS 1171
+#define IDC_MASQ 1180
+#define IDC_CM 1191
+#define IDC_MG 1192
+#define IDC_SETPROFILE 1200
+#define IDC_II 1210
+#define IDC_PROFILE 1220
+#define IDC_IIM 1230
+#define IDC_IIH 1240
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 41
+#define _APS_NEXT_COMMAND_VALUE 40002
+#define _APS_NEXT_CONTROL_VALUE 178
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/AimOscar/src/server.cpp b/protocols/AimOscar/src/server.cpp
new file mode 100644
index 0000000000..a968c20bd5
--- /dev/null
+++ b/protocols/AimOscar/src/server.cpp
@@ -0,0 +1,2397 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "version.h"
+
+void CAimProto::snac_md5_authkey(SNAC &snac,HANDLE hServerConn,unsigned short &seqno, const char* username, const char* password)//family 0x0017
+{
+ if (snac.subcmp(0x0007))//md5 authkey string
+ {
+ unsigned short length=snac.ushort();
+ char* authkey = snac.part(2, length);
+ aim_auth_request(hServerConn, seqno, authkey, AIM_LANGUAGE, AIM_COUNTRY, username, password);
+ mir_free(authkey);
+ }
+}
+
+int CAimProto::snac_authorization_reply(SNAC &snac)//family 0x0017
+{
+ int res = 0;
+
+ if (snac.subcmp(0x0003))
+ {
+ char* server = NULL;
+ int address = 0;
+ unsigned short port;
+ unsigned char use_ssl = 0;
+
+ while (address < snac.len())
+ {
+ TLV tlv(snac.val(address));
+ if (tlv.cmp(0x0005))
+ server = tlv.dup();
+ else if (tlv.cmp(0x0006))
+ {
+ Netlib_CloseHandle(hServerConn);
+
+ if (server == NULL) return 3;
+ char* delim = strchr(server, ':');
+ port = delim ? (unsigned short)atoi(delim + 1) : get_default_port();
+ if (delim) *delim = 0;
+
+ hServerConn = aim_connect(server, port, use_ssl != 0, "bos.oscar.aol.com");
+ if (hServerConn)
+ {
+ mir_free(COOKIE);
+ COOKIE_LENGTH = tlv.len();
+ COOKIE = tlv.dup();
+ ForkThread(&CAimProto::aim_protocol_negotiation, 0);
+ res = 1;
+ }
+ else
+ res = 3;
+ break;
+ }
+ else if (tlv.cmp(0x0008))
+ {
+ login_error(tlv.ushort());
+ res = 2;
+ break;
+ }
+ else if (tlv.cmp(0x0011))
+ {
+ char* email = tlv.dup();
+ setString(AIM_KEY_EM, email);
+ mir_free(email);
+ }
+ else if (tlv.cmp(0x008e))
+ {
+ use_ssl = tlv.ubyte();
+ }
+ address += tlv.len() + 4;
+ }
+ mir_free(server);
+ }
+ return res;
+}
+void CAimProto::snac_supported_families(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)//family 0x0001
+{
+ if (snac.subcmp(0x0003))//server supported service list
+ {
+ aim_send_service_request(hServerConn,seqno);
+ }
+}
+void CAimProto::snac_supported_family_versions(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)//family 0x0001
+{
+ if (snac.subcmp(0x0018))//service list okayed
+ {
+ aim_request_rates(hServerConn,seqno);//request some rate crap
+ }
+}
+void CAimProto::snac_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)// family 0x0001
+{
+ if (snac.subcmp(0x0007))
+ {
+ aim_accept_rates(hServerConn,seqno);
+ aim_request_icbm(hServerConn,seqno);
+ }
+}
+void CAimProto::snac_mail_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)// family 0x0001
+{
+ if (snac.subcmp(0x0007))
+ {
+ aim_accept_rates(hServerConn,seqno);
+ aim_request_mail(hServerConn,seqno);
+ aim_activate_mail(hServerConn,seqno);
+ aim_mail_ready(hServerConn,seqno);
+ }
+}
+
+void CAimProto::snac_avatar_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)// family 0x0001
+{
+ if (snac.subcmp(0x0007))
+ {
+ aim_accept_rates(hServerConn,seqno);
+ aim_avatar_ready(hServerConn,seqno);
+ SetEvent(hAvatarEvent);
+ }
+}
+
+void CAimProto::snac_chatnav_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)// family 0x0001
+{
+ if (snac.subcmp(0x0007))
+ {
+ aim_accept_rates(hServerConn,seqno);
+ aim_chatnav_request_limits(hChatNavConn,chatnav_seqno); // Get the max number of rooms we're allowed in.
+ }
+}
+
+void CAimProto::snac_chat_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)// family 0x0001
+{
+ if (snac.subcmp(0x0007))
+ {
+ aim_accept_rates(hServerConn,seqno);
+ aim_chat_ready(hServerConn,seqno);
+ }
+}
+
+void CAimProto::snac_icbm_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)//family 0x0004
+{
+ if (snac.subcmp(0x0005))
+ {
+ switch (m_iDesiredStatus)
+ {
+ case ID_STATUS_ONLINE:
+ broadcast_status(ID_STATUS_ONLINE);
+ aim_set_status(hServerConn,seqno,AIM_STATUS_ONLINE);
+ break;
+
+ case ID_STATUS_INVISIBLE:
+ broadcast_status(ID_STATUS_INVISIBLE);
+ aim_set_status(hServerConn,seqno,AIM_STATUS_INVISIBLE);
+ break;
+
+ case ID_STATUS_OCCUPIED:
+ broadcast_status(ID_STATUS_OCCUPIED);
+ aim_set_status(hServerConn,seqno,AIM_STATUS_BUSY|AIM_STATUS_AWAY);
+ break;
+
+ case ID_STATUS_AWAY:
+ broadcast_status(ID_STATUS_AWAY);
+ aim_set_status(hServerConn,seqno,AIM_STATUS_AWAY);
+ break;
+ }
+
+ char** msgptr = get_status_msg_loc(m_iDesiredStatus);
+ mir_free(last_status_msg);
+ last_status_msg = msgptr ? mir_strdup(*msgptr) : NULL;
+ aim_set_statusmsg(hServerConn, seqno, last_status_msg);
+
+ if (m_iDesiredStatus == ID_STATUS_AWAY)
+ aim_set_away(hServerConn, seqno, last_status_msg, true);
+
+ if (getByte(AIM_KEY_II,0))
+ {
+ unsigned long time = getDword(AIM_KEY_IIT, 0);
+ aim_set_idle(hServerConn,seqno,time*60);
+ instantidle=1;
+ }
+ aim_request_list(hServerConn,seqno);
+ }
+}
+
+void CAimProto::snac_self_info(SNAC &snac)//family 0x0001
+{
+ if (snac.subcmp(0x000f))
+ {
+ int offset = snac.flags() & 0x8000 ? snac.ushort(0) + 2 : 0;
+
+ unsigned char sn_len = snac.ubyte(offset++);
+ char* sn = snac.part(offset, sn_len);
+ offset += sn_len + 2;
+
+ int tlv_count = snac.ushort(offset);
+ offset += 2;
+
+ for (int i = 0; i < tlv_count; i++)
+ {
+ TLV tlv(snac.val(offset));
+ offset += TLV_HEADER_SIZE + tlv.len();
+
+ if (tlv.cmp(0x000a))
+ {
+ detected_ip = tlv.ulong();
+ }
+ }
+ mir_free(sn);
+ }
+}
+
+void CAimProto::snac_user_online(SNAC &snac)//family 0x0003
+{
+ if (snac.subcmp(0x000b))
+ {
+ char client[100] = "";
+ bool hiptop_user = false;
+ bool bot_user = false;
+ bool wireless_user = false;
+ bool away_user = false;
+ bool caps_included = false;
+ unsigned long status_type = 0; // 0 = online
+
+ char *hash_sm = NULL, *hash_lg = NULL;
+
+ unsigned char sn_len = snac.ubyte();
+ char* sn = snac.part(1, sn_len);
+ HANDLE hContact = contact_from_sn(sn, true);
+
+ int offset = sn_len + 3;
+ int tlv_count = snac.ushort(offset);
+ offset += 2;
+
+ for (int i = 0; i < tlv_count; i++)
+ {
+ TLV tlv(snac.val(offset));
+ offset += TLV_HEADER_SIZE;
+ if (tlv.cmp(0x0001))//user m_iStatus
+ {
+ unsigned short status = tlv.ushort();
+ int unconfirmed = status & 0x0001;
+ int admin_aol = status & 0x0002;
+ int aol = status & 0x0004;
+ //int nonfree = status & 0x0008;
+ //int aim = status & 0x0010;
+ int away = status & 0x0020;
+ int icq = status & 0x0040;
+ int wireless = status & 0x0080;
+ int bot = status & 0x0400;
+ setString(hContact, AIM_KEY_NK, sn);
+
+ if (icq)
+ setString(hContact, "Transport", "ICQ");
+ else
+ deleteSetting(hContact, "Transport" );
+
+ if(admin_aol)
+ {
+ setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_ADMIN);
+ }
+ else if(aol)
+ {
+ setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_AOL);
+ }
+ else if(icq)
+ {
+ setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_ICQ);
+ }
+ else if(unconfirmed)
+ {
+ setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_UNCONFIRMED);
+ }
+ else
+ {
+ setByte(hContact, AIM_KEY_AC, ACCOUNT_TYPE_CONFIRMED);
+ }
+
+ if(bot)
+ {
+ strcpy(client,CLIENT_BOT);
+ bot_user=1;
+ }
+ if(wireless)
+ {
+ strcpy(client,CLIENT_SMS);
+ wireless_user=1;
+ }
+ else if(away)
+ {
+ away_user=1;
+ }
+ setDword(hContact, AIM_KEY_IT, 0);//erase idle time
+ setDword(hContact, AIM_KEY_OT, 0);//erase online time
+ }
+ else if (tlv.cmp(0x0006)) // Status
+ {
+ status_type = tlv.ulong() & 0x00000FFF;
+ }
+ else if (tlv.cmp(0x000d))
+ {
+ caps_included = true;
+
+ for(int i = 0; i<tlv.len(); i += 16)
+ {
+ char* cap = tlv.part(i,16);
+ if (memcmp(cap, "MirandaM", 8) == 0)
+ {
+ char a =cap[8];
+ char b =cap[9];
+ char c =cap[10];
+ char d =cap[11];
+ char e =cap[12];
+ char f =cap[13];
+ char g =cap[14];
+ char h =cap[15];
+ mir_snprintf(client,sizeof(client),CLIENT_OSCARJ,a&0x7f,b,c,d,alpha_cap_str(a),e&0x7f,f,g,h,alpha_cap_str(e));
+ }
+ else if (memcmp(cap, "MirandaA", 8) == 0)
+ {
+ char a =cap[8];
+ char b =cap[9];
+ char c =cap[10];
+ char d =cap[11];
+ char e =cap[12];
+ char f =cap[13];
+ char g =cap[14];
+ char h =cap[15];
+ mir_snprintf(client,sizeof(client),CLIENT_AIMOSCAR,a,b,c,d,e,f,g,h);
+ }
+ if (memcmp(cap, "sinj", 4) == 0)
+ {
+ char a =cap[4];
+ char b =cap[5];
+ char c =cap[6];
+ char d =cap[7];
+ char e =cap[8];
+ char f =cap[9];
+ char g =cap[10];
+ char h =cap[11];
+ mir_snprintf(client,sizeof(client),CLIENT_OSCARSN,a&0x7f,b,c,d,alpha_cap_str(a),e&0x7f,f,g,h,alpha_cap_str(e),secure_cap_str(&cap[12]));
+ }
+ if (memcmp(cap, "icqp", 4) == 0)
+ {
+ char a =cap[4];
+ char b =cap[5];
+ char c =cap[6];
+ char d =cap[7];
+ char e =cap[8];
+ char f =cap[9];
+ char g =cap[10];
+ char h =cap[11];
+ mir_snprintf(client,sizeof(client),CLIENT_OSCARPL,a&0x7f,b,c,d,alpha_cap_str(a),e&0x7f,f,g,h,alpha_cap_str(e),secure_cap_str(&cap[12]));
+ }
+ else if (memcmp(cap, "Kopete ICQ", 10) == 0)
+ {
+ strcpy(client,CLIENT_KOPETE);
+ }
+ else if (memcmp(&cap[7], "QIP", 3) == 0)
+ {
+ strcpy(client,CLIENT_QIP);
+ }
+ else if (memcmp(cap, "mICQ", 4) == 0)
+ {
+ strcpy(client,CLIENT_MICQ);
+ }
+ else if (cap_cmp(cap, AIM_CAP_IM2) == 0)
+ {
+ strcpy(client,CLIENT_IM2);
+ }
+ else if (memcmp(cap, "SIM client", 10) == 0)
+ {
+ strcpy(client,CLIENT_SIM);
+ }
+ else if (memcmp(cap+4, "naim", 4) == 0)
+ {
+ strcpy(client,CLIENT_NAIM);
+ }
+ else if (memcmp(cap, "digsby", 6) == 0)
+ {
+ strcpy(client,CLIENT_DIGSBY);
+ }
+ mir_free(cap);
+ }
+ }
+ else if (tlv.cmp(0x0019))//new caps
+ {
+ caps_included=1;
+ bool f002=0, f003=0, f004=0, f005=0, f007=0, f008=0,
+ O101=0, O102=0, O103=0, O104=0, O105=0, O107=0, O1ff=0,
+ O10a=0, O10c=0, O10d=0,
+ l341=0, l343=0, l345=0, l346=0, l347=0, l348=0, l349=0, l34b=0, l34e=0;
+ //utf8=0;//O actually means 0 in this case
+ for(int i=0;i<tlv.len();i=i+2)
+ {
+ unsigned short cap=tlv.ushort(i);
+ //if(cap==0x134E)
+ // utf8=1;
+ if(cap==0xf002)
+ f002=1;
+ if(cap==0xf003)
+ f003=1;
+ if(cap==0xf004)
+ f004=1;
+ if(cap==0xf005)
+ f005=1;
+ if(cap==0xf007)
+ f007=1;
+ if(cap==0xf008)
+ f008=1;
+ if(cap==0x0101)
+ O101=1;
+ if(cap==0x0102)
+ O102=1;
+ if(cap==0x0103)
+ O103=1;
+ if(cap==0x0104)
+ O104=1;
+ if(cap==0x0105)
+ O105=1;
+ if(cap==0x0107)
+ O107=1;
+ if(cap==0x010a)
+ O10a=1;
+ if(cap==0x010c)
+ O10c=1;
+ if(cap==0x010d)
+ O10d=1;
+ if(cap==0x01ff)
+ O1ff=1;
+ if(cap==0x1323)
+ {
+ strcpy(client,CLIENT_GPRS);
+ hiptop_user=1;
+ }
+ if(cap==0x1341)
+ l341=1;
+ if(cap==0x1343)
+ l343=1;
+ if(cap==0x1345)
+ l345=1;
+ if(cap==0x1346)
+ l346=1;
+ if(cap==0x1347)
+ l347=1;
+ if(cap==0x1348)
+ l348=1;
+ if(cap==0x1349)
+ l349=1;
+ if(cap==0x134b)
+ l34b=1;
+ if(cap==0x134e)
+ l34e=1;
+ }
+ if(f002&&f003&&f004&&f005)
+ strcpy(client,CLIENT_TRILLIAN_PRO);
+ else if ((f004&&f005&&f007&&f008) || (f004&&f005&&O104&&O105))
+ strcpy(client,CLIENT_ICHAT);
+ else if(f003&f004&f005)
+ strcpy(client,CLIENT_TRILLIAN);
+ else if(l343&&O1ff&&tlv.len()==4)
+ strcpy(client,CLIENT_TRILLIAN_ASTRA);
+ else if(l343&&tlv.len()==2)
+ strcpy(client,CLIENT_AIMTOC);
+ else if(l343&&l345&&l346&&tlv.len()==6)
+ strcpy(client,CLIENT_GAIM);
+ else if(l343&&l345&&l346&&l34e&&tlv.len()==8)
+ strcpy(client,CLIENT_PURPLE);
+ else if(l343&&l345&&l346&&l349&&l34e&&tlv.len()==10)
+ strcpy(client,CLIENT_PURPLE);
+ else if(l343&&l345&&l34e&&tlv.len()==6)
+ strcpy(client,CLIENT_ADIUM);
+ else if(l343&&l346&&l34e&&tlv.len()==6)
+ strcpy(client,CLIENT_TERRAIM);
+ else if(tlv.len()==0 && getWord(hContact, AIM_KEY_ST,0)!=ID_STATUS_ONTHEPHONE)
+ strcpy(client,CLIENT_AIMEXPRESS5);
+ else if(l34b&&l343&&O1ff&&l345&&l346&&tlv.len()==10)
+ strcpy(client,CLIENT_AIMEXPRESS6);
+ else if(l34b&&l341&&l343&&O1ff&&l345&&l346&&l347)
+ strcpy(client,CLIENT_AIM5);
+ else if(l34b&&l341&&l343&&l345&l346&&l347&&l348)
+ strcpy(client,CLIENT_AIM4);
+ else if(O1ff&&l343&&O107&&l341&&O104&&O105&&O101&&l346)
+ {
+ if (O10d)
+ strcpy(client,CLIENT_AIM6_9);
+ else if (O10c)
+ strcpy(client,CLIENT_AIM6_8);
+ else if (O10a)
+ strcpy(client,CLIENT_AIM6_5);
+ else
+ strcpy(client,CLIENT_AIM_TRITON);
+ }
+ else if(O1ff&&l343&&l341&&O104&&O105&&O101&&l346)
+ strcpy(client,CLIENT_AIM7_0);
+ else if(l346&&l34e&&tlv.len()==4)
+ strcpy(client,CLIENT_MEEBO);
+ else if(l34e&&tlv.len()==2)
+ strcpy(client,CLIENT_BEEJIVE);
+ else if(l34e&&l343&&tlv.len()==4)
+ strcpy(client,CLIENT_BEEJIVE);
+
+ // setByte(hContact, AIM_KEY_US, utf8);
+ }
+ else if (tlv.cmp(0x001d)) //bart
+ {
+ if (hContact)
+ {
+ bool msg_exist = false;
+ for (int i = 0; i < tlv.len(); )
+ {
+ // Bart header
+ unsigned short type = tlv.ushort(i);
+ unsigned char flags = tlv.ubyte(i + 2);
+ unsigned char datalen = tlv.ubyte(i + 3);
+
+ switch (type)
+ {
+ case 0x0001:
+ hash_sm = bytes_to_string(tlv.val() + i + 4, datalen);
+ break;
+
+ case 0x000c:
+ hash_lg = bytes_to_string(tlv.val() + i + 4, datalen);
+ break;
+
+ case 0x0002:
+ if ((flags & 4) && datalen > 2)
+ {
+ unsigned short len = tlv.ushort(i + 4);
+ if (len)
+ {
+ msg_exist = true;
+ char* msg = tlv.part(i + 6, len);
+ char* msg_s = process_status_msg(msg, sn);
+ DBWriteContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_SM, msg_s);
+
+ TCHAR* tszMsg = mir_utf8decodeT(msg_s);
+ sendBroadcast(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, NULL, (LPARAM)tszMsg);
+ mir_free(tszMsg);
+ mir_free(msg);
+ mir_free(msg_s);
+ }
+ }
+ break;
+ }
+ i += 4 + datalen;
+ }
+
+ if (!msg_exist)
+ DBDeleteContactSetting(hContact, MOD_KEY_CL, OTH_KEY_SM);
+ }
+ }
+ else if(tlv.cmp(0x0004))//idle tlv
+ {
+ if (hContact)
+ {
+ time_t current_time;
+ time(&current_time);
+ setDword(hContact, AIM_KEY_IT, ((DWORD)current_time) - tlv.ushort() * 60);
+ }
+ }
+ else if (tlv.cmp(0x0003))//online time tlv
+ {
+ if (hContact)
+ setDword(hContact, AIM_KEY_OT, tlv.ulong());
+ }
+ else if (tlv.cmp(0x0005))//member since
+ {
+ if (hContact)
+ setDword(hContact, AIM_KEY_MS, tlv.ulong());
+ }
+ offset += tlv.len();
+ }
+
+ if (status_type & AIM_STATUS_INVISIBLE)
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_INVISIBLE);
+ else if (status_type & AIM_STATUS_BUSY)
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_OCCUPIED);
+ else if (status_type & AIM_STATUS_AWAY || away_user)
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_AWAY);
+ else if (wireless_user)
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_ONTHEPHONE);
+ else
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_ONLINE);
+
+ if (hash_lg)
+ avatar_request_handler(hContact, hash_lg, 12);
+ else
+ avatar_request_handler(hContact, hash_sm, 1);
+
+ if (bot_user)
+ setByte(hContact, AIM_KEY_ET, EXTENDED_STATUS_BOT);
+ else if (hiptop_user)
+ setByte(hContact, AIM_KEY_ET, EXTENDED_STATUS_HIPTOP);
+ if (caps_included)
+ set_contact_icon(this, hContact);
+
+ if (caps_included || client[0])
+ setString(hContact, AIM_KEY_MV, client[0] ? client : "?");
+ else if (atoi(sn))
+ setString(hContact, AIM_KEY_MV, CLIENT_ICQ);
+ else if (getBool(hContact, AIM_KEY_BLS, false))
+ setString(hContact, AIM_KEY_MV, CLIENT_BLAST);
+ else
+ setString(hContact, AIM_KEY_MV, CLIENT_AIMEXPRESS7);
+
+ mir_free(hash_lg);
+ mir_free(hash_sm);
+ mir_free(sn);
+ }
+}
+void CAimProto::snac_user_offline(SNAC &snac)//family 0x0003
+{
+ if(snac.subcmp(0x000c))
+ {
+ unsigned char buddy_length=snac.ubyte();
+ char* buddy=snac.part(1,buddy_length);
+ HANDLE hContact=contact_from_sn(buddy, true);
+ if (hContact)
+ offline_contact(hContact,0);
+ mir_free(buddy);
+ }
+}
+void CAimProto::snac_error(SNAC &snac)//family 0x0003 or 0x0004
+{
+ if(snac.subcmp(0x0001))
+ {
+ get_error(snac.ushort());
+ }
+}
+
+void CAimProto::process_ssi_list(SNAC &snac, int &offset)
+{
+ unsigned short name_length = snac.ushort(offset);
+ char* name = snac.part(offset+2, name_length);
+ unsigned short group_id = snac.ushort(offset+ 2 +name_length);
+ unsigned short item_id = snac.ushort(offset+4+name_length);
+ unsigned short type = snac.ushort(offset+6+name_length);
+ unsigned short tlv_size = snac.ushort(offset+8+name_length);
+ const int tlv_base = offset + name_length + 10;
+
+ switch (type)
+ {
+ case 0x0000: //buddy record
+ {
+ HANDLE hContact = contact_from_sn(name, true);
+ if (hContact)
+ {
+ int i;
+ for (i=1; ; i++)
+ {
+ if (!getBuddyId(hContact, i))
+ {
+ setBuddyId(hContact, i, item_id);
+ setGroupId(hContact, i, group_id);
+ break;
+ }
+ }
+ if (i == 1 && getByte(AIM_KEY_MG, 1))
+ {
+ const char* group = group_list.find_name(group_id);
+ if (group)
+ {
+ bool ok = false;
+ DBVARIANT dbv;
+ if (!DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0])
+ {
+ ok = strcmp(group, dbv.pszVal) == 0;
+ if (strcmp(dbv.pszVal, "MetaContacts Hidden Group") == 0)
+ {
+ DBFreeVariant(&dbv);
+ if (!DBGetContactSettingStringUtf(hContact, "MetaContacts", "OldCListGroup", &dbv))
+ {
+ ok = strcmp(group, dbv.pszVal) == 0;
+ DBFreeVariant(&dbv);
+ }
+ }
+ else
+ DBFreeVariant(&dbv);
+ }
+ else
+ {
+ ok = strcmp(group, AIM_DEFAULT_GROUP) == 0;
+ }
+ if (!ok)
+ {
+ if (strcmp(group, AIM_DEFAULT_GROUP))
+ DBWriteContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, group);
+ else
+ DBDeleteContactSetting(hContact, MOD_KEY_CL, OTH_KEY_GP);
+ }
+ }
+ }
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE);
+
+ bool nickfound = false;
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x0131) && tlv.len())
+ {
+ char* nick = tlv.dup();
+ DBWriteContactSettingStringUtf(hContact, MOD_KEY_CL, "MyHandle", nick);
+ mir_free(nick);
+ nickfound = true;
+ }
+ else if (tlv.cmp(0x7b))
+ setByte(hContact, AIM_KEY_BLS, 1);
+ else if (tlv.cmp(0x6a))
+ setByte(hContact, AIM_KEY_NIL, 1);
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ if (!nickfound && getDword(AIM_KEY_LV, 0) >= 0x80500)
+ DBDeleteContactSetting(hContact, MOD_KEY_CL, "MyHandle");
+ }
+ break;
+ }
+
+ case 0x0001: //group record
+ if (group_id)
+ {
+ group_list.add(name, group_id);
+ if (getByte(AIM_KEY_MG, 1))
+ create_group(name);
+ }
+ break;
+
+ case 0x0002: //permit record
+ allow_list.add(name, item_id);
+ break;
+
+ case 0x0003: //deny record
+ block_list.add(name, item_id);
+ break;
+
+ case 0x0004: //privacy record
+ if (group_id == 0)
+ {
+ pd_info_id = item_id;
+
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if(tlv.cmp(0x00ca))
+ pd_mode = tlv.ubyte();
+ else if(tlv.cmp(0x00cc))
+ pd_flags = tlv.ulong();
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ break;
+
+ case 0x0005: //prefernces record
+ if (group_id == 0)
+ {
+ pref1_id = item_id;
+
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x00c9))
+ pref1_flags = tlv.ulong();
+ else if (tlv.cmp(0x00d6))
+ pref1_set_flags = tlv.ulong();
+ else if (tlv.cmp(0x00d7))
+ {
+ mir_free(pref2_flags);
+ pref2_flags = tlv.dup();
+ pref2_len = tlv.len();
+ }
+ else if (tlv.cmp(0x00d8))
+ {
+ mir_free(pref2_set_flags);
+ pref2_set_flags = tlv.dup();
+ pref2_set_len = tlv.len();
+ }
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ break;
+
+ case 0x0014: //avatar record
+ if (!_strcmps(name, "1") || !_strcmps(name, "12"))
+ {
+ if (name_length == 1)
+ avatar_id_sm = item_id;
+ else
+ avatar_id_lg = item_id;
+
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val( tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x00d5) && tlv.len() > 2)
+ {
+ unsigned char type = tlv.ubyte(0);
+ if (name_length == 1)
+ {
+ mir_free(hash_sm);
+ hash_sm = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
+ }
+ else
+ {
+ mir_free(hash_lg);
+ hash_lg = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
+ }
+ }
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ if (list_received)
+ avatar_request_handler(NULL, NULL, 0);
+ }
+ break;
+
+ case 0x001D: // Vanity information
+ if (group_id == 0)
+ {
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x0150)) // Number of IMs sent
+ setDword(AIM_KEY_TIS, tlv.ulong());
+ else if (tlv.cmp(0x0151)) // Number of seconds a user is online
+ setDword(AIM_KEY_TTO, tlv.ulong());
+ else if (tlv.cmp(0x0152)) // Number of times a user has the away message set
+ setDword(AIM_KEY_TAM, tlv.ulong());
+ else if (tlv.cmp(0x0153)) // Number of IMs received
+ setDword(AIM_KEY_TIR, tlv.ulong());
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ break;
+ }
+
+ mir_free(name);
+
+ offset = tlv_base + tlv_size;
+}
+
+void CAimProto::modify_ssi_list(SNAC &snac, int &offset)
+{
+ unsigned short name_length = snac.ushort(offset);
+ char* name = snac.part(offset+2, name_length);
+ unsigned short group_id = snac.ushort(offset+ 2 +name_length);
+ unsigned short item_id = snac.ushort(offset+4+name_length);
+ unsigned short type = snac.ushort(offset+6+name_length);
+ unsigned short tlv_size = snac.ushort(offset+8+name_length);
+ const int tlv_base = offset + name_length + 10;
+
+ switch (type)
+ {
+ case 0x0000: //buddy record
+ {
+ HANDLE hContact = contact_from_sn(name, true);
+ if (hContact)
+ {
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x0131) && tlv.len())
+ {
+ char* nick = tlv.dup();
+ if (nick)
+ DBWriteContactSettingStringUtf(hContact, MOD_KEY_CL, "MyHandle", nick);
+ else
+ DBDeleteContactSetting(hContact, MOD_KEY_CL, "MyHandle");
+ mir_free(nick);
+ }
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ break;
+ }
+
+ case 0x0004: //privacy record
+ if (group_id == 0)
+ {
+ pd_info_id = item_id;
+
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if(tlv.cmp(0x00ca))
+ pd_mode = tlv.ubyte();
+ else if(tlv.cmp(0x00cc))
+ pd_flags = tlv.ulong();
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ break;
+
+ case 0x0005: //prefernces record
+ if (group_id == 0)
+ {
+ pref1_id = item_id;
+
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val(tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x00c9))
+ pref1_flags = tlv.ulong();
+ else if (tlv.cmp(0x00d6))
+ pref1_set_flags = tlv.ulong();
+ else if (tlv.cmp(0x00d7))
+ {
+ mir_free(pref2_flags);
+ pref2_flags = tlv.dup();
+ pref2_len = tlv.len();
+ }
+ else if (tlv.cmp(0x00d8))
+ {
+ mir_free(pref2_set_flags);
+ pref2_set_flags = tlv.dup();
+ pref2_set_len = tlv.len();
+ }
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ break;
+
+ case 0x0014: //avatar record
+ if (!_strcmps(name, "1") || !_strcmps(name, "12"))
+ {
+ if (name_length == 1)
+ avatar_id_sm = item_id;
+ else
+ avatar_id_lg = item_id;
+
+ for (int tlv_offset = 0; tlv_offset < tlv_size; )
+ {
+ TLV tlv(snac.val( tlv_base + tlv_offset));
+
+ if (tlv.cmp(0x00d5) && tlv.len() > 2)
+ {
+ unsigned char type = tlv.ubyte(0);
+ if (name_length == 1)
+ {
+ mir_free(hash_sm);
+ hash_sm = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
+ }
+ else
+ {
+ mir_free(hash_lg);
+ hash_lg = bytes_to_string(tlv.val() + 2, tlv.ubyte(1));
+ }
+ }
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ avatar_request_handler(NULL, NULL, 0);
+ }
+ break;
+ }
+
+ mir_free(name);
+}
+
+void CAimProto::delete_ssi_list(SNAC &snac, int &offset)
+{
+ int i;
+
+ unsigned short name_length=snac.ushort(offset);
+ char* name=snac.part(offset+2,name_length);
+ unsigned short group_id=snac.ushort(offset+2+name_length);
+ unsigned short item_id=snac.ushort(offset+4+name_length);
+ unsigned short type=snac.ushort(offset+6+name_length);
+
+ HANDLE hContact = contact_from_sn(name);
+
+ switch (type)
+ {
+ case 0x0000: //buddy record
+ for(i=1;;++i)
+ {
+ unsigned short item_id_st = getBuddyId(hContact, i);
+ if (item_id_st == 0) break;
+
+ if (item_id == item_id_st)
+ {
+ deleteBuddyId(hContact, i);
+ deleteGroupId(hContact, i);
+ --i;
+ }
+ }
+ if (i == 1)
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ break;
+
+ case 0x0001: //group record
+ group_list.remove_by_id(group_id);
+ break;
+
+ case 0x0014: //avatar record
+ if (_strcmps(name, "1"))
+ {
+ avatar_id_sm = 0;
+ mir_free(hash_sm);
+ hash_sm = NULL;
+ }
+ else if (!_strcmps(name, "12"))
+ {
+ avatar_id_lg = 0;
+ mir_free(hash_lg);
+ hash_lg = NULL;
+ }
+ avatar_request_handler(NULL, NULL, 0);
+ break;
+ }
+ mir_free(name) ;
+}
+
+void CAimProto::snac_contact_list(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)//family 0x0013
+{
+ if (snac.subcmp(0x0006)) //contact list
+ {
+ LOG("Contact List Received");
+// unsigned char ver = snac.ubyte();
+ int num_obj = snac.ushort(1);
+
+ int offset=3;
+ for (int i=0; i<num_obj; ++i)
+ process_ssi_list(snac, offset);
+
+ if (!list_received)//because they can send us multiple buddy list packets
+ {//only want one finished connection
+ list_received=1;
+ aim_activate_list(hServerConn,seqno);
+ aim_set_caps(hServerConn,seqno);
+ aim_set_icbm(hServerConn,seqno);
+ aim_client_ready(hServerConn,seqno);
+ aim_request_offline_msgs(hServerConn,seqno);
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingStringUtf(NULL, m_szModuleName, AIM_KEY_PR, &dbv))
+ {
+ aim_set_profile(hServerConn, seqno, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (getDword(AIM_KEY_LV, 0) < 0x80500)
+ {
+ upload_nicks();
+ setDword(AIM_KEY_LV, (DWORD)CallService(MS_SYSTEM_GETVERSION,0,0));
+ }
+
+ if (getByte(AIM_KEY_CM, 0))
+ aim_new_service_request(hServerConn, seqno, 0x0018);//mail
+
+ avatar_request_handler(NULL, NULL, 0);
+
+ LOG("Connection Negotiation Finished");
+ state = 1;
+ }
+ }
+ else if (snac.subcmp(0x0008)) // add buddy
+ {
+ int offset=8;
+ process_ssi_list(snac, offset);
+ }
+ else if (snac.subcmp(0x0009)) // modify buddy
+ {
+ int offset=8;
+ modify_ssi_list(snac, offset);
+ }
+ else if (snac.subcmp(0x000a)) // delete buddy
+ {
+ int offset=8;
+ delete_ssi_list(snac, offset);
+ }
+}
+
+void CAimProto::snac_message_accepted(SNAC &snac)//family 0x004
+{
+ if (snac.subcmp(0x000c))
+ {
+
+ char* icbm_cookie = snac.part(0,8);
+ unsigned char sn_length=snac.ubyte(10);
+ char* sn = snac.part(11,sn_length);
+
+ HANDLE hContact = contact_from_sn(sn);
+ if (hContact)
+ {
+ msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param));
+ msg_ack->hContact = hContact;
+ msg_ack->id = *(int*)icbm_cookie & 0x7fffffff;
+ msg_ack->msg = NULL;
+ msg_ack->success = true;
+ ForkThread(&CAimProto::msg_ack_success, msg_ack);
+ }
+
+ mir_free(sn);
+ mir_free(icbm_cookie);
+ }
+}
+void CAimProto::snac_received_message(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)//family 0x0004
+{
+ if (snac.subcmp(0x0007))
+ {
+ unsigned short channel = snac.ushort(8);
+ unsigned char sn_length = snac.ubyte(10);
+ char* sn = snac.part(11,sn_length);
+
+ HANDLE hContact = contact_from_sn(sn, true, true);
+
+ int offset=15+sn_length;
+
+ CCSDATA ccs={0};
+ PROTORECVEVENT pre;
+
+ char* msg_buf=NULL;
+ unsigned long offline_timestamp = 0;
+ bool is_offline = false;
+ //file transfer stuff
+ char* icbm_cookie = NULL;
+ char* filename = NULL;
+ unsigned __int64 file_size=0;
+ bool auto_response=false;
+ bool force_proxy=false;
+ bool descr_included=false;
+ bool utf_fname=false;
+ bool unicode_descr=false;
+ short rdz_msg_type=-1;
+ unsigned short request_num=0;
+ unsigned long local_ip=0, verified_ip=0, proxy_ip=0;
+ unsigned short port = 0;
+ unsigned short max_ver = 0;
+ unsigned short num_files = 0;
+ //end file transfer stuff
+
+ unsigned short tlv_head_num=snac.ushort(offset-2);
+ for (int i=0;i<tlv_head_num;i++)
+ { // skip server-added TLVs - prevent another problems with parsing
+ TLV tlv(snac.val(offset));
+ offset+=TLV_HEADER_SIZE+tlv.len();
+ // some extra sanity
+ if (offset>=snac.len()) break;
+ }
+ while (offset<snac.len())
+ {
+ TLV tlv(snac.val(offset));
+ offset+=TLV_HEADER_SIZE;
+ if (tlv.cmp(0x0004)&&!tlv.len())//auto response flag
+ {
+ auto_response=1;
+ }
+ if (tlv.cmp(0x0002))//msg
+ {
+ unsigned short caps_length=tlv.ushort(2);
+ unsigned short msg_length=tlv.ushort(6+caps_length)-4;
+ unsigned short encoding=tlv.ushort(8+caps_length);
+ char* buf=tlv.part(12+caps_length,msg_length);
+ if(hContact)
+ {
+ wchar_t* wbuf;
+ ccs.hContact = hContact;
+ switch (encoding)
+ {
+ case 2:
+ wbuf = (wchar_t*)buf;
+ wcs_htons(wbuf);
+
+ msg_buf = mir_utf8encodeW(wbuf);
+ mir_free(wbuf);
+ break;
+
+ case 3:
+ wbuf = mir_a2u_cp(buf, 28591);
+
+ msg_buf = mir_utf8encodeW(wbuf);
+ mir_free(wbuf);
+ mir_free(buf);
+ break;
+
+ default:
+ msg_buf = buf;
+ break;
+ }
+ }
+ }
+ if (tlv.cmp(0x0004) && !tlv.len())//auto response flag
+ {
+ auto_response=1;
+ }
+ if (channel == 2 && tlv.cmp(0x0005))//recv rendervous packet
+ {
+ rdz_msg_type = snac.ushort(offset);
+ icbm_cookie = snac.part(offset+2,8);
+ if (cap_cmp(snac.val(offset+10), AIM_CAP_FILE_TRANSFER) == 0)
+ {
+ for (int i = 26; i < tlv.len(); )
+ {
+ TLV tlv(snac.val(offset+i));
+ if (tlv.cmp(0x000A))
+ {
+ request_num=tlv.ushort();//for file transfer
+ }
+ else if(tlv.cmp(0x0002))//proxy ip
+ {
+ proxy_ip = tlv.ulong();
+ }
+ else if(tlv.cmp(0x0003))//client ip
+ {
+ local_ip = tlv.ulong();
+ }
+ else if(tlv.cmp(0x0004))//verified ip
+ {
+ verified_ip = tlv.ulong();
+ }
+ else if(tlv.cmp(0x0005))
+ {
+ port=tlv.ushort();
+ }
+ else if(tlv.cmp(0x0010))
+ {
+ force_proxy=1;
+ }
+ else if (tlv.cmp(0x0012))
+ {
+ max_ver = tlv.ushort();
+ }
+ else if (tlv.cmp(0x2711))
+ {
+ num_files = tlv.ushort(2);
+ file_size = tlv.ulong(4);
+ filename = tlv.part(8, tlv.len()-8);
+ }
+ else if (tlv.cmp(0x2712))
+ {
+ char* enc = tlv.dup();
+ utf_fname = strcmp(enc, "utf-8") == 0;
+ mir_free(enc);
+ }
+ else if (tlv.cmp(0x2713))
+ {
+ file_size = tlv.u64();
+ }
+ else if (tlv.cmp(0x000c))
+ {
+ msg_buf = unicode_descr ? tlv.dupw() : tlv.dup();
+ html_decode(msg_buf);
+ descr_included = true;
+ if (strstr(msg_buf, "<ICQ_COOL_FT>"))
+ {
+ char* beg = strstr(msg_buf, "<DESC>");
+ char* end = strstr(msg_buf, "</DESC>");
+ if (beg && end && beg < end)
+ {
+ beg += 6;
+ end[0] = 0;
+ memmove(msg_buf, beg, end - beg + 1);
+ }
+ else
+ descr_included = false;
+ }
+ }
+ else if(tlv.cmp(0x000d))
+ {
+ char* enc = tlv.dup();
+ unicode_descr = strcmp(enc, "unicode-2-0") == 0;
+ mir_free(enc);
+ }
+ i += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ else if (cap_cmp(snac.val(offset+10), AIM_CAP_RTCAUDIO) == 0 ||
+ cap_cmp(snac.val(offset+10), AIM_CAP_RTCVIDEO) == 0)
+ {
+ for (int i = 26; i < tlv.len(); )
+ {
+ TLV tlv(snac.val(offset+i));
+ if (tlv.cmp(0x000A))
+ {
+ request_num=tlv.ushort();//for file transfer
+ }
+ else if(tlv.cmp(0x0002))//proxy ip
+ {
+ proxy_ip = tlv.ulong();
+ }
+ else if(tlv.cmp(0x0003))//client ip
+ {
+ local_ip = tlv.ulong();
+ }
+ else if(tlv.cmp(0x0004))//verified ip
+ {
+ verified_ip = tlv.ulong();
+ }
+ else if(tlv.cmp(0x0005))
+ {
+ port=tlv.ushort();
+ }
+ }
+ channel = 0;
+ break;
+ }
+ else if (cap_cmp(snac.val(offset+10), AIM_CAP_CHAT) == 0)//it's a chat invite request
+ {
+ for(int i=26;i<tlv.len();)
+ {
+ TLV tlv(snac.val(offset+i));
+ if(tlv.cmp(0x000c))//optional message
+ {
+ msg_buf = tlv.dup();
+ }
+ else if(tlv.cmp(0x2711))//room information
+ {
+ int cookie_len=tlv.ubyte(2);
+ chatnav_param* par =
+ new chatnav_param(tlv.part(3,cookie_len), tlv.ushort(), tlv.ushort(3+cookie_len),
+ msg_buf, sn, icbm_cookie);
+
+ invite_chat_req_param* chat_rq = new invite_chat_req_param(par, this, msg_buf, sn, icbm_cookie);
+ CallFunctionAsync(chat_request_cb, chat_rq);
+ }
+ i+=TLV_HEADER_SIZE+tlv.len();
+ }
+ }
+ else
+ {
+ channel = 0;
+ break;
+ }
+ }
+ if (channel == 6 && tlv.cmp(0x0005))//audio/video tunnel
+ {
+ msg_buf = tlv.dup();
+ }
+ if (tlv.cmp(0x0006))//Offline message flag
+ {
+ is_offline = true;
+ }
+ if (tlv.cmp(0x0016))//Offline message timestamp
+ {
+ offline_timestamp = tlv.ulong(0);
+ }
+ offset+=(tlv.len());
+ }
+ if (channel == 1)//Message not file
+ {
+ if (auto_response)//this message must be an autoresponse
+ {
+ char* away = mir_utf8encodeT(TranslateT("[Auto-Response]:"));
+ size_t len = strlen(msg_buf) + strlen(away) + 2;
+ char* buf = (char*)mir_alloc(len);
+ mir_snprintf(buf, len, "%s %s", away, msg_buf);
+ mir_free(away);
+ mir_free(msg_buf);
+ msg_buf = buf;
+ }
+
+ // Okay we are setting up the structure to give the message back to miranda's core
+ pre.flags = PREF_UTF;
+
+ if (is_offline)
+ pre.timestamp = offline_timestamp;
+ else
+ pre.timestamp = (DWORD)time(NULL);
+ pre.szMessage = msg_buf;
+ pre.lParam = 0;
+ ccs.szProtoService = PSR_MESSAGE;
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)ccs.hContact, 0);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+ if(m_iStatus==ID_STATUS_AWAY && !auto_response && !getByte(AIM_KEY_DM,0))
+ {
+ unsigned long msg_time = getDword(hContact, AIM_KEY_LM, 0);
+ unsigned long away_time = getDword(AIM_KEY_LA, 0);
+ char** msgptr = get_status_msg_loc(m_iStatus);
+ if (away_time > msg_time && *msgptr)
+ {
+ char* s_msg = process_status_msg(*msgptr, sn);
+
+ char* away = mir_utf8encodeT(TranslateT("[Auto-Response]:"));
+ size_t len = strlen(s_msg) + strlen(away) + 2;
+ char* buf = (char*)alloca(len);
+ mir_snprintf(buf, len, "%s %s", away, s_msg);
+ mir_free(away);
+
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = m_szModuleName;
+ dbei.timestamp = (DWORD)time(NULL);
+ dbei.flags = DBEF_SENT | DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = (int)len;
+ dbei.pBlob = (PBYTE)buf;
+ CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&dbei);
+
+ aim_send_message(hServerConn, seqno, sn, s_msg, true, getBool(hContact, AIM_KEY_BLS, false));
+ mir_free(s_msg);
+ }
+ setDword(hContact, AIM_KEY_LM, (DWORD)time(NULL));
+ }
+ }
+ else if (channel == 2) // File Transfer
+ {
+ if (rdz_msg_type == 0 && request_num == 1) //buddy wants to send us a file
+ {
+ LOG("Buddy Wants to Send us a file. Request 1");
+ LOG(force_proxy ? "Forcing a Proxy File transfer." : "Not forcing Proxy File transfer.");
+
+ file_transfer* ft = new file_transfer(hContact, sn, icbm_cookie);
+
+ ft->me_force_proxy = getByte(AIM_KEY_FP, 0) != 0;
+ ft->peer_force_proxy = force_proxy;
+ ft->local_ip = local_ip;
+ ft->verified_ip = verified_ip;
+ ft->proxy_ip = proxy_ip;
+ ft->port = port;
+ ft->max_ver = max_ver;
+ ft->req_num = request_num;
+
+ ft->file = mir_strdup(filename);
+
+ ft->pfts.totalBytes = file_size;
+ ft->pfts.totalFiles = num_files;
+
+ ft_list.insert(ft);
+
+ if (!descr_included) msg_buf = NULL;
+
+ TCHAR* filenameT = mir_utf8decodeT(filename);
+
+ PROTORECVFILET pre = {0};
+ pre.flags = PREF_TCHAR;
+ pre.fileCount = 1;
+ pre.timestamp = time(NULL);
+ pre.tszDescription = mir_utf8decodeT(msg_buf);
+ pre.ptszFiles = &filenameT;
+ pre.lParam = (LPARAM)ft;
+
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs);
+
+ mir_free(pre.tszDescription);
+ mir_free(filenameT);
+
+ char cip[20];
+ LOG("Local IP: %s:%u", long_ip_to_char_ip(local_ip, cip), port);
+ LOG("Verified IP: %s:%u", long_ip_to_char_ip(verified_ip, cip), port);
+ LOG("Proxy IP: %s:%u", long_ip_to_char_ip(proxy_ip, cip), port);
+ }
+ else if (rdz_msg_type == 0)
+ {
+ LOG("We are sending a file. Buddy wants us to connect to them. Request %d", request_num);
+ LOG(force_proxy ? "Forcing a Proxy File transfer." : "Not forcing Proxy File transfer.");
+
+ file_transfer* ft = ft_list.find_by_cookie(icbm_cookie, hContact);
+ if (ft)
+ {
+ ft->hContact = hContact;
+
+ ft->me_force_proxy |= (request_num > 2);
+ ft->peer_force_proxy = force_proxy;
+ ft->local_ip = local_ip;
+ ft->verified_ip = verified_ip;
+ ft->proxy_ip = proxy_ip;
+ ft->port = port;
+ ft->requester = false;
+ ft->req_num = request_num;
+ ft->max_ver = max_ver;
+
+ char cip[20];
+ LOG("Local IP: %s:%u", long_ip_to_char_ip(local_ip, cip), port);
+ LOG("Verified IP: %s:%u", long_ip_to_char_ip(verified_ip, cip), port);
+ LOG("Proxy IP: %s:%u", long_ip_to_char_ip(proxy_ip, cip), port);
+
+ ForkThread(&CAimProto::accept_file_thread, ft);
+ }
+ else
+ {
+ LOG("Unknown File transfer, thus denied.");
+ aim_file_ad(hServerConn, seqno, sn, icbm_cookie, true, 0);
+ }
+ }
+ else if (rdz_msg_type == 1)//buddy cancelled or denied file transfer
+ {
+ LOG("File transfer cancelled or denied.");
+
+ file_transfer* ft = ft_list.find_by_cookie(icbm_cookie, hContact);
+ sendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0);
+ ft_list.remove_by_ft(ft);
+ }
+ else if (rdz_msg_type == 2)//buddy accepts our file transfer request
+ {
+ LOG("File transfer accepted");
+ file_transfer* ft = ft_list.find_by_cookie(icbm_cookie, hContact);
+ if (ft)
+ {
+ ft->accepted = true;
+ ft->max_ver = max_ver;
+ }
+ else
+ aim_file_ad(hServerConn, seqno, sn, icbm_cookie, true, 0);
+ }
+ }
+ else if (channel == 6) // Audio/Video call
+ {
+ aim_file_ad(hServerConn, seqno, sn, icbm_cookie, true, 0);
+ ShowPopup(LPGEN("Contact tried to open an audio/video conference (currently not supported)"), ERROR_POPUP);
+ }
+
+ mir_free(sn);
+ mir_free(msg_buf);
+ mir_free(filename);
+ mir_free(icbm_cookie);
+ }
+}
+
+void CAimProto::snac_file_decline(SNAC &snac)//family 0x0004
+{
+ if (snac.subcmp(0x000b))
+ {
+ char *icbm_cookie = snac.part(0, 8);
+ int channel = snac.ushort(8);
+ if (channel == 0x01)
+ {
+ int sn_len = snac.ubyte(10);
+ char* sn = snac.part(11, sn_len);
+ int reason = snac.ushort(11 + sn_len);
+ HANDLE hContact = contact_from_sn(sn);
+
+ msg_ack_param *msg_ack = (msg_ack_param*)mir_alloc(sizeof(msg_ack_param));
+ msg_ack->hContact = hContact;
+ msg_ack->msg = NULL;
+ msg_ack->id = *(int*)icbm_cookie & 0x7fffffff;
+ msg_ack->success = false;
+ ForkThread(&CAimProto::msg_ack_success, msg_ack);
+ }
+ if (channel == 0x02)
+ {
+ int sn_len = snac.ubyte(10);
+ char* sn = snac.part(11, sn_len);
+ int reason = snac.ushort(11 + sn_len);
+ if (reason == 0x03)
+ {
+ int error = snac.ushort(13 + sn_len);
+ if (error == 0x02)
+ {
+ LOG("File Transfer declied");
+ HANDLE hContact = contact_from_sn(sn);
+ file_transfer *ft = ft_list.find_by_cookie(icbm_cookie, hContact);
+ if (ft)
+ {
+ sendBroadcast(hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0);
+ if (ft->hConn) Netlib_Shutdown(ft->hConn);
+ else ft_list.remove_by_ft(ft);
+ }
+ }
+ }
+ mir_free(sn);
+ }
+ mir_free(icbm_cookie);
+ }
+}
+void CAimProto::snac_received_info(SNAC &snac)//family 0x0002
+{
+ if(snac.subcmp(0x0006))
+ {
+ unsigned short offset = 0;
+ int i = 0;
+ bool away_message_received = false;
+ bool away_message_unicode = false;
+ bool away_message_utf = false;
+ bool profile_received = false;
+ bool profile_unicode = false;
+ bool profile_utf = false;
+ unsigned char sn_length = snac.ubyte();
+ char* sn = snac.part(1, sn_length);
+ unsigned short tlv_count = snac.ushort(3 + sn_length);
+ offset = 5 + sn_length;
+ HANDLE hContact = contact_from_sn(sn, true, true);
+
+ while (offset < snac.len())
+ {
+ TLV tlv(snac.val(offset));
+
+ if (++i > tlv_count)
+ {
+ if (tlv.cmp(0x0001))//profile encoding
+ {
+ char* enc = tlv.dup();
+ profile_unicode = strstr(enc, "unicode-2-0") != NULL;
+ profile_utf = strstr(enc, "utf-8") != NULL;
+ mir_free(enc);
+ }
+ else if (tlv.cmp(0x0002))//profile message string
+ {
+ char* msg = profile_unicode ? tlv.dupw() : tlv.dup();
+
+ profile_received = true;
+ write_profile(sn, msg, profile_unicode | profile_utf);
+ mir_free(msg);
+ }
+ else if (tlv.cmp(0x0003))//away message encoding
+ {
+ char* enc = tlv.dup();
+ away_message_unicode = strstr(enc, "unicode-2-0") != NULL;
+ away_message_utf = strstr(enc, "utf-8") != NULL;
+ mir_free(enc);
+ }
+ else if (tlv.cmp(0x0004))//away message string
+ {
+ char* msg = away_message_unicode ? tlv.dupw() : tlv.dup();
+
+ away_message_received = true;
+ write_away_message(sn, msg, away_message_unicode | away_message_utf);
+ mir_free(msg);
+ }
+ }
+ offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ if (hContact)
+ {
+ if (getWord(hContact,AIM_KEY_ST,ID_STATUS_OFFLINE) == ID_STATUS_AWAY)
+ {
+ if (!away_message_received && request_away_message)
+ write_away_message(sn,Translate("No information has been provided by the server."),false);
+ request_away_message = 0;
+ }
+ if (!profile_received&&request_HTML_profile)
+ write_profile(sn,"No Profile",false);
+ request_HTML_profile=0;
+ }
+ mir_free(sn);
+ }
+}
+void CAimProto::snac_typing_notification(SNAC &snac)//family 0x004
+{
+ if(snac.subcmp(0x0014))
+ {
+ unsigned char sn_length=snac.ubyte(10);
+ char* sn=snac.part(11,sn_length);
+ HANDLE hContact=contact_from_sn(sn);
+ if(hContact)
+ {
+ unsigned short type=snac.ushort(11+sn_length);
+ if(type==0x0000)//typing finished
+ CallService(MS_PROTO_CONTACTISTYPING,(WPARAM)hContact,(WPARAM)PROTOTYPE_CONTACTTYPING_OFF);
+ else if(type==0x0001)//typed
+ CallService(MS_PROTO_CONTACTISTYPING,(WPARAM)hContact,PROTOTYPE_CONTACTTYPING_INFINITE);
+ else if(type==0x0002)//typing
+ CallService(MS_PROTO_CONTACTISTYPING,(WPARAM)hContact,(LPARAM)60);
+ }
+ mir_free(sn);
+ }
+}
+void CAimProto::snac_list_modification_ack(SNAC &snac)//family 0x0013
+{
+ if (snac.subcmp(0x000e))
+ {
+ unsigned short id = snac.id();
+ TLV tlv(snac.val(2));
+ unsigned short code = snac.ushort(6 + tlv.len());
+// ssi_queue.execute(this, code == 0);
+ switch (id)
+ {
+ case 0x000a:
+ switch (code)
+ {
+ case 0x0000:
+// ShowPopup(LPGEN("Successfully removed buddy from list."), ERROR_POPUP);
+ break;
+
+ case 0x0002:
+ ShowPopup(LPGEN("Item you want to delete not found in list."), ERROR_POPUP);
+ break;
+
+ default:
+ char msg[64];
+ mir_snprintf(msg, sizeof(msg), "Error removing buddy from list. Error code %#x", code);
+ ShowPopup(msg, ERROR_POPUP);
+ break;
+ }
+ break;
+
+ case 0x0008:
+ switch (code)
+ {
+ case 0x0000:
+// ShowPopup("Successfully added buddy to list.", ERROR_POPUP);
+ break;
+
+ case 0x0003:
+ ShowPopup(LPGEN("Failed to add buddy to list: Item already exist."), ERROR_POPUP);
+ break;
+
+ case 0x000a:
+ ShowPopup(LPGEN("Error adding buddy(invalid id?, already in list?)"), ERROR_POPUP);
+ break;
+
+ case 0x000c:
+ ShowPopup(LPGEN("Cannot add buddy. Limit for this type of item exceeded."), ERROR_POPUP);
+ break;
+
+ case 0x000d:
+ ShowPopup(LPGEN("Error? Attempting to add ICQ contact to an AIM list."), ERROR_POPUP);
+ break;
+
+ case 0x000e:
+ ShowPopup(LPGEN("Cannot add this buddy because it requires authorization."), ERROR_POPUP);
+ break;
+
+ default:
+ char msg[64];
+ mir_snprintf(msg, sizeof(msg), Translate("Unknown error when adding buddy to list. Error code %#x"), code);
+ ShowPopup(msg, ERROR_POPUP);
+ break;
+ }
+ break;
+
+ case 0x0009:
+ switch (code)
+ {
+ case 0x0000:
+ case 0x000e:
+// ShowPopup(LPGEN("Successfully modified group."), ERROR_POPUP);
+ break;
+
+ case 0x0002:
+ ShowPopup(LPGEN("Item you want to modify not found in list."), ERROR_POPUP);
+ break;
+
+ default:
+ char msg[64];
+ mir_snprintf(msg, sizeof(msg), Translate("Unknown error when attempting to modify a group. Error code %#x"), code);
+ ShowPopup(msg, ERROR_POPUP);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+void CAimProto::snac_service_redirect(SNAC &snac)//family 0x0001
+{
+ if (snac.subcmp(0x0005))
+ {
+ char* server=NULL;
+ char* local_cookie=NULL;
+ char* host=NULL;
+ int local_cookie_length=0;
+ unsigned short family=0;
+ unsigned char use_ssl=0;
+
+ int offset=2; // skip number of bytes in family version tlv
+ while (offset < snac.len())
+ {
+ TLV tlv(snac.val(offset));
+ if(tlv.cmp(0x000d))
+ {
+ family=tlv.ushort();
+ }
+ else if(tlv.cmp(0x0005))
+ {
+ server=tlv.dup();
+ }
+ else if(tlv.cmp(0x0006))
+ {
+ local_cookie=tlv.dup();
+ local_cookie_length=tlv.len();
+ }
+ else if(tlv.cmp(0x008d))
+ {
+ host=tlv.dup();
+ }
+ else if(tlv.cmp(0x008e))
+ {
+ use_ssl=tlv.ubyte();
+ }
+ offset+=TLV_HEADER_SIZE+tlv.len();
+ }
+ if (family == 0x0018)
+ {
+ hMailConn = aim_connect(server, get_default_port(), false/*use_ssl != 0*/, host);
+ if(hMailConn)
+ {
+ LOG("Successfully Connected to the Mail Server.");
+ MAIL_COOKIE=local_cookie;
+ MAIL_COOKIE_LENGTH=local_cookie_length;
+ ForkThread( &CAimProto::aim_mail_negotiation, 0 );
+ }
+ else
+ LOG("Failed to connect to the Mail Server.");
+ }
+ else if (family == 0x0010)
+ {
+ hAvatarConn = aim_connect(server, get_default_port(), false/*use_ssl != 0*/);
+ if(hAvatarConn)
+ {
+ LOG("Successfully Connected to the Avatar Server.");
+ AVATAR_COOKIE = local_cookie;
+ AVATAR_COOKIE_LENGTH = local_cookie_length;
+ ForkThread( &CAimProto::aim_avatar_negotiation, 0 );
+ }
+ else
+ LOG("Failed to connect to the Avatar Server.");
+ }
+ else if (family == 0x000D)
+ {
+ hChatNavConn = aim_connect(server, get_default_port(), use_ssl != 0, host);
+ if(hChatNavConn)
+ {
+ LOG("Successfully Connected to the Chat Navigation Server.");
+ CHATNAV_COOKIE = local_cookie;
+ CHATNAV_COOKIE_LENGTH = local_cookie_length;
+ ForkThread( &CAimProto::aim_chatnav_negotiation, 0 );
+ }
+ else
+ LOG("Failed to connect to the Chat Navigation Server.");
+
+ }
+ else if (family == 0x000E)
+ {
+ chat_list_item* item = find_chat_by_cid(snac.idh());
+ if (item)
+ {
+ item->hconn = aim_connect(server, get_default_port(), use_ssl != 0, host);
+ if (item->hconn)
+ {
+ LOG("Successfully Connected to the Chat Server.");
+ chat_start(item->id, item->exchange);
+ item->CHAT_COOKIE = local_cookie;
+ item->CHAT_COOKIE_LENGTH = local_cookie_length;
+ ForkThread( &CAimProto::aim_chat_negotiation, item );
+ }
+ else
+ LOG("Failed to connect to the Chat Server.");
+ }
+ }
+ else if (family == 0x0007)
+ {
+ hAdminConn = aim_connect(server, get_default_port(), false /*use_ssl != 0*/);
+ if(hAdminConn)
+ {
+ LOG("Successfully Connected to the Admin Server.");
+ ADMIN_COOKIE = local_cookie;
+ ADMIN_COOKIE_LENGTH = local_cookie_length;
+ ForkThread( &CAimProto::aim_admin_negotiation, 0 );
+ }
+ else
+ LOG("Failed to connect to the Admin Server.");
+ }
+ mir_free(server);
+ mir_free(host);
+ }
+}
+
+void CAimProto::snac_mail_response(SNAC &snac)//family 0x0018
+{
+ if (snac.subcmp(0x0007))
+ {
+ char* sn = NULL;
+ time_t time = 0;
+ unsigned short num_msgs = 0;
+ unsigned short flags = 0;
+ char new_mail = 0;
+ char* url = NULL;
+ char* address = NULL;
+
+ int position = 26;
+ int num_tlvs = snac.ushort(24);
+ for (int i = 0; i < num_tlvs; i++)
+ {
+ TLV tlv(snac.val(position));
+ if (tlv.cmp(0x0009))
+ {
+ sn = tlv.dup();
+ }
+ else if (tlv.cmp(0x001d))
+ {
+ time = tlv.ulong();
+ }
+ else if (tlv.cmp(0x0080))
+ {
+ num_msgs = tlv.ushort();
+ }
+ else if (tlv.cmp(0x0081))
+ {
+ new_mail = tlv.ubyte();
+ }
+ else if (tlv.cmp(0x0084))
+ {
+ flags = tlv.ushort();
+ }
+ else if (tlv.cmp(0x0007))
+ {
+ url = tlv.dup();
+ }
+ else if (tlv.cmp(0x0082))
+ {
+ address = tlv.dup();
+ }
+ position += TLV_HEADER_SIZE + tlv.len();
+ }
+ if (new_mail && num_msgs)
+ {
+ TCHAR msg[1024];
+
+ int len = mir_sntprintf(msg, SIZEOF(msg), _T("%S@%S (%d)\r\n%s "), sn, address, num_msgs,
+ TranslateT("You've got mail! Checked at")) ;
+
+ SYSTEMTIME stLocal;
+ GetLocalTime(&stLocal);
+ GetTimeFormat(LOCALE_USER_DEFAULT, 0, &stLocal, NULL, msg + len, SIZEOF(msg) - len);
+
+ ShowPopup((char*)msg, MAIL_POPUP | TCHAR_POPUP, url);
+ }
+ mir_free(sn);
+ mir_free(address);
+ mir_free(url);
+ }
+}
+void CAimProto::snac_retrieve_avatar(SNAC &snac)//family 0x0010
+{
+ if (snac.subcmp(0x0007))
+ {
+ int sn_len = snac.ubyte(0);
+ char* sn = snac.part(1, sn_len);
+
+ int parse_off = sn_len + 4;
+ parse_off += snac.ubyte(parse_off);
+
+ int hash_size=snac.ubyte(5+parse_off);
+ char* hash_string=bytes_to_string(snac.val(6+parse_off), hash_size);
+ parse_off += hash_size + 6;
+
+ int icon_length=snac.ushort(parse_off);
+ char* icon_data=snac.val(parse_off+2);
+
+ avatar_retrieval_handler(sn, hash_string, icon_data, icon_length);
+
+ mir_free(hash_string);
+ mir_free(sn);
+ }
+}
+void CAimProto::snac_upload_reply_avatar(SNAC &snac)//family 0x0010
+{
+ if (snac.subcmp(0x0003))
+ {
+ int code = snac.ubyte(0);
+ switch (code)
+ {
+ case 0:
+ break;
+ case 3:
+ ShowPopup(LPGEN("Error uploading avatar. (Too small)"), ERROR_POPUP);
+ break;
+ case 4:
+ ShowPopup(LPGEN("Error uploading avatar. (Too big)"), ERROR_POPUP);
+ break;
+ case 5:
+ ShowPopup(LPGEN("Error uploading avatar. (Wrong type)"), ERROR_POPUP);
+ break;
+ case 6:
+ ShowPopup(LPGEN("Error uploading avatar. (Is banned)"), ERROR_POPUP);
+ break;
+ default:
+ ShowPopup(LPGEN("Error uploading avatar. (Unknown error)"), ERROR_POPUP);
+ break;
+ }
+ }
+}
+void CAimProto::snac_email_search_results(SNAC &snac)//family 0x000A
+{
+ if (snac.subcmp(0x0003)) // Found some buddies
+ {
+ PROTOSEARCHRESULT psr = {0};
+ psr.cbSize = sizeof(psr);
+
+ unsigned short offset=0;
+ while(offset<snac.len()) // Loop through all the TLVs and pull out the buddy name
+ {
+ TLV tlv(snac.val(offset));
+ offset+=TLV_HEADER_SIZE;
+ psr.id = (TCHAR*)tlv.dup();
+ offset+=tlv.len();
+ sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE) 1, (LPARAM) & psr);
+ mir_free(psr.nick);
+ }
+ sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ }
+ else // If no match, stop the search.
+ CAimProto::sendBroadcast(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+}
+
+void CAimProto::snac_chatnav_info_response(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)//family 0x000D
+{
+ if(snac.subcmp(0x0009))
+ {
+ LOG("Chat Info Received");
+
+ unsigned short offset_info=0;
+ while (offset_info < snac.len()) // Loop through all the TLVs and pull out the buddy name
+ {
+ TLV info_tlv(snac.val(offset_info));
+ if (info_tlv.cmp(0x0001)) // Redirect
+ {
+ // char redirect = info_tlv.ubyte();
+ }
+ else if (info_tlv.cmp(0x0002)) // Max Concurrent Rooms (usually 10)
+ {
+ // This typecasting pointer to number and as such bogus
+ MAX_ROOMS = info_tlv.ubyte();
+
+ aim_chatnav_ready(hServerConn,seqno);
+ SetEvent(hChatNavEvent);
+ }
+ else if (info_tlv.cmp(0x0003)) // Exchanges
+ {
+ }
+ else if (info_tlv.cmp(0x0004)) // Room Info
+ {
+ // Main TLV info
+ unsigned short exchange = 0;
+ unsigned short cookie_len = 0;
+ char* cookie = 0;
+ unsigned short instance = 0;
+ unsigned short num_tlv = 0;
+ unsigned short tlv_offset = 0;
+
+ exchange = info_tlv.ushort(0); // Exchange
+ cookie_len = info_tlv.ubyte(2); // Cookie Length
+ cookie = info_tlv.part(3,cookie_len); // Cookie String
+ instance = info_tlv.ushort(3+cookie_len); // Instance
+ num_tlv = info_tlv.ushort(6+cookie_len); // Number of TLVs
+ tlv_offset = 8+cookie_len; // We're looking at any remaining TLVs
+
+ char* name = 0;
+/*
+ unsigned short max_occupancy = 0;
+ char* fqn = 0;
+ unsigned short flags = 0;
+ unsigned long create_time = 0;
+ unsigned short max_msg_len = 0;
+ unsigned char create_perms = 0;
+*/
+ for (int i = 0; i < num_tlv; i++) // Loop through all the TLVs
+ {
+ TLV tlv(info_tlv.val() + tlv_offset);
+
+ // TLV List
+ if (tlv.cmp(0x00d3))
+ name = tlv.dup();
+/*
+ else if (tlv.cmp(0x00d2))
+ max_occupancy = tlv.ushort();
+ else if (tlv.cmp(0x006a))
+ fqn = tlv.dup();
+ else if (tlv.cmp(0x00c9))
+ flags = tlv.ushort();
+ else if (tlv.cmp(0x00ca))
+ create_time = tlv.ulong();
+ else if (tlv.cmp(0x00d1))
+ max_msg_len = tlv.ushort();
+ else if (tlv.cmp(0x00d5))
+ create_perms = tlv.ubyte();
+*/
+ tlv_offset+=TLV_HEADER_SIZE+tlv.len();
+ }
+
+ chat_list_item *item = find_chat_by_id(name);
+ if (item == NULL)
+ {
+ item = new chat_list_item(name, cookie, exchange, instance);
+ chat_rooms.insert(item);
+
+ //Join the actual room
+ aim_chat_join_room(CAimProto::hServerConn, CAimProto::seqno, cookie, exchange, instance, item->cid);
+ }
+
+ mir_free(name);
+ mir_free(cookie);
+ }
+ offset_info += TLV_HEADER_SIZE + info_tlv.len();
+ }
+ }
+}
+void CAimProto::snac_chat_joined_left_users(SNAC &snac,chat_list_item* item)//family 0x000E
+{ // Handles both joining and leaving users.
+ if (snac.subcmp(0x0003) || snac.subcmp(0x0004))
+ {
+ int offset = 0;
+ while (offset < snac.len())
+ {
+ int sn_len = snac.ubyte(offset);
+ char* sn = snac.part(offset+1, sn_len); // Most important part (screenname)
+
+ chat_event(item->id, sn, snac.subcmp(0x0003) ? GC_EVENT_JOIN : GC_EVENT_PART);
+
+ mir_free(sn);
+
+// int warning = snac.ushort(offset+1+sn_len);
+ int num_tlv = snac.ushort(offset+3+sn_len);
+ offset += 5+sn_len; // We're looking at any remaining TLVs
+/*
+ unsigned short user_class = 0;
+ unsigned long idle_time = 0;
+ unsigned long signon_time = 0;
+ unsigned long creation_time = 0; // Server uptime?
+*/
+ for (int i = 0; i < num_tlv; i++) // Loop through all the TLVs
+ {
+ TLV tlv(snac.val(offset));
+/*
+ if (tlv.cmp(0x0001))
+ user_class = tlv.ushort();
+ else if (tlv.cmp(0x0003))
+ signon_time = tlv.ulong();
+ else if (tlv.cmp(0x0005))
+ creation_time = tlv.ulong();
+ else if (tlv.cmp(0x000F))
+ idle_time = tlv.ulong();
+*/
+ offset += TLV_HEADER_SIZE + tlv.len();
+ }
+ }
+ }
+}
+void CAimProto::snac_chat_received_message(SNAC &snac,chat_list_item* item)//family 0x000E
+{
+ if (snac.subcmp(0x0006))
+ {
+ TCHAR* message = NULL;
+ char* sn = NULL;
+
+// unsigned long cookie = snac.ulong(0);
+// unsigned short channel = snac.ushort(8);
+
+ int tlv_offset = 10;
+ while (tlv_offset < snac.len())
+ {
+ TLV tlv(snac.val(tlv_offset));
+
+ if (tlv.cmp(0x0003)) // Sender information
+ {
+ int sn_len = tlv.ubyte(0);
+ sn = tlv.part(1, sn_len);
+ /*
+ unsigned short warning = tlv.ushort(1+sn_len);
+ int num_tlv = tlv.ushort(3+sn_len);
+
+ int offset = 19 + sn_len;
+
+ unsigned short user_class = 0;
+ unsigned long idle_time = 0;
+ unsigned long signon_time = 0;
+ unsigned long creation_time = 0; //Server uptime?
+
+ for (int i = 0; i < num_tlv; i++) // Loop through all the TLVs
+ {
+ TLV info_tlv(tlv.val() + offset);
+
+ // TLV List
+ if (info_tlv.cmp(0x0001))
+ user_class = info_tlv.ushort();
+ else if (info_tlv.cmp(0x0003))
+ signon_time = info_tlv.ulong();
+ else if (info_tlv.cmp(0x0005))
+ creation_time = info_tlv.ulong();
+ else if (info_tlv.cmp(0x000F))
+ idle_time = info_tlv.ulong();
+
+ offset += TLV_HEADER_SIZE + info_tlv.len();
+ }
+ */
+ }
+ else if (tlv.cmp(0x0001)) // Public/Whisper flag
+ {
+ }
+ else if (tlv.cmp(0x0005)) // Message information
+ {
+ bool uni = false;
+ bool utf = false;
+// char* language = NULL;
+
+ int offset = 0;
+ while (offset < tlv.len())
+ {
+ TLV msg_tlv(tlv.val() + offset);
+
+ // TLV List
+ if (msg_tlv.cmp(0x0001))
+ {
+ if (uni)
+ {
+ char* msg = msg_tlv.dupw();
+ html_decode(msg);
+ message = mir_utf8decodeT(msg);
+ mir_free(msg);
+ }
+ else if (utf)
+ {
+ char* msg = msg_tlv.dup();
+ html_decode(msg);
+ message = mir_utf8decodeT(msg);
+ mir_free(msg);
+ }
+ else
+ {
+ char* msg = msg_tlv.dup();
+ html_decode(msg);
+ message = mir_a2t(msg);
+ mir_free(msg);
+ }
+ }
+ else if (msg_tlv.cmp(0x0002))
+ {
+ char* enc = msg_tlv.dup();
+ uni = strstr(enc, "unicode-2-0") != NULL;
+ utf = strstr(enc, "utf-8") != NULL;
+ mir_free(enc);
+ }
+// else if (msg_tlv.cmp(0x0003))
+// language = msg_tlv.dup();
+
+ offset += TLV_HEADER_SIZE + msg_tlv.len();
+ }
+ }
+
+ tlv_offset += TLV_HEADER_SIZE + tlv.len();
+ }
+
+ chat_event(item->id, sn, GC_EVENT_MESSAGE, message);
+
+ mir_free(message);
+ mir_free(sn);
+ }
+}
+
+void CAimProto::snac_admin_rate_limitations(SNAC &snac,HANDLE hServerConn,unsigned short &seqno)// family 0x0001
+{
+ if (snac.subcmp(0x0007))
+ {
+ aim_accept_rates(hServerConn,seqno);
+ aim_admin_ready(hServerConn,seqno);
+ SetEvent(hAdminEvent);
+ }
+}
+
+void CAimProto::snac_admin_account_infomod(SNAC &snac)//family 0x0007
+{
+ if (snac.subcmp(0x0003) || snac.subcmp(0x0005)) // Handles info response and modification response
+ {
+ bool err = false;
+ bool req_email = false;
+ unsigned short perms = 0;
+ unsigned short num_tlv = 0;
+
+ perms = snac.ushort(); // Permissions
+ num_tlv = snac.ushort(2); // Number of TLVs
+
+ char* sn = NULL; // Screen Name
+ char* email = NULL; // Email address
+ //unsigned short status = 0; // Account status
+
+ unsigned short offset = 0;
+ for (int i = 0; i < num_tlv; i++) // Loop through all the TLVs
+ {
+ TLV tlv(snac.val(4+offset));
+
+ // TLV List
+ if (tlv.cmp(0x0001))
+ sn = tlv.dup();
+ if (tlv.cmp(0x0011))
+ {
+ req_email = true;
+ email = tlv.dup();
+ }
+ //if (tlv.cmp(0x0013))
+ // status = tlv.ushort();
+ if (tlv.cmp(0x0008)) // Handles any problems when requesting/changing information
+ {
+ err = true;
+ admin_error(tlv.ushort());
+ }
+ //if (tlv.cmp(0x0004))
+ //error description
+
+ offset += TLV_HEADER_SIZE + tlv.len();
+ }
+
+ if (snac.subcmp(0x0003) && !err) // Requested info
+ {
+ // Display messages
+ if (email)
+ setString(AIM_KEY_EM,email); // Save our email for future reference.
+ if(sn)
+ setString(AIM_KEY_SN,sn); // Update the database to reflect the formatted name.
+ sendBroadcast( NULL, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1, 0 );
+
+ }
+ else if (snac.subcmp(0x0005) && !err) // Changed info
+ {
+ // Display messages
+ if (email && req_email) // We requested to change the email
+ ShowPopup(LPGEN("A confirmation message has been sent to the new email address. Please follow its instructions."), 0);
+ else if (sn)
+ {
+ setString(AIM_KEY_SN,sn); // Update the database to reflect the formatted name.
+ //ShowPopup("Your Screen Name has been successfully formatted.", 0);
+ }
+ }
+ mir_free(sn);
+ mir_free(email);
+ }
+}
+
+void CAimProto::snac_admin_account_confirm(SNAC &snac)//family 0x0007
+{
+ if (snac.subcmp(0x0007))
+ {
+ unsigned short status = 0;
+
+ status = snac.ushort();
+
+ switch (status)
+ {
+ case 0:
+ ShowPopup(LPGEN("A confirmation message has been sent to your email address. Please follow its instructions."), 0);
+ break;
+
+ case 0x13:
+ ShowPopup(LPGEN("Unable to confirm at this time. Please try again later."), 0);
+ break;
+
+ case 0x1e:
+ ShowPopup(LPGEN("Your account has already been confirmed."), 0);
+ break;
+
+ case 0x23:
+ ShowPopup(LPGEN("Can't start the confirmation procedure."), 0);
+ break;
+ }
+
+ //TLV tlv(snac.val(2));
+ //if (tlv.cmp(0x0004))
+ //error description
+ }
+}
+
+
+/*void CAimProto::snac_delete_contact(SNAC &snac, char* buf)//family 0x0013
+{
+ if(snac.subcmp(0x000a))
+ {
+ char sn[33];
+ int sn_length=buf[SNAC_SIZE*2];
+ HANDLE hContact;
+ ZeroMemory(sn,sizeof(sn));
+ memcpy(sn,&buf[SNAC_SIZE*2+1],sn_length);
+ hContact=find_contact(sn);
+ if(hContact)
+ {
+ unsigned short* type=(unsigned short*)&buf[SNAC_SIZE*2+1+sn_length];
+ *type=htons(*type);
+ if (*type==0x0000)//typing finished
+ CallService(MS_PROTO_CONTACTISTYPING,(WPARAM)hContact,(WPARAM)PROTOTYPE_CONTACTTYPING_OFF);
+ else if (*type==0x0001)//typed
+ CallService(MS_PROTO_CONTACTISTYPING,(WPARAM)hContact,PROTOTYPE_CONTACTTYPING_INFINITE);
+ else if (*type==0x0002)//typing
+ CallService(MS_PROTO_CONTACTISTYPING,(WPARAM)hContact,(LPARAM)60);
+ }
+ }
+}*/
diff --git a/protocols/AimOscar/src/services.cpp b/protocols/AimOscar/src/services.cpp
new file mode 100644
index 0000000000..caf2209560
--- /dev/null
+++ b/protocols/AimOscar/src/services.cpp
@@ -0,0 +1,531 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+INT_PTR CAimProto::GetMyAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ char** msgptr = get_status_msg_loc(wParam ? wParam : m_iStatus);
+ if (msgptr == NULL) return 0;
+
+ return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_utf8decodeW(*msgptr) : (INT_PTR)mir_utf8decodeA(*msgptr);
+}
+
+int CAimProto::OnIdleChanged(WPARAM /*wParam*/, LPARAM lParam)
+{
+ if (state != 1)
+ {
+ idle=0;
+ return 0;
+ }
+
+ if (instantidle) //ignore- we are instant idling at the moment
+ return 0;
+
+ bool bIdle = (lParam & IDF_ISIDLE) != 0;
+ bool bPrivacy = (lParam & IDF_PRIVACY) != 0;
+
+ if (bPrivacy && idle)
+ {
+ aim_set_idle(hServerConn,seqno,0);
+ return 0;
+ }
+
+ if (bPrivacy)
+ return 0;
+
+ if (bIdle) //don't want to change idle time if we are already idle
+ {
+ MIRANDA_IDLE_INFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM) & mii);
+
+ idle = 1;
+ aim_set_idle(hServerConn,seqno,mii.idleTime * 60);
+ }
+ else aim_set_idle(hServerConn,seqno,0);
+
+ return 0;
+}
+
+int CAimProto::OnWindowEvent(WPARAM wParam, LPARAM lParam)
+{
+ MessageWindowEventData* msgEvData = (MessageWindowEventData*)lParam;
+
+ if (msgEvData->uType == MSG_WINDOW_EVT_CLOSE)
+ {
+ if (state != 1 || !is_my_contact(msgEvData->hContact))
+ return 0;
+
+ if (getWord(msgEvData->hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE)
+ return 0;
+
+ DBVARIANT dbv;
+ if (!getBool(msgEvData->hContact, AIM_KEY_BLS, false) && !getString(msgEvData->hContact, AIM_KEY_SN, &dbv))
+ {
+ if (_stricmp(dbv.pszVal, SYSTEM_BUDDY))
+ aim_typing_notification(hServerConn, seqno, dbv.pszVal, 0x000f);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+}
+
+INT_PTR CAimProto::GetProfile(WPARAM wParam, LPARAM lParam)
+{
+ if (state != 1)
+ return 0;
+
+ DBVARIANT dbv;
+ if (!getString((HANDLE)wParam, AIM_KEY_SN, &dbv))
+ {
+ request_HTML_profile = 1;
+ aim_query_profile(hServerConn, seqno, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+INT_PTR CAimProto::GetHTMLAwayMsg(WPARAM wParam, LPARAM /*lParam*/)
+{
+ if (state != 1)
+ return 0;
+
+ DBVARIANT dbv;
+ if (!getString((HANDLE)wParam, AIM_KEY_SN, &dbv))
+ {
+ request_away_message = 1;
+ aim_query_away_message(hServerConn, seqno, dbv.pszVal);
+ }
+ return 0;
+}
+
+int CAimProto::OnDbSettingChanged(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam;
+
+ if (strcmp(cws->szModule, MOD_KEY_CL) == 0 && state == 1 && wParam)
+ {
+ HANDLE hContact = (HANDLE)wParam;
+ if (strcmp(cws->szSetting, AIM_KEY_NL) == 0)
+ {
+ if (cws->value.type == DBVT_DELETED)
+ {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0])
+ {
+ add_contact_to_group(hContact, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else
+ add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
+ }
+ }
+ else if (strcmp(cws->szSetting, "MyHandle") == 0)
+ {
+ char* name;
+ switch (cws->value.type)
+ {
+ case DBVT_DELETED:
+ set_local_nick(hContact, NULL, NULL);
+ break;
+
+ case DBVT_ASCIIZ:
+ name = mir_utf8encode(cws->value.pszVal);
+ set_local_nick(hContact, name, NULL);
+ mir_free(name);
+ break;
+
+ case DBVT_UTF8:
+ set_local_nick(hContact, cws->value.pszVal, NULL);
+ break;
+
+ case DBVT_WCHAR:
+ name = mir_utf8encodeW(cws->value.pwszVal);
+ set_local_nick(hContact, name, NULL);
+ mir_free(name);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int CAimProto::OnContactDeleted(WPARAM wParam,LPARAM /*lParam*/)
+{
+ if (state != 1) return 0;
+
+ const HANDLE hContact = (HANDLE)wParam;
+
+ if (DBGetContactSettingByte(hContact, MOD_KEY_CL, AIM_KEY_NL, 0))
+ return 0;
+
+ DBVARIANT dbv;
+ if (!getString(hContact, AIM_KEY_SN, &dbv))
+ {
+ for(int i=1;;++i)
+ {
+ unsigned short item_id = getBuddyId(hContact, i);
+ if (item_id == 0) break;
+
+ unsigned short group_id = getGroupId(hContact, i);
+ if (group_id)
+ {
+ bool is_not_in_list = getBool(hContact, AIM_KEY_NIL, false);
+ aim_ssi_update(hServerConn, seqno, true);
+ aim_delete_contact(hServerConn, seqno, dbv.pszVal, item_id, group_id, 0, is_not_in_list);
+ char* group = group_list.find_name(group_id);
+ update_server_group(group, group_id);
+ aim_ssi_update(hServerConn, seqno, false);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+
+int CAimProto::OnGroupChange(WPARAM wParam,LPARAM lParam)
+{
+ if (state != 1 || !getByte(AIM_KEY_MG, 1)) return 0;
+
+ const HANDLE hContact = (HANDLE)wParam;
+ const CLISTGROUPCHANGE* grpchg = (CLISTGROUPCHANGE*)lParam;
+
+ if (hContact == NULL)
+ {
+ if (grpchg->pszNewName == NULL && grpchg->pszOldName != NULL)
+ {
+ char* szOldName = mir_utf8encodeT(grpchg->pszOldName);
+ unsigned short group_id = group_list.find_id(szOldName);
+ if (group_id)
+ {
+ aim_delete_contact(hServerConn, seqno, szOldName, 0, group_id, 1, false);
+ group_list.remove_by_id(group_id);
+ update_server_group("", 0);
+ }
+ mir_free(szOldName);
+ }
+ else if (grpchg->pszNewName != NULL && grpchg->pszOldName != NULL)
+ {
+ char* szOldName = mir_utf8encodeT(grpchg->pszOldName);
+ unsigned short group_id = group_list.find_id(szOldName);
+ if (group_id)
+ {
+ char* szNewName = mir_utf8encodeT(grpchg->pszNewName);
+ update_server_group(szNewName, group_id);
+ mir_free(szNewName);
+ }
+ mir_free(szOldName);
+ }
+ }
+ else
+ {
+ if (is_my_contact(hContact) && getBuddyId(hContact, 1) &&
+ !DBGetContactSettingByte(hContact, MOD_KEY_CL, AIM_KEY_NL, 0))
+ {
+ if (grpchg->pszNewName)
+ {
+ char* szNewName = mir_utf8encodeT(grpchg->pszNewName);
+ add_contact_to_group(hContact, szNewName);
+ mir_free(szNewName);
+ }
+ else
+ add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
+ }
+ }
+ return 0;
+}
+
+INT_PTR CAimProto::AddToServerList(WPARAM wParam, LPARAM /*lParam*/)
+{
+ if (state != 1) return 0;
+
+ HANDLE hContact = (HANDLE)wParam;
+ DBVARIANT dbv;
+ if (!DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, &dbv) && dbv.pszVal[0])
+ {
+ add_contact_to_group(hContact, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else
+ add_contact_to_group(hContact, AIM_DEFAULT_GROUP);
+ return 0;
+}
+
+INT_PTR CAimProto::BlockBuddy(WPARAM wParam, LPARAM /*lParam*/)
+{
+ if (state != 1) return 0;
+
+ HANDLE hContact = (HANDLE)wParam;
+ unsigned short item_id;
+ DBVARIANT dbv;
+ if (getString(hContact, AIM_KEY_SN, &dbv)) return 0;
+
+ switch(pd_mode)
+ {
+ case 1:
+ pd_mode = 4;
+ aim_set_pd_info(hServerConn, seqno);
+
+ case 4:
+ item_id = block_list.find_id(dbv.pszVal);
+ if (item_id != 0)
+ {
+ block_list.remove_by_id(item_id);
+ aim_delete_contact(hServerConn, seqno, dbv.pszVal, item_id, 0, 3, false);
+ }
+ else
+ {
+ item_id = block_list.add(dbv.pszVal);
+ aim_add_contact(hServerConn, seqno, dbv.pszVal, item_id, 0, 3, false);
+ }
+ break;
+
+ case 2:
+ pd_mode = 3;
+ aim_set_pd_info(hServerConn, seqno);
+
+ case 3:
+ item_id = allow_list.find_id(dbv.pszVal);
+ if (item_id != 0)
+ {
+ allow_list.remove_by_id(item_id);
+ aim_delete_contact(hServerConn, seqno, dbv.pszVal, item_id, 0, 2, false);
+ }
+ else
+ {
+ item_id = allow_list.add(dbv.pszVal);
+ aim_add_contact(hServerConn, seqno, dbv.pszVal, item_id, 0, 2);
+ }
+ break;
+ }
+ DBFreeVariant(&dbv);
+
+ return 0;
+}
+
+ INT_PTR CAimProto::JoinChatUI(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+ DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CHAT), NULL, join_chat_dialog, LPARAM(this));
+ return 0;
+}
+
+INT_PTR CAimProto::OnJoinChat(WPARAM wParam, LPARAM /*lParam*/)
+{
+ if (state != 1) return 0;
+
+ HANDLE hContact = (HANDLE)wParam;
+
+ DBVARIANT dbv;
+ if (!getString(hContact, "ChatRoomID", &dbv))
+ {
+ chatnav_param* par = new chatnav_param(dbv.pszVal, getWord(hContact, "Exchange", 4));
+ ForkThread(&CAimProto::chatnav_request_thread, par);
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+INT_PTR CAimProto::OnLeaveChat(WPARAM wParam, LPARAM /*lParam*/)
+{
+ if (state != 1) return 0;
+
+ HANDLE hContact = (HANDLE)wParam;
+
+ DBVARIANT dbv;
+ if (!getString(hContact, "ChatRoomID", &dbv))
+ {
+ chat_leave(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+INT_PTR CAimProto::InstantIdle(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+ DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_IDLE), NULL, instant_idle_dialog, LPARAM(this));
+ return 0;
+}
+
+INT_PTR CAimProto::ManageAccount(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+ ShellExecuteA(NULL, "open", "https://my.screenname.aol.com", NULL, NULL, SW_SHOW);
+ return 0;
+}
+
+INT_PTR CAimProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATIONT* AI = (PROTO_AVATAR_INFORMATIONT*)lParam;
+
+ AI->filename[0] = 0;
+ AI->format = PA_FORMAT_UNKNOWN;
+
+ if (getByte(AIM_KEY_DA, 0)) return GAIR_NOAVATAR;
+
+ switch (get_avatar_filename(AI->hContact, AI->filename, SIZEOF(AI->filename), NULL))
+ {
+ case GAIR_SUCCESS:
+ if (!(wParam & GAIF_FORCE) || state != 1 )
+ return GAIR_SUCCESS;
+
+ case GAIR_WAITFOR:
+ AI->format = detect_image_type(AI->filename);
+ break;
+
+ default:
+ return GAIR_NOAVATAR;
+ }
+
+ if (state == 1)
+ {
+ ForkThread(&CAimProto::avatar_request_thread, AI->hContact);
+ return GAIR_WAITFOR;
+ }
+
+ return GAIR_NOAVATAR;
+}
+
+INT_PTR CAimProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
+{
+ int res = 0;
+
+ switch (wParam)
+ {
+ case AF_MAXSIZE:
+ ((POINT*)lParam)->x = 100;
+ ((POINT*)lParam)->y = 100;
+ break;
+
+ case AF_MAXFILESIZE:
+ res = 11264;
+ break;
+
+ case AF_PROPORTION:
+ res = PIP_SQUARE;
+ break;
+
+ case AF_FORMATSUPPORTED:
+ res = (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_BMP);
+ break;
+
+ case AF_ENABLED:
+ case AF_DONTNEEDDELAYS:
+ case AF_FETCHALWAYS:
+ res = 1;
+ break;
+ }
+
+ return res;
+}
+
+INT_PTR CAimProto::GetAvatar(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR* buf = (TCHAR*)wParam;
+ int size = (int)lParam;
+
+ if (buf == NULL || size <= 0)
+ return -1;
+
+ PROTO_AVATAR_INFORMATIONT ai = { sizeof(ai) };
+ if (GetAvatarInfo(0, (LPARAM)&ai) == GAIR_SUCCESS)
+ {
+ _tcsncpy(buf, ai.filename, size);
+ buf[size-1] = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+INT_PTR CAimProto::SetAvatar(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR* szFileName = (TCHAR*)lParam;
+
+ if (state != 1) return 1;
+
+ if (szFileName == NULL)
+ {
+ aim_ssi_update(hServerConn, seqno, true);
+ aim_delete_avatar_hash(hServerConn, seqno, 1, 1, avatar_id_sm);
+ aim_delete_avatar_hash(hServerConn, seqno, 1, 12, avatar_id_lg);
+ aim_ssi_update(hServerConn, seqno, false);
+
+ avatar_request_handler(NULL, NULL, 0);
+ }
+ else
+ {
+ char hash[16], hash1[16], *data, *data1 = NULL;
+ unsigned short size, size1 = 0;
+
+ if (!get_avatar_hash(szFileName, hash, &data, size))
+ {
+ mir_free(hash);
+ return 1;
+ }
+
+ rescale_image(data, size, data1, size1);
+
+ if (size1)
+ {
+ mir_md5_state_t state;
+ mir_md5_init(&state);
+ mir_md5_append(&state, (unsigned char*)data1, size1);
+ mir_md5_finish(&state, (unsigned char*)hash1);
+
+ mir_free(hash_lg); hash_lg = bytes_to_string(hash, sizeof(hash));
+ mir_free(hash_sm); hash_sm = bytes_to_string(hash1, sizeof(hash1));
+
+ aim_ssi_update(hServerConn, seqno, true);
+ aim_set_avatar_hash(hServerConn, seqno, 1, 1, avatar_id_sm, 16, hash1);
+ aim_set_avatar_hash(hServerConn, seqno, 1, 12, avatar_id_lg, 16, hash);
+ aim_ssi_update(hServerConn, seqno, false);
+ }
+ else
+ {
+ mir_free(hash_lg); hash_lg = NULL;
+ mir_free(hash_sm); hash_sm = bytes_to_string(hash, sizeof(hash1));
+
+ aim_ssi_update(hServerConn, seqno, true);
+ aim_set_avatar_hash(hServerConn, seqno, 1, 1, avatar_id_sm, 16, hash);
+ aim_delete_avatar_hash(hServerConn, seqno, 1, 12, avatar_id_lg);
+ aim_ssi_update(hServerConn, seqno, false);
+ }
+
+ avatar_request_handler(NULL, NULL, 0);
+
+ avatar_up_req *req = new avatar_up_req(data, size, data1, size1);
+ ForkThread(&CAimProto::avatar_upload_thread, req);
+
+ TCHAR tFileName[MAX_PATH];
+ TCHAR *ext = _tcsrchr(szFileName, '.');
+ get_avatar_filename(NULL, tFileName, SIZEOF(tFileName), ext);
+ int fileId = _topen(tFileName, _O_CREAT | _O_TRUNC | _O_WRONLY | O_BINARY, _S_IREAD | _S_IWRITE);
+ if (fileId < 0)
+ {
+ char errmsg[512];
+ mir_snprintf(errmsg, SIZEOF(errmsg), "Cannot store avatar. File '%s' could not be created/overwritten", tFileName);
+ ShowPopup(errmsg, ERROR_POPUP);
+ return 1;
+ }
+ _write(fileId, data, size);
+ _close(fileId);
+ }
+ return 0;
+}
diff --git a/protocols/AimOscar/src/snac.cpp b/protocols/AimOscar/src/snac.cpp
new file mode 100644
index 0000000000..ed8af265fe
--- /dev/null
+++ b/protocols/AimOscar/src/snac.cpp
@@ -0,0 +1,65 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "snac.h"
+#include "packets.h"
+
+SNAC::SNAC(char* buf,unsigned short length)
+{
+ service_=_htons((*(unsigned short*)&buf[0]));
+ subgroup_=_htons((*(unsigned short*)&buf[2]));
+ flags_=_htons((*(unsigned short*)&buf[4]));
+ idh_=_htons((*(unsigned short*)&buf[6]));
+ id_=_htons((*(unsigned short*)&buf[8]));
+ value_=&buf[SNAC_SIZE];
+ length_=length;
+}
+int SNAC::cmp(unsigned short service)
+{
+ if(service_==service)
+ return 1;
+ else
+ return 0;
+}
+int SNAC::subcmp(unsigned short subgroup)
+{
+ if(subgroup_==subgroup)
+ return 1;
+ else
+ return 0;
+}
+unsigned short SNAC::ushort(int pos)
+{
+ return _htons(*(unsigned short*)&value_[pos]);
+}
+unsigned long SNAC::ulong(int pos)
+{
+ return _htonl(*(unsigned long*)&value_[pos]);
+}
+unsigned char SNAC::ubyte(int pos)
+{
+ return value_[pos];
+}
+char* SNAC::part(int pos, int length)
+{
+ char* value = (char*)mir_alloc(length+1);
+ memcpy(value, &value_[pos], length);
+ value[length] = '\0';
+ return value;
+}
diff --git a/protocols/AimOscar/src/snac.h b/protocols/AimOscar/src/snac.h
new file mode 100644
index 0000000000..8c184dfa3e
--- /dev/null
+++ b/protocols/AimOscar/src/snac.h
@@ -0,0 +1,49 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef SNAC_H
+#define SNAC_H
+
+#define SNAC_SIZE 10
+
+class SNAC
+{
+private:
+ unsigned short service_;
+ unsigned short subgroup_;
+ unsigned short length_;
+ unsigned short flags_;
+ unsigned short idh_;
+ unsigned short id_;
+ char* value_;
+public:
+ SNAC(char* buf, unsigned short length);
+ int cmp(unsigned short service);
+ int subcmp(unsigned short subgroup);
+ unsigned short ushort(int pos=0);
+ unsigned long ulong(int pos=0);
+ unsigned char ubyte(int pos=0);
+ char* part(int pos, int length);
+ char* val(int pos=0) { return &value_[pos]; }
+ unsigned short len(void) { return length_; }
+ unsigned short flags(void) { return flags_; }
+ unsigned short id(void) { return id_; }
+ unsigned short idh(void) { return idh_; }
+};
+
+#endif
diff --git a/protocols/AimOscar/src/theme.cpp b/protocols/AimOscar/src/theme.cpp
new file mode 100644
index 0000000000..085c7335d7
--- /dev/null
+++ b/protocols/AimOscar/src/theme.cpp
@@ -0,0 +1,542 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+#include <m_cluiframes.h>
+#include "m_extraicons.h"
+
+#include "theme.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Icons init
+
+struct _tag_iconList
+{
+ const char* szDescr;
+ const char* szName;
+ int defIconID;
+ const char* szSection;
+}
+static const iconList[] =
+{
+ { LPGEN("ICQ"), "icq", IDI_ICQ },
+ { LPGEN("Add"), "add", IDI_ADD },
+ { LPGEN("Block"), "block", IDI_BLOCK },
+ { LPGEN("Profile"), "profile", IDI_PROFILE },
+ { LPGEN("AOL Mail"), "mail", IDI_MAIL },
+ { LPGEN("AIM Icon"), "aim", IDI_AIM },
+ { LPGEN("Hiptop"), "hiptop", IDI_HIPTOP },
+ { LPGEN("AOL Bot"), "bot", IDI_BOT },
+ { LPGEN("Admin"), "admin", IDI_ADMIN },
+ { LPGEN("Confirmed"), "confirm", IDI_CONFIRMED },
+ { LPGEN("Not Confirmed"), "uconfirm", IDI_UNCONFIRMED },
+ { LPGEN("Blocked list"), "away", IDI_AWAY },
+ { LPGEN("Idle"), "idle", IDI_IDLE },
+ { LPGEN("AOL"), "aol", IDI_AOL },
+
+ { LPGEN("Foreground Color"), "foreclr", IDI_FOREGROUNDCOLOR, LPGEN("Profile Editor") },
+ { LPGEN("Background Color"), "backclr", IDI_BACKGROUNDCOLOR, LPGEN("Profile Editor") },
+ { LPGEN("Bold"), "bold", IDI_BOLD, LPGEN("Profile Editor") },
+ { LPGEN("Not Bold"), "nbold", IDI_NBOLD, LPGEN("Profile Editor") },
+ { LPGEN("Italic"), "italic", IDI_ITALIC, LPGEN("Profile Editor") },
+ { LPGEN("Not Italic"), "nitalic", IDI_NITALIC, LPGEN("Profile Editor") },
+ { LPGEN("Underline"), "undrln", IDI_UNDERLINE, LPGEN("Profile Editor") },
+ { LPGEN("Not Underline"), "nundrln", IDI_NUNDERLINE, LPGEN("Profile Editor") },
+ { LPGEN("Subscript"), "sub_scrpt", IDI_SUBSCRIPT, LPGEN("Profile Editor") },
+ { LPGEN("Not Subscript"), "nsub_scrpt", IDI_NSUBSCRIPT, LPGEN("Profile Editor") },
+ { LPGEN("Superscript"), "sup_scrpt", IDI_SUPERSCRIPT, LPGEN("Profile Editor") },
+ { LPGEN("Not Superscript"), "nsup_scrpt", IDI_NSUPERSCRIPT, LPGEN("Profile Editor") },
+ { LPGEN("Normal Script"), "norm_scrpt", IDI_NORMALSCRIPT, LPGEN("Profile Editor") },
+ { LPGEN("Not Normal Script"), "nnorm_scrpt", IDI_NNORMALSCRIPT, LPGEN("Profile Editor") },
+};
+
+static HANDLE hIconLibItem[SIZEOF(iconList)];
+
+void InitIcons(void)
+{
+ TCHAR szFile[MAX_PATH];
+ GetModuleFileName(hInstance, szFile, SIZEOF(szFile));
+
+ char szSettingName[100];
+ char szSectionName[100];
+
+ SKINICONDESC sid = {0};
+ sid.cbSize = sizeof(SKINICONDESC);
+ sid.ptszDefaultFile = szFile;
+ sid.pszName = szSettingName;
+ sid.pszSection = szSectionName;
+ sid.flags = SIDF_PATH_TCHAR;
+
+ for (int i = 0; i < SIZEOF(iconList); i++) {
+ mir_snprintf(szSettingName, sizeof(szSettingName), "AIM_%s", iconList[i].szName);
+
+ if (iconList[i].szSection)
+ mir_snprintf(szSectionName, sizeof(szSectionName), "%s/%s/%s", LPGEN("Protocols"), LPGEN("AIM"), iconList[i].szSection);
+ else
+ mir_snprintf(szSectionName, sizeof(szSectionName), "%s/%s", LPGEN("Protocols"), LPGEN("AIM"));
+
+ sid.pszDescription = (char*)iconList[i].szDescr;
+ sid.iDefaultIndex = -iconList[i].defIconID;
+ hIconLibItem[i] = Skin_AddIcon(&sid);
+ }
+}
+
+HICON LoadIconEx(const char* name, bool big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, sizeof(szSettingName), "AIM_%s", name);
+ return (HICON)CallService(MS_SKIN2_GETICON, big, (LPARAM)szSettingName);
+}
+
+HANDLE GetIconHandle(const char* name)
+{
+ for (unsigned i=0; i < SIZEOF(iconList); i++)
+ if (strcmp(iconList[i].szName, name) == 0)
+ return hIconLibItem[i];
+ return NULL;
+}
+
+void ReleaseIconEx(const char* name, bool big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, sizeof(szSettingName ), "%s_%s", "AIM", name);
+ CallService(big ? MS_SKIN2_RELEASEICONBIG : MS_SKIN2_RELEASEICON, 0, (LPARAM)szSettingName);
+}
+
+void WindowSetIcon(HWND hWnd, const char* name)
+{
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadIconEx( name, true ));
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadIconEx( name ));
+}
+
+void WindowFreeIcon(HWND hWnd)
+{
+ CallService(MS_SKIN2_RELEASEICON, SendMessage(hWnd, WM_SETICON, ICON_BIG, 0), 0);
+ CallService(MS_SKIN2_RELEASEICON, SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0), 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Extra Icons
+
+extern OBJLIST<CAimProto> g_Instances;
+
+static HANDLE bot_icon, icq_icon, aol_icon, hiptop_icon;
+static HANDLE admin_icon, confirmed_icon, unconfirmed_icon;
+
+static HANDLE hListRebuld, hIconApply;
+static HANDLE hExtraAT, hExtraES;
+
+static const char* extra_AT_icon_name[5] =
+{
+ "uconfirm",
+ "confirm",
+ "icq",
+ "aol",
+ "admin",
+};
+
+static const char* extra_ES_icon_name[2] =
+{
+ "bot",
+ "hiptop",
+};
+
+static HANDLE extra_AT_icon_handle[5];
+static HANDLE extra_ES_icon_handle[2];
+
+static void load_extra_icons(void)
+{
+ if (!ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) return;
+
+ unsigned i;
+
+ for (i = 0; i < SIZEOF(extra_AT_icon_handle); ++i)
+ {
+ extra_AT_icon_handle[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)LoadIconEx(extra_AT_icon_name[i]), 0);
+ ReleaseIconEx(extra_AT_icon_name[i]);
+ }
+
+ for (i = 0; i < SIZEOF(extra_ES_icon_handle); ++i)
+ {
+ extra_ES_icon_handle[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)LoadIconEx(extra_ES_icon_name[i]), 0);
+ ReleaseIconEx(extra_ES_icon_name[i]);
+ }
+}
+
+static void set_extra_icon(HANDLE hContact, HANDLE hImage, int column_type)
+{
+ IconExtraColumn iec;
+ iec.cbSize = sizeof(iec);
+ iec.hImage = hImage;
+ iec.ColumnType = column_type;
+ CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec);
+}
+
+static void clear_AT_icon(HANDLE hContact)
+{
+ if (hExtraAT)
+ ExtraIcon_SetIcon(hExtraAT, hContact, (char*)NULL);
+ else
+ set_extra_icon(hContact, (HANDLE)-1, EXTRA_ICON_ADV2);
+}
+
+static void clear_ES_icon(HANDLE hContact)
+{
+ if (hExtraES)
+ ExtraIcon_SetIcon(hExtraES, hContact, (char*)NULL);
+ else
+ set_extra_icon(hContact, (HANDLE)-1, EXTRA_ICON_ADV3);
+}
+
+static void set_AT_icon(CAimProto* ppro, HANDLE hContact)
+{
+ if (ppro->getByte(hContact, "ChatRoom", 0)) return;
+
+ unsigned i = ppro->getByte(hContact, AIM_KEY_AC, 0) - 1;
+
+ if (hExtraAT)
+ {
+ if (i < 5)
+ {
+ char name[64];
+ mir_snprintf(name, sizeof(name), "AIM_%s", extra_AT_icon_name[i]);
+ ExtraIcon_SetIcon(hExtraAT, hContact, name);
+ }
+ else
+ ExtraIcon_SetIcon(hExtraAT, hContact, (char*)NULL);
+ }
+ else
+ set_extra_icon(hContact, i < 5 ? extra_AT_icon_handle[i] : (HANDLE)-1, EXTRA_ICON_ADV2);
+}
+
+static void set_ES_icon(CAimProto* ppro, HANDLE hContact)
+{
+ if (ppro->getByte(hContact, "ChatRoom", 0)) return;
+
+ unsigned i = ppro->getByte(hContact, AIM_KEY_ET, 0) - 1;
+
+ if (hExtraES)
+ {
+ if (i < 2)
+ {
+ char name[64];
+ mir_snprintf(name, sizeof(name), "AIM_%s", extra_ES_icon_name[i]);
+ ExtraIcon_SetIcon(hExtraES, hContact, name);
+ }
+ else
+ ExtraIcon_SetIcon(hExtraES, hContact, (char*)NULL);
+ }
+ else
+ set_extra_icon(hContact, i < 2 ? extra_ES_icon_handle[i] : (HANDLE)-1, EXTRA_ICON_ADV3);
+}
+
+void set_contact_icon(CAimProto* ppro, HANDLE hContact)
+{
+ if (!ppro->getByte(AIM_KEY_AT, 0)) set_AT_icon(ppro, hContact);
+ if (!ppro->getByte(AIM_KEY_ES, 0)) set_ES_icon(ppro, hContact);
+}
+
+static int OnExtraIconsRebuild(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+ load_extra_icons();
+ return 0;
+}
+
+static int OnExtraIconsApply(WPARAM wParam, LPARAM /*lParam*/)
+{
+ if (!ServiceExists(MS_CLIST_EXTRA_SET_ICON)) return 0;
+
+ HANDLE hContact = (HANDLE)wParam;
+
+ CAimProto *ppro = NULL;
+ for (int i = 0; i < g_Instances.getCount(); ++i)
+ {
+ if (g_Instances[i].is_my_contact(hContact))
+ {
+ ppro = &g_Instances[i];
+ break;
+ }
+ }
+
+ if (ppro) set_contact_icon(ppro, hContact);
+
+ return 0;
+}
+
+void remove_AT_icons(CAimProto* ppro)
+{
+ if (!ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) return;
+
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (ppro->is_my_contact(hContact) && !ppro->getByte(hContact, "ChatRoom", 0))
+ clear_AT_icon(hContact);
+
+ hContact = db_find_next(hContact);
+ }
+}
+
+void remove_ES_icons(CAimProto* ppro)
+{
+ if (!ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) return;
+
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (ppro->is_my_contact(hContact) && !ppro->getByte(hContact, "ChatRoom", 0))
+ clear_ES_icon(hContact);
+ hContact = db_find_next(hContact);
+ }
+}
+
+void add_AT_icons(CAimProto* ppro)
+{
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (ppro->is_my_contact(hContact))
+ set_AT_icon(ppro, hContact);
+
+ hContact = db_find_next(hContact);
+ }
+}
+
+void add_ES_icons(CAimProto* ppro)
+{
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (ppro->is_my_contact(hContact))
+ set_ES_icon(ppro, hContact);
+
+ hContact = db_find_next(hContact);
+ }
+}
+
+void InitExtraIcons(void)
+{
+ hExtraAT = ExtraIcon_Register("aimaccounttype", LPGEN("AIM Account Type"), "AIM_aol");
+ hExtraES = ExtraIcon_Register("aimextstatus", LPGEN("AIM Extended Status"), "AIM_hiptop");
+
+ if (hExtraAT == NULL)
+ {
+ hListRebuld = HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, OnExtraIconsRebuild);
+ hIconApply = HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, OnExtraIconsApply);
+ }
+}
+
+void DestroyExtraIcons(void)
+{
+ UnhookEvent(hIconApply);
+ UnhookEvent(hListRebuld);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Themes
+
+#define MGPROC(x) GetProcAddress(themeAPIHandle,x)
+
+HMODULE themeAPIHandle = NULL; // handle to uxtheme.dll
+HANDLE (WINAPI *MyOpenThemeData)(HWND,LPCWSTR) = 0;
+HRESULT (WINAPI *MyCloseThemeData)(HANDLE) = 0;
+HRESULT (WINAPI *MyDrawThemeBackground)(HANDLE,HDC,int,int,const RECT *,const RECT *) = 0;
+
+void InitThemeSupport(void)
+{
+ if (!IsWinVerXPPlus()) return;
+
+ themeAPIHandle = GetModuleHandleA("uxtheme");
+ if (themeAPIHandle)
+ {
+ MyOpenThemeData = (HANDLE (WINAPI *)(HWND,LPCWSTR))MGPROC("OpenThemeData");
+ MyCloseThemeData = (HRESULT (WINAPI *)(HANDLE))MGPROC("CloseThemeData");
+ MyDrawThemeBackground = (HRESULT (WINAPI *)(HANDLE,HDC,int,int,const RECT *,const RECT *))MGPROC("DrawThemeBackground");
+ }
+}
+
+void DestroyThemeSupport(void)
+{
+ DestroyExtraIcons();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnPreBuildContactMenu
+
+int CAimProto::OnPreBuildContactMenu(WPARAM wParam,LPARAM /*lParam*/)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ bool isChatRoom = getByte(hContact, "ChatRoom", 0) != 0;
+
+ CLISTMENUITEM mi;
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize = sizeof(mi);
+
+ //see if we should add the html away message context menu items
+ mi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE;
+ if (getWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE) != ID_STATUS_AWAY || isChatRoom)
+ mi.flags |= CMIF_HIDDEN;
+
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hHTMLAwayContextMenuItem,(LPARAM)&mi);
+
+ mi.flags = CMIM_FLAGS | CMIF_NOTONLINE;
+ if (getBuddyId(hContact, 1) || state == 0 || isChatRoom)
+ mi.flags |= CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM,(WPARAM)hAddToServerListContextMenuItem,(LPARAM)&mi);
+
+ DBVARIANT dbv;
+ if (!getString(hContact, AIM_KEY_SN, &dbv))
+ {
+ mi.flags = CMIM_NAME | CMIM_FLAGS;
+ switch(pd_mode)
+ {
+ case 1:
+ mi.pszName = LPGEN("&Block");
+ break;
+
+ case 2:
+ mi.pszName = LPGEN("&Unblock");
+ break;
+
+ case 3:
+ mi.pszName = (char*)(allow_list.find_id(dbv.pszVal) ? LPGEN("&Block") : LPGEN("&Unblock"));
+ break;
+
+ case 4:
+ mi.pszName = (char*)(block_list.find_id(dbv.pszVal) ? LPGEN("&Unblock") : LPGEN("&Block"));
+ break;
+
+ default:
+ mi.pszName = LPGEN("&Block");
+ mi.flags |= CMIF_HIDDEN;
+ break;
+ }
+
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hBlockContextMenuItem, (LPARAM)&mi);
+ DBFreeVariant(&dbv);
+ }
+
+ return 0;
+}
+
+void CAimProto::InitMainMenus(void)
+{
+ //Do not put any services below HTML get away message!!!
+ char service_name[200];
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+
+ HGENMENU hRoot = MO_GetProtoRootMenu(m_szModuleName);
+ if (hRoot == NULL) {
+ mi.flags = CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
+ mi.icolibItem = GetIconHandle("aim");
+ mi.ptszName = m_tszUserName;
+ mi.hParentMenu = HGENMENU_ROOT;
+ mi.popupPosition = 500090000;
+ mi.position = 500090000;
+ hRoot = hMenuRoot = Menu_AddProtoMenuItem(&mi);
+ }
+ else {
+ RemoveMainMenus();
+ hMenuRoot = NULL;
+ }
+
+ mi.pszService = service_name;
+ mi.hParentMenu = hRoot;
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_CHILDPOPUP;
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/ManageAccount");
+ CreateProtoService("/ManageAccount", &CAimProto::ManageAccount);
+ mi.position = 201001;
+ mi.icolibItem = GetIconHandle("aim");
+ mi.pszName = LPGEN("Manage Account");
+ hMainMenu[0] = Menu_AddProtoMenuItem(&mi);
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/InstantIdle");
+ CreateProtoService("/InstantIdle",&CAimProto::InstantIdle);
+ mi.position = 201002;
+ mi.icolibItem = GetIconHandle("idle");
+ mi.pszName = LPGEN("Instant Idle");
+ hMainMenu[1] = Menu_AddProtoMenuItem(&mi);
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/JoinChatRoom");
+ CreateProtoService("/JoinChatRoom", &CAimProto::JoinChatUI);
+ mi.position = 201003;
+ mi.icolibItem = GetIconHandle("aol");
+ mi.pszName = LPGEN( "Join Chat Room" );
+ hMainMenu[2] = Menu_AddProtoMenuItem(&mi);
+}
+
+void CAimProto::InitContactMenus(void)
+{
+ //Do not put any services below HTML get away message!!!
+ char service_name[200];
+
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.pszService = service_name;
+ mi.pszContactOwner = m_szModuleName;
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/GetHTMLAwayMsg");
+ CreateProtoService("/GetHTMLAwayMsg",&CAimProto::GetHTMLAwayMsg);
+ mi.position = -2000006000;
+ mi.icolibItem = GetIconHandle("away");
+ mi.pszName = LPGEN("Read &HTML Away Message");
+ mi.flags = CMIF_NOTOFFLINE | CMIF_HIDDEN | CMIF_ICONFROMICOLIB;
+ hHTMLAwayContextMenuItem = Menu_AddContactMenuItem(&mi);
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/GetProfile");
+ CreateProtoService("/GetProfile", &CAimProto::GetProfile);
+ mi.position = -2000005090;
+ mi.icolibItem = GetIconHandle("profile");
+ mi.pszName = LPGEN("Read Profile");
+ mi.flags = CMIF_NOTOFFLINE | CMIF_ICONFROMICOLIB;
+ hReadProfileMenuItem = Menu_AddContactMenuItem(&mi);
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/AddToServerList");
+ CreateProtoService("/AddToServerList", &CAimProto::AddToServerList);
+ mi.position = -2000005080;
+ mi.icolibItem = GetIconHandle("add");
+ mi.pszName = LPGEN("Add To Server List");
+ mi.flags = CMIF_NOTONLINE | CMIF_HIDDEN | CMIF_ICONFROMICOLIB;
+ hAddToServerListContextMenuItem = Menu_AddContactMenuItem(&mi);
+
+ mir_snprintf(service_name, sizeof(service_name), "%s%s", m_szModuleName, "/BlockCommand");
+ CreateProtoService("/BlockCommand", &CAimProto::BlockBuddy);
+ mi.position = -2000005060;
+ mi.icolibItem = GetIconHandle("block");
+ mi.pszName = LPGEN("&Block");
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_HIDDEN;
+ hBlockContextMenuItem = Menu_AddContactMenuItem(&mi);
+}
+
+void CAimProto::RemoveMainMenus(void)
+{
+ if (hMenuRoot)
+ CallService(MS_CLIST_REMOVEMAINMENUITEM, (WPARAM)hMenuRoot, 0);
+}
+
+void CAimProto::RemoveContactMenus(void)
+{
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hHTMLAwayContextMenuItem, 0);
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hReadProfileMenuItem, 0);
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hAddToServerListContextMenuItem, 0);
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)hBlockContextMenuItem, 0);
+}
diff --git a/protocols/AimOscar/src/theme.h b/protocols/AimOscar/src/theme.h
new file mode 100644
index 0000000000..41b098aff6
--- /dev/null
+++ b/protocols/AimOscar/src/theme.h
@@ -0,0 +1,46 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef THEME_H
+#define THEME_H
+
+extern HMODULE themeAPIHandle;
+extern HANDLE (WINAPI *MyOpenThemeData)(HWND,LPCWSTR);
+extern HRESULT (WINAPI *MyCloseThemeData)(HANDLE);
+extern HRESULT (WINAPI *MyDrawThemeBackground)(HANDLE,HDC,int,int,const RECT *,const RECT *);
+
+void InitThemeSupport(void);
+void InitIcons(void);
+void InitExtraIcons(void);
+
+void DestroyExtraIcons(void);
+
+HICON LoadIconEx(const char* name, bool big = false);
+HANDLE GetIconHandle(const char* name);
+void ReleaseIconEx(const char* name, bool big = false);
+void WindowSetIcon(HWND hWnd, const char* name);
+void WindowFreeIcon(HWND hWnd);
+
+void add_AT_icons(CAimProto* ppro);
+void remove_AT_icons(CAimProto* ppro);
+void add_ES_icons(CAimProto* ppro);
+void remove_ES_icons(CAimProto* ppro);
+
+void set_contact_icon(CAimProto* ppro, HANDLE hContact);
+
+#endif
diff --git a/protocols/AimOscar/src/thread.cpp b/protocols/AimOscar/src/thread.cpp
new file mode 100644
index 0000000000..e8044f90d2
--- /dev/null
+++ b/protocols/AimOscar/src/thread.cpp
@@ -0,0 +1,92 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+
+void __cdecl CAimProto::accept_file_thread(void* param)//buddy sending file
+{
+ file_transfer *ft = (file_transfer*)param;
+
+ HANDLE hConn = NULL;
+ if (ft->peer_force_proxy) //peer is forcing proxy
+ {
+ hConn = aim_peer_connect(ft->proxy_ip, get_default_port());
+ if (hConn)
+ {
+ LOG("Connected to proxy ip that buddy specified.");
+ ft->hConn = hConn;
+ ForkThread(&CAimProto::aim_proxy_helper, ft);
+ ft->stop_listen();
+ }
+ }
+ else if (ft->me_force_proxy) //we are forcing proxy
+ {
+ hConn = aim_peer_connect(AIM_PROXY_SERVER, get_default_port());
+ if (hConn)
+ {
+ LOG("Connected to proxy ip because we want to use a proxy for the file transfer.");
+ ft->requester = true;
+ ft->hConn = hConn;
+ ForkThread(&CAimProto::aim_proxy_helper, ft);
+ ft->stop_listen();
+ }
+ }
+ else
+ {
+ bool verif = ft->verified_ip != detected_ip;
+ hConn = aim_peer_connect(verif ? ft->verified_ip : ft->local_ip, ft->port);
+ if (hConn)
+ {
+ LOG("Connected to buddy over P2P port via %s ip.", verif ? "verified": "local");
+ ft->accepted = true;
+ ft->hConn = hConn;
+ aim_file_ad(hServerConn, seqno, ft->sn, ft->icbm_cookie, false, ft->max_ver);
+ ForkThread(&CAimProto::aim_dc_helper, ft);
+ ft->stop_listen();
+ }
+ else if (ft->sending)
+ {
+ hConn = aim_peer_connect(AIM_PROXY_SERVER, get_default_port());
+ if (hConn)
+ {
+ ft->hConn = hConn;
+ ft->requester = true;
+ ForkThread(&CAimProto::aim_proxy_helper, ft);
+ ft->stop_listen();
+ }
+ }
+ else
+ {
+ LOG("Failed to connect to buddy- asking buddy to connect to us.");
+ ft->listen(this);
+ ft->requester = true;
+ aim_send_file(hServerConn, seqno, detected_ip, ft->local_port, false, ft);
+ return;
+ }
+ }
+
+ if (hConn == NULL)
+ {
+ if (ft->req_num)
+ {
+ aim_file_ad(hServerConn, seqno, ft->sn, ft->icbm_cookie, true, 0);
+ }
+ sendBroadcast(ft->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
+ ft_list.remove_by_ft(ft);
+ }
+}
diff --git a/protocols/AimOscar/src/tlv.cpp b/protocols/AimOscar/src/tlv.cpp
new file mode 100644
index 0000000000..f458a28eb0
--- /dev/null
+++ b/protocols/AimOscar/src/tlv.cpp
@@ -0,0 +1,103 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "aim.h"
+#include "tlv.h"
+
+TLV::TLV(char* buf)
+{
+ type_=_htons((*(unsigned short*)&buf[0]));
+ length_=_htons((*(unsigned short*)&buf[2]));
+ if (length_ > 0)
+ {
+ value_=(char*)mir_alloc(length_+1);
+ memcpy(value_,&buf[4],length_);
+ }
+ else
+ value_= NULL;
+}
+
+TLV::TLV(unsigned short type, unsigned short length, const char* value)
+{
+ type_ = type;
+ length_ = length;
+ if(length_ > 0)
+ {
+ value_ = (char*)mir_alloc(length_+1);
+ memcpy(value_, value, length_);
+ }
+ else
+ value_= NULL;
+}
+
+TLV::~TLV()
+{
+ mir_free(value_);
+}
+
+unsigned short TLV::ushort(int pos)
+{
+ return _htons(*(unsigned short*)&value_[pos]);
+}
+
+unsigned long TLV::ulong(int pos)
+{
+ return _htonl(*(unsigned long*)&value_[pos]);
+}
+
+unsigned __int64 TLV::u64(int pos)
+{
+ return _htonl64(*(unsigned __int64*)&value_[pos]);
+}
+
+unsigned char TLV::ubyte(int pos)
+{
+ return value_[pos];
+}
+
+char* TLV::part(int pos, int length)//returns part of the tlv value
+{
+ if ((pos + length) > length_) return NULL;
+
+ char* value = (char*)mir_alloc(length + 2);
+ memcpy(value, &value_[pos], length);
+ value[length] = '\0';
+ value[length+1] = '\0';
+
+ return value;
+}
+
+char* TLV::dupw(void)
+{
+ wchar_t *str = (wchar_t*)part(0, length_);
+ wcs_htons(str);
+
+ char* stru = mir_utf8encodeW(str);
+ mir_free(str);
+
+ return stru;
+}
+
+
+unsigned short TLV::whole(char* buf)//returns the whole tlv
+{
+ *(unsigned short*)buf = _htons(type_);
+ *(unsigned short*)&buf[2] = _htons(length_);
+ memcpy(&buf[4], value_, length_);
+ return length_ + TLV_HEADER_SIZE;
+}
diff --git a/protocols/AimOscar/src/tlv.h b/protocols/AimOscar/src/tlv.h
new file mode 100644
index 0000000000..8656453b7b
--- /dev/null
+++ b/protocols/AimOscar/src/tlv.h
@@ -0,0 +1,52 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef TLV_H
+#define TLV_H
+
+#include "packets.h"
+
+#define TLV_HEADER_SIZE 4
+
+class TLV
+{
+private:
+ unsigned short type_;
+ unsigned short length_;
+ char* value_;
+public:
+ TLV(char* buf);
+ TLV(unsigned short type, unsigned short length, const char* value);
+ ~TLV();
+
+ int cmp(unsigned short type) { return type_ == type; }
+ unsigned short len(void) { return length_; }
+ char* val(void) { return value_; }
+
+ char* part(int pos, int length);
+ char* dup(void) { return part(0, length_); };
+ char* dupw(void);
+
+ unsigned short whole(char* buf);
+ unsigned short ushort(int pos=0);
+ unsigned long ulong(int pos=0);
+ unsigned __int64 u64(int pos=0);
+ unsigned char ubyte(int pos=0);
+};
+
+#endif
diff --git a/protocols/AimOscar/src/ui.cpp b/protocols/AimOscar/src/ui.cpp
new file mode 100644
index 0000000000..d4a8116ecd
--- /dev/null
+++ b/protocols/AimOscar/src/ui.cpp
@@ -0,0 +1,1584 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aim.h"
+#include "ui.h"
+
+HANDLE hThemeButton = NULL;
+COLORREF foreground=0;
+COLORREF background=0xffffff;
+COLORREF custColours[16]={0};
+
+static int CALLBACK EnumFontsProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam)
+{
+ if (!IsWindow((HWND) lParam))
+ return FALSE;
+ if (SendMessage((HWND) lParam, CB_FINDSTRINGEXACT, 1, (LPARAM) lpelfe->elfLogFont.lfFaceName) == CB_ERR)
+ SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) lpelfe->elfLogFont.lfFaceName);
+ return TRUE;
+}
+
+void DrawMyControl(HDC hDC, HWND /*hwndButton*/, HANDLE hTheme, UINT iState, RECT rect)
+{
+ BOOL bIsPressed = (iState & ODS_SELECTED);
+ BOOL bIsFocused = (iState & ODS_FOCUS);
+ if (hTheme)
+ {
+ DWORD state = (bIsPressed)?PBS_PRESSED:PBS_NORMAL;
+ if(state == PBS_NORMAL)
+ {
+ if(bIsFocused)
+ state = PBS_DEFAULTED;
+ }
+ rect.top-=1;
+ rect.left-=1;
+ MyDrawThemeBackground(hTheme, hDC, BP_PUSHBUTTON,state, &rect, NULL);
+ }
+ else
+ {
+ if (bIsFocused)
+ {
+ HBRUSH br = CreateSolidBrush(RGB(0,0,0));
+ FrameRect(hDC, &rect, br);
+ InflateRect(&rect, -1, -1);
+ DeleteObject(br);
+ } // if
+ COLORREF crColor = GetSysColor(COLOR_BTNFACE);
+ HBRUSH brBackground = CreateSolidBrush(crColor);
+ FillRect(hDC,&rect, brBackground);
+ DeleteObject(brBackground);
+ // Draw pressed button
+ if (bIsPressed)
+ {
+ HBRUSH brBtnShadow = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
+ FrameRect(hDC, &rect, brBtnShadow);
+ DeleteObject(brBtnShadow);
+ }
+ else // ...else draw non pressed button
+ {
+ UINT uState = DFCS_BUTTONPUSH|(bIsPressed? DFCS_PUSHED : 0);
+ DrawFrameControl(hDC, &rect, DFC_BUTTON, uState);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// User info dialog
+
+static INT_PTR CALLBACK userinfo_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ SendDlgItemMessage(hwndDlg, IDC_BOLD, BUTTONSETASPUSHBTN, TRUE, 0);
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETEVENTMASK, 0, ENM_CHANGE|ENM_SELCHANGE|ENM_REQUESTRESIZE);
+ SendDlgItemMessage(hwndDlg, IDC_BACKGROUNDCOLORPICKER, CPM_SETCOLOUR, 0, 0x00ffffff);
+ LOGFONT lf ={0};
+ HDC hdc = GetDC(hwndDlg);
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfFaceName[0] = 0;
+ lf.lfPitchAndFamily = 0;
+ EnumFontFamiliesEx(hdc, &lf, (FONTENUMPROC) EnumFontsProc, (LPARAM) GetDlgItem(hwndDlg, IDC_TYPEFACE), 0);
+ ReleaseDC(hwndDlg, hdc);
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("8"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("10"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("12"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("14"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("18"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("24"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_ADDSTRING, 0, (LPARAM)TEXT("36"));
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_SETCURSEL, 2, 0);
+ if (SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_SELECTSTRING, 1, (LPARAM)TEXT("Arial"))!=CB_ERR)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(cf);
+ cf.yHeight=12*20;
+ cf.dwMask=CFM_SIZE|CFM_FACE;
+ _tcscpy(cf.szFaceName, TEXT("Arial"));
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ else
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(cf);
+ cf.yHeight=12*20;
+ cf.dwMask=CFM_SIZE;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ }
+ break;
+ }
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 0);
+ break;
+
+ case WM_SIZING:
+ {
+ RECT* rect=(RECT*)lParam;
+#define MIN_HEIGHT 200
+#define MIN_WIDTH 400
+ if (WMSZ_RIGHT==wParam||WMSZ_TOPRIGHT==wParam||WMSZ_BOTTOMRIGHT==wParam)
+ {
+ if(rect->right-rect->left<MIN_WIDTH)
+ rect->right=rect->left+MIN_WIDTH;
+ }
+ if (WMSZ_LEFT==wParam||WMSZ_TOPLEFT==wParam||WMSZ_BOTTOMLEFT==wParam)
+ {
+ if(rect->right-rect->left<MIN_WIDTH)
+ rect->left=rect->right-MIN_WIDTH;
+ }
+ if (WMSZ_TOP==wParam||WMSZ_TOPRIGHT==wParam||WMSZ_TOPLEFT==wParam)
+ {
+ if(rect->bottom-rect->top<MIN_HEIGHT)
+ rect->top=rect->bottom-MIN_HEIGHT;
+ }
+ if (WMSZ_BOTTOM==wParam||WMSZ_BOTTOMLEFT==wParam||WMSZ_BOTTOMRIGHT==wParam)
+ {
+ if(rect->bottom-rect->top<MIN_HEIGHT)
+ rect->bottom=rect->top+MIN_HEIGHT;
+ }
+ break;
+ }
+
+ case WM_SIZE:
+ {
+ int width=LOWORD(lParam);
+ int height=HIWORD(lParam);
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_PROFILE),HWND_TOP,6,60,width-12,height-67,0); // this 'case' should go away
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_SETPROFILE),HWND_TOP,width-97,height-224,0,0,SWP_NOSIZE); // since there's no profile window resize anymore
+ break;
+ }
+ case WM_NOTIFY:
+ switch (LOWORD(wParam))
+ {
+ case IDC_PROFILE:
+ if (((LPNMHDR)lParam)->code==EN_SELCHANGE)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_FACE | CFM_SIZE;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ if (SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_SELECTSTRING, 1, (LPARAM)cfOld.szFaceName)==-1)
+ {
+ SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_ADDSTRING, 0, (LPARAM)cfOld.szFaceName);
+ SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_SELECTSTRING, 1, (LPARAM)cfOld.szFaceName);
+ }
+ char size[10];
+ _itoa(cfOld.yHeight/20,size,sizeof(size));
+ //SetDlgItemText(hwndDlg, IDC_FONTSIZE, size);
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_SELECTSTRING, 1, (LPARAM)size);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_SUPERSCRIPT), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_NORMALSCRIPT), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_SUBSCRIPT), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_BOLD), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_ITALIC), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_UNDERLINE), NULL, FALSE);
+ }
+ else if (((LPNMHDR)lParam)->code==EN_REQUESTRESIZE)
+ {
+ // REQRESIZE* rr= (REQRESIZE*)lParam;
+ //SetWindowPos(GetDlgItem(hwndDlg, IDC_PROFILE),HWND_TOP,rr->rc.left,rr->rc.top,rr->rc.right,rr->rc.bottom,0);
+ }
+ break;
+
+ default:
+ if (((LPNMHDR)lParam)->code == PSN_PARAMCHANGED)
+ {
+ ppro = (CAimProto*)((PSHNOTIFY*)lParam)->lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, LPARAM(ppro));
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingStringUtf(NULL, ppro->m_szModuleName, AIM_KEY_PR, &dbv))
+ {
+ html_decode(dbv.pszVal);
+ TCHAR *txt = mir_utf8decodeT(dbv.pszVal);
+ SetDlgItemText(hwndDlg, IDC_PROFILE, txt);
+ mir_free(txt);
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+ break;
+
+ case WM_DRAWITEM:
+ {
+ if (themeAPIHandle)
+ {
+ MyCloseThemeData (hThemeButton);
+ hThemeButton = MyOpenThemeData (GetDlgItem(hwndDlg, IDC_BOLD), L"Button");
+ }
+ LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam;
+ if (lpDIS->CtlID == IDC_SUPERSCRIPT)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_SUPERSCRIPT;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isSuper = (cfOld.dwEffects & CFE_SUPERSCRIPT) && (cfOld.dwMask & CFM_SUPERSCRIPT);
+ if(isSuper)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState|ODS_SELECTED, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("sup_scrpt"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("sup_scrpt");
+ }
+ else
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nsup_scrpt"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("nsup_scrpt");
+ }
+ }
+ else if (lpDIS->CtlID == IDC_NORMALSCRIPT)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_SUBSCRIPT|CFM_SUPERSCRIPT;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isSub = (cfOld.dwEffects & CFE_SUBSCRIPT) && (cfOld.dwMask & CFM_SUBSCRIPT);
+ BOOL isSuper = (cfOld.dwEffects & CFE_SUPERSCRIPT) && (cfOld.dwMask & CFM_SUPERSCRIPT);
+ if (!isSub&&!isSuper)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState|ODS_SELECTED, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("norm_scrpt"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("norm_scrpt");
+ }
+ else
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nnorm_scrpt"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("nnorm_scrpt");
+ }
+ }
+ else if (lpDIS->CtlID == IDC_SUBSCRIPT)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_SUBSCRIPT;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isSub = (cfOld.dwEffects & CFE_SUBSCRIPT) && (cfOld.dwMask & CFM_SUBSCRIPT);
+ if(isSub)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState|ODS_SELECTED, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("sub_scrpt"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("sub_scrpt");
+ }
+ else
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nsub_scrpt"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("nsub_scrpt");
+ }
+ }
+ else if (lpDIS->CtlID == IDC_BOLD)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_BOLD;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
+ if (!isBold)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nbold"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("nbold");
+ }
+ else
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BOLD),hThemeButton,lpDIS->itemState|ODS_SELECTED, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("bold"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("bold");
+ }
+ }
+ else if(lpDIS->CtlID == IDC_ITALIC)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_ITALIC;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
+ if (!isItalic)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_ITALIC),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nitalic"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("nitalic");
+ }
+ else
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_ITALIC),hThemeButton,lpDIS->itemState|ODS_SELECTED, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("italic"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("italic");
+ }
+ }
+ else if (lpDIS->CtlID == IDC_UNDERLINE)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_UNDERLINE;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
+ if (!isUnderline)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_UNDERLINE),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("nundrln"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("nundrln");
+ }
+ else
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_UNDERLINE),hThemeButton,lpDIS->itemState|ODS_SELECTED, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 5, LoadIconEx("undrln"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("undrln");
+ }
+ }
+ else if (lpDIS->CtlID == IDC_FOREGROUNDCOLOR)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLOR),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 2, LoadIconEx("foreclr"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("foreclr");
+ HBRUSH hbr = CreateSolidBrush(foreground);
+ HPEN hp = CreatePen(PS_SOLID, 1, ~foreground&0x00ffffff);
+ SelectObject(lpDIS->hDC,hp);
+ RECT rect=lpDIS->rcItem;
+ rect.top+=18;
+ rect.bottom-=4;
+ rect.left+=5;
+ rect.right-=5;
+ Rectangle(lpDIS->hDC,rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
+ FillRect(lpDIS->hDC,&rect, hbr);
+ DeleteObject(hbr);
+ DeleteObject(hp);
+ }
+ else if (lpDIS->CtlID == IDC_FOREGROUNDCOLORPICKER)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLORPICKER),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ HBRUSH hbr = CreateSolidBrush(foreground);
+ HPEN hp = CreatePen(PS_SOLID, 1,~foreground&0x00ffffff);
+ SelectObject(lpDIS->hDC,hbr);
+ SelectObject(lpDIS->hDC,hp);
+ POINT tri[3];
+ tri[0].x=3;
+ tri[0].y=10;
+ tri[1].x=9;
+ tri[1].y=10;
+ tri[2].x=6;
+ tri[2].y=15;
+ Polygon(lpDIS->hDC,tri,3);
+ DeleteObject(hbr);
+ DeleteObject(hp);
+ }
+ else if (lpDIS->CtlID == IDC_BACKGROUNDCOLOR)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BACKGROUNDCOLOR),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ DrawIconEx(lpDIS->hDC, 4, 2, LoadIconEx("backclr"), 16, 16, 0, 0, DI_NORMAL);
+ ReleaseIconEx("backclr");
+ HBRUSH hbr = CreateSolidBrush(background);
+ HPEN hp = CreatePen(PS_SOLID, 1, ~background&0x00ffffff);
+ SelectObject(lpDIS->hDC,hp);
+ RECT rect=lpDIS->rcItem;
+ rect.top+=18;
+ rect.bottom-=4;
+ rect.left+=5;
+ rect.right-=5;
+ Rectangle(lpDIS->hDC,rect.left-1,rect.top-1,rect.right+1,rect.bottom+1);
+ FillRect(lpDIS->hDC,&rect, hbr);
+ DeleteObject(hbr);
+ DeleteObject(hp);
+ }
+ else if (lpDIS->CtlID == IDC_BACKGROUNDCOLORPICKER)
+ {
+ DrawMyControl(lpDIS->hDC,GetDlgItem(hwndDlg, IDC_BACKGROUNDCOLORPICKER),hThemeButton,lpDIS->itemState, lpDIS->rcItem);
+ HBRUSH hbr = CreateSolidBrush(background);
+ HPEN hp = CreatePen(PS_SOLID, 1,~background&0x00ffffff);
+ SelectObject(lpDIS->hDC,hbr);
+ SelectObject(lpDIS->hDC,hp);
+ POINT tri[3];
+ tri[0].x=3;
+ tri[0].y=10;
+ tri[1].x=9;
+ tri[1].y=10;
+ tri[2].x=6;
+ tri[2].y=15;
+ Polygon(lpDIS->hDC,tri,3);
+ DeleteObject(hbr);
+ DeleteObject(hp);
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_PROFILE:
+ if (HIWORD(wParam) == EN_CHANGE)
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SETPROFILE), TRUE);
+ break;
+
+ case IDC_SETPROFILE:
+ {
+ char* buf = rtf_to_html(hwndDlg, IDC_PROFILE);
+ DBWriteContactSettingStringUtf(NULL, ppro->m_szModuleName, AIM_KEY_PR, buf);
+ if (ppro->state==1)
+ ppro->aim_set_profile(ppro->hServerConn, ppro->seqno, buf);//also see set caps for profile setting
+
+ mir_free(buf);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SETPROFILE), FALSE);
+ }
+ break;
+
+ case IDC_SUPERSCRIPT:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask=CFM_SUPERSCRIPT;
+ cf.dwEffects=CFE_SUPERSCRIPT;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_NORMALSCRIPT), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_SUBSCRIPT), NULL, FALSE);
+ }
+ break;
+
+ case IDC_NORMALSCRIPT:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask=CFM_SUPERSCRIPT;
+ cf.dwEffects &= ~CFE_SUPERSCRIPT;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_SUPERSCRIPT), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_SUBSCRIPT), NULL, FALSE);
+ }
+ break;
+
+ case IDC_SUBSCRIPT:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask=CFM_SUBSCRIPT;
+ cf.dwEffects=CFE_SUBSCRIPT;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_SUPERSCRIPT), NULL, FALSE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_NORMALSCRIPT), NULL, FALSE);
+ }
+ break;
+
+ case IDC_BOLD:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_BOLD;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isBold = (cfOld.dwEffects & CFE_BOLD) && (cfOld.dwMask & CFM_BOLD);
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwEffects = isBold ? 0 : CFE_BOLD;
+ cf.dwMask = CFM_BOLD;
+ CheckDlgButton(hwndDlg, IDC_BOLD, !isBold);
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_ITALIC:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_ITALIC;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isItalic = (cfOld.dwEffects & CFE_ITALIC) && (cfOld.dwMask & CFM_ITALIC);
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwEffects = isItalic ? 0 : CFE_ITALIC;
+ cf.dwMask = CFM_ITALIC;
+ CheckDlgButton(hwndDlg, IDC_ITALIC, !isItalic);
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_UNDERLINE:
+ if(HIWORD(wParam)==BN_CLICKED)
+ {
+ CHARFORMAT2 cfOld;
+ cfOld.cbSize = sizeof(CHARFORMAT2);
+ cfOld.dwMask = CFM_UNDERLINE;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cfOld);
+ BOOL isUnderline = (cfOld.dwEffects & CFE_UNDERLINE) && (cfOld.dwMask & CFM_UNDERLINE);
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwEffects = isUnderline ? 0 : CFE_UNDERLINE;
+ cf.dwMask = CFM_UNDERLINE;
+ CheckDlgButton(hwndDlg, IDC_UNDERLINE, !isUnderline);
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_FOREGROUNDCOLOR:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask=CFM_COLOR;
+ cf.dwEffects=0;
+ cf.crTextColor=foreground;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLORPICKER),GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLOR),0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_FOREGROUNDCOLORPICKER:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHOOSECOLOR cc={0};
+ custColours[0]=foreground;
+ custColours[1]=background;
+ cc.lStructSize=sizeof(CHOOSECOLOR);
+ cc.hwndOwner=hwndDlg;
+ cc.hInstance=(HWND)GetModuleHandle(NULL);
+ cc.lpCustColors=custColours;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(ChooseColor(&cc))
+ {
+ foreground=cc.rgbResult;
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FOREGROUNDCOLOR), NULL, FALSE);
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_BACKGROUNDCOLOR:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask=CFM_BACKCOLOR;
+ cf.dwEffects=0;
+ cf.crBackColor=background;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_BACKGROUNDCOLORPICKER:
+ if(HIWORD(wParam)==BN_CLICKED)
+ {
+ CHOOSECOLOR cc={0};
+ custColours[0]=foreground;
+ custColours[1]=background;
+ cc.lStructSize=sizeof(CHOOSECOLOR);
+ cc.hwndOwner=hwndDlg;
+ cc.hInstance=(HWND)GetModuleHandle(NULL);
+ cc.lpCustColors=custColours;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(ChooseColor(&cc))
+ {
+ background=cc.rgbResult;
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_BACKGROUNDCOLOR), NULL, FALSE);
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ }
+ break;
+
+ case IDC_TYPEFACE:
+ if (HIWORD(wParam)==CBN_SELENDOK)
+ {
+ CHARFORMAT2A cf;
+ cf.cbSize = sizeof(cf);
+ cf.dwMask=CFM_FACE;
+ cf.dwEffects=0;
+ SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_GETLBTEXT, SendDlgItemMessage(hwndDlg, IDC_TYPEFACE, CB_GETCURSEL, 0, 0),(LPARAM)cf.szFaceName);
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ break;
+ }
+ break;
+
+ case IDC_FONTSIZE:
+ if (HIWORD(wParam)==CBN_SELENDOK)
+ {
+ CHARFORMAT2 cf;
+ cf.cbSize = sizeof(CHARFORMAT2);
+ cf.dwMask=CFM_SIZE;
+ cf.dwEffects=0;
+ char chsize[5] = "";
+ SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETLBTEXT, SendDlgItemMessage(hwndDlg, IDC_FONTSIZE, CB_GETCURSEL, 0, 0),(LPARAM)chsize);
+ //strlcpy(cf.szFaceName,size,strlen(size)+1);
+ cf.yHeight=atoi(chsize)*20;
+ SendDlgItemMessage(hwndDlg, IDC_PROFILE, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
+ SetFocus(GetDlgItem(hwndDlg, IDC_PROFILE));
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// View admin dialog
+
+INT_PTR CALLBACK admin_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ DBVARIANT dbv;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_FNAME, EM_LIMITTEXT, 63, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CEMAIL, EM_LIMITTEXT, 253, 0);
+ SendDlgItemMessage(hwndDlg, IDC_CPW, EM_LIMITTEXT, 253, 0);
+ SendDlgItemMessage(hwndDlg, IDC_NPW1, EM_LIMITTEXT, 253, 0);
+ SendDlgItemMessage(hwndDlg, IDC_NPW2, EM_LIMITTEXT, 253, 0);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_PARAMCHANGED:
+ ppro = (CAimProto*)((LPPSHNOTIFY)lParam)->lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)ppro);
+
+ if (ppro->wait_conn(ppro->hAdminConn, ppro->hAdminEvent, 0x07)) // Make a connection
+ {
+ ppro->aim_admin_request_info(ppro->hAdminConn,ppro->admin_seqno,0x01); // Get our screenname
+ ppro->aim_admin_request_info(ppro->hAdminConn,ppro->admin_seqno,0x11); // Get our email
+ }
+
+ case PSN_INFOCHANGED:
+ if (!ppro->getString(AIM_KEY_SN, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_FNAME, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ if (!ppro->getString(AIM_KEY_EM, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_CEMAIL, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_SAVECHANGES)
+ {
+ if (!ppro->wait_conn(ppro->hAdminConn, ppro->hAdminEvent, 0x07)) // Make a connection
+ break;
+
+ char name[64];
+ GetDlgItemTextA(hwndDlg, IDC_FNAME, name, sizeof(name));
+ if (strlen(trim_str(name)) > 0 && !ppro->getString(AIM_KEY_SN, &dbv))
+ {
+ if (strcmp(name, dbv.pszVal))
+ ppro->aim_admin_format_name(ppro->hAdminConn,ppro->admin_seqno,name);
+ DBFreeVariant(&dbv);
+ }
+
+ char email[254];
+ GetDlgItemTextA(hwndDlg, IDC_CEMAIL, email, sizeof(email));
+ if (strlen(trim_str(email)) > 1 && !ppro->getString(AIM_KEY_EM, &dbv)) // Must be greater than 1 or a SNAC error is thrown.
+ {
+ if (strcmp(email, dbv.pszVal))
+ ppro->aim_admin_change_email(ppro->hAdminConn,ppro->admin_seqno,email);
+ DBFreeVariant(&dbv);
+ }
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PINFO), SW_HIDE);
+
+ char cpw[256], npw1[256], npw2[256];
+ GetDlgItemTextA(hwndDlg, IDC_CPW, cpw, sizeof(cpw));
+ GetDlgItemTextA(hwndDlg, IDC_NPW1, npw1, sizeof(npw1));
+ GetDlgItemTextA(hwndDlg, IDC_NPW2, npw2, sizeof(npw2));
+ if (strlen(cpw) > 0 && strlen(npw1) > 0 && strlen(npw2) > 0)
+ {
+ // AOL only requires that you send the current password and a (single) new password.
+ // Let's allow the client to type (two) new passwords incase they make a mistake so we
+ // can handle any input error locally.
+ if (strcmp(npw1,npw2) == 0)
+ {
+ ppro->aim_admin_change_password(ppro->hAdminConn,ppro->admin_seqno,cpw,npw1);
+ }
+ else
+ {
+ SetDlgItemTextA(hwndDlg, IDC_CPW, "");
+ SetDlgItemTextA(hwndDlg, IDC_NPW1, "");
+ SetDlgItemTextA(hwndDlg, IDC_NPW2, "");
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PINFO), SW_SHOW);
+ }
+ }
+ }
+ else if (LOWORD(wParam) == IDC_CONFIRM) // Confirmation
+ {
+ if (ppro->wait_conn(ppro->hAdminConn, ppro->hAdminEvent, 0x07)) // Make a connection
+ ppro->aim_admin_account_confirm(ppro->hAdminConn,ppro->admin_seqno);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int CAimProto::OnUserInfoInit(WPARAM wParam,LPARAM lParam)
+{
+ if (!lParam)//hContact
+ {
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -1900000000;
+ odp.flags = ODPF_USERINFOTAB | ODPF_TCHAR;
+ odp.hInstance = hInstance;
+ odp.ptszTitle = m_tszUserName;
+ odp.dwInitParam = LPARAM(this);
+
+ odp.ptszTab = LPGENT("Profile");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO);
+ odp.pfnDlgProc = userinfo_dialog;
+ UserInfo_AddPage(wParam, &odp);
+
+ odp.ptszTab = LPGENT("Admin");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_ADMIN);
+ odp.pfnDlgProc = admin_dialog;
+ UserInfo_AddPage(wParam, &odp);
+ }
+ return 0;
+}
+
+INT_PTR CAimProto::EditProfile(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+ DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_AIM), NULL, userinfo_dialog, LPARAM(this));
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Options dialog
+
+static INT_PTR CALLBACK options_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ ppro = (CAimProto*)lParam;
+ {
+ DBVARIANT dbv;
+ if (!ppro->getString(AIM_KEY_SN, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_SN, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ if (!ppro->getString(AIM_KEY_NK, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_NK, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else if (!ppro->getString(AIM_KEY_SN, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_NK, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ if (!ppro->getString(AIM_KEY_PW, &dbv))
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM) dbv.pszVal);
+ SetDlgItemTextA(hwndDlg, IDC_PW, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ if (!ppro->getString(AIM_KEY_HN, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_HN, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else
+ SetDlgItemTextA(hwndDlg, IDC_HN, ppro->getByte(AIM_KEY_DSSL, 0) ? AIM_DEFAULT_SERVER_NS : AIM_DEFAULT_SERVER);
+
+ SetDlgItemInt(hwndDlg, IDC_PN, ppro->get_default_port(), FALSE);
+
+ CheckDlgButton(hwndDlg, IDC_DC, ppro->getByte(AIM_KEY_DC, 0));//Message Delivery Confirmation
+ CheckDlgButton(hwndDlg, IDC_FP, ppro->getByte(AIM_KEY_FP, 0));//force proxy
+ CheckDlgButton(hwndDlg, IDC_AT, ppro->getByte(AIM_KEY_AT, 0));//Account Type Icons
+ CheckDlgButton(hwndDlg, IDC_ES, ppro->getByte(AIM_KEY_ES, 0));//Extended Status Type Icons
+ CheckDlgButton(hwndDlg, IDC_HF, ppro->getByte(AIM_KEY_HF, 0));//Fake hiptopness
+ CheckDlgButton(hwndDlg, IDC_DM, ppro->getByte(AIM_KEY_DM, 0));//Disable Sending Mode Message
+ CheckDlgButton(hwndDlg, IDC_FI, ppro->getByte(AIM_KEY_FI, 1));//Format incoming messages
+ CheckDlgButton(hwndDlg, IDC_FO, ppro->getByte(AIM_KEY_FO, 1));//Format outgoing messages
+ CheckDlgButton(hwndDlg, IDC_II, ppro->getByte(AIM_KEY_II, 0));//Instant Idle
+ CheckDlgButton(hwndDlg, IDC_CM, ppro->getByte(AIM_KEY_CM, 0));//Check Mail
+ CheckDlgButton(hwndDlg, IDC_MG, ppro->getByte(AIM_KEY_MG, 1));//Manage Groups
+ CheckDlgButton(hwndDlg, IDC_DA, ppro->getByte(AIM_KEY_DA, 0));//Disable Avatars
+ CheckDlgButton(hwndDlg, IDC_DSSL, ppro->getByte(AIM_KEY_DSSL, 0));//Disable SSL
+ CheckDlgButton(hwndDlg, IDC_FSC, ppro->getByte(AIM_KEY_FSC, 0));//Force Single Client
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_DSSL:
+ {
+ bool dssl = IsDlgButtonChecked(hwndDlg, IDC_DSSL) != 0;
+ SetDlgItemTextA(hwndDlg, IDC_HN, dssl ? AIM_DEFAULT_SERVER_NS : AIM_DEFAULT_SERVER);
+ SetDlgItemInt(hwndDlg, IDC_PN, dssl ? AIM_DEFAULT_PORT : AIM_DEFAULT_SSL_PORT, FALSE);
+ }
+ break;
+
+ case IDC_SVRRESET:
+ SetDlgItemTextA(hwndDlg, IDC_HN,
+ IsDlgButtonChecked(hwndDlg, IDC_DSSL) ? AIM_DEFAULT_SERVER_NS : AIM_DEFAULT_SERVER);
+ SetDlgItemInt(hwndDlg, IDC_PN,ppro->get_default_port(), FALSE);
+ break;
+
+ case IDC_SN:
+ case IDC_PN:
+ case IDC_NK:
+ case IDC_PW:
+ case IDC_HN:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
+ return 0;
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ char str[128];
+ //SN
+ GetDlgItemTextA(hwndDlg, IDC_SN, str, sizeof(str));
+ if(strlen(str)>0)
+ ppro->setString(AIM_KEY_SN, str);
+ else
+ ppro->deleteSetting(NULL, AIM_KEY_SN);
+ //END SN
+
+ //NK
+ if(GetDlgItemTextA(hwndDlg, IDC_NK, str, sizeof(str)))
+ ppro->setString(AIM_KEY_NK, str);
+ else
+ {
+ GetDlgItemTextA(hwndDlg, IDC_SN, str, sizeof(str));
+ ppro->setString(AIM_KEY_NK, str);
+ }
+ //END NK
+
+ //PW
+ GetDlgItemTextA(hwndDlg, IDC_PW, str, sizeof(str));
+ if(strlen(str)>0)
+ {
+ CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), (LPARAM) str);
+ ppro->setString(AIM_KEY_PW, str);
+ }
+ else
+ ppro->deleteSetting(NULL, AIM_KEY_PW);
+ //END PW
+
+ //HN
+ GetDlgItemTextA(hwndDlg, IDC_HN, str, sizeof(str));
+ if(strlen(str)>0 && strcmp(str, AIM_DEFAULT_SERVER))
+ ppro->setString(AIM_KEY_HN, str);
+ else
+ ppro->deleteSetting(NULL, AIM_KEY_HN);
+ //END HN
+
+ //Delivery Confirmation
+ ppro->setByte(AIM_KEY_DC, IsDlgButtonChecked(hwndDlg, IDC_DC) != 0);
+ //End Delivery Confirmation
+
+ //Disable Avatar
+ ppro->setByte(AIM_KEY_DA, IsDlgButtonChecked(hwndDlg, IDC_DA) != 0);
+ //Disable Avatar
+
+ //Disable SSL
+ ppro->setByte(AIM_KEY_DSSL, IsDlgButtonChecked(hwndDlg, IDC_DSSL) != 0);
+ //Disable SSL
+
+ //Force Single Login
+ ppro->setByte(AIM_KEY_FSC, IsDlgButtonChecked(hwndDlg, IDC_FSC) != 0);
+ //Force Single Login
+
+ //Force Proxy Transfer
+ ppro->setByte(AIM_KEY_FP, IsDlgButtonChecked(hwndDlg, IDC_FP) != 0);
+ //End Force Proxy Transfer
+
+ //PN
+ int port = GetDlgItemInt(hwndDlg, IDC_PN, NULL, FALSE);
+ if(port > 0 && port != ppro->getByte(AIM_KEY_DSSL, 0) ? AIM_DEFAULT_PORT : AIM_DEFAULT_SSL_PORT)
+ ppro->setWord(AIM_KEY_PN, (WORD)port);
+ else
+ ppro->deleteSetting(NULL, AIM_KEY_PN);
+ //END PN
+
+ //Disable Account Type Icons
+ if (IsDlgButtonChecked(hwndDlg, IDC_AT))
+ {
+ int acc_disabled = ppro->getByte(AIM_KEY_AT, 0);
+ if (!acc_disabled)
+ remove_AT_icons(ppro);
+ ppro->setByte(AIM_KEY_AT, 1);
+ }
+ else
+ {
+ int acc_disabled = ppro->getByte(AIM_KEY_AT, 0);
+ if(acc_disabled)
+ add_AT_icons(ppro);
+ ppro->setByte(AIM_KEY_AT, 0);
+ }
+ //END
+ //Disable Extra Status Icons
+ if (IsDlgButtonChecked(hwndDlg, IDC_ES))
+ {
+ int es_disabled = ppro->getByte(AIM_KEY_ES, 0);
+ ppro->setByte(AIM_KEY_ES, 1);
+ if (!es_disabled)
+ remove_ES_icons(ppro);
+ }
+ else
+ {
+ int es_disabled = ppro->getByte(AIM_KEY_ES, 0);
+ ppro->setByte(AIM_KEY_ES, 0);
+ if(es_disabled)
+ add_ES_icons(ppro);
+ }
+ //End
+
+ //Fake Hiptop
+ if (IsDlgButtonChecked(hwndDlg, IDC_HF))
+ {
+ int hf = ppro->getByte(AIM_KEY_HF, 0);
+ if (!hf)
+ ShowWindow(GetDlgItem(hwndDlg, IDC_MASQ), SW_SHOW);
+ ppro->setByte(AIM_KEY_HF, 1);
+ }
+ else
+ {
+ int hf = ppro->getByte(AIM_KEY_HF, 0);
+ if(hf)
+ ShowWindow(GetDlgItem(hwndDlg, IDC_MASQ), SW_SHOW);
+ ppro->setByte(AIM_KEY_HF, 0);
+ }
+ //End
+
+ //Disable Mode Message Sending
+ ppro->setByte(AIM_KEY_DM, IsDlgButtonChecked(hwndDlg, IDC_DM) != 0);
+ //End Disable Mode Message Sending
+
+ //Format Incoming Messages
+ ppro->setByte(AIM_KEY_FI, IsDlgButtonChecked(hwndDlg, IDC_FI) != 0);
+ //End Format Incoming Messages
+
+ //Format Outgoing Messages
+ ppro->setByte(AIM_KEY_FO, IsDlgButtonChecked(hwndDlg, IDC_FO) != 0);
+ //End Format Outgoing Messages
+
+ //Instant Idle on Login
+ ppro->setByte(AIM_KEY_II, IsDlgButtonChecked(hwndDlg, IDC_II) != 0);
+ //End
+ //Check Mail on Login
+ ppro->setByte(AIM_KEY_CM, IsDlgButtonChecked(hwndDlg, IDC_CM) != 0);
+ //End
+
+ //Manage Groups
+ ppro->setByte(AIM_KEY_MG, IsDlgButtonChecked(hwndDlg, IDC_MG) != 0);
+ //End
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+static INT_PTR CALLBACK privacy_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static const int btns[] = { IDC_ALLOWALL, IDC_BLOCKALL, IDC_ALLOWBELOW, IDC_BLOCKBELOW, IDC_ALLOWCONT };
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ int i;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ ppro = (CAimProto*)lParam;
+
+ CheckRadioButton(hwndDlg, IDC_ALLOWALL, IDC_BLOCKBELOW, btns[ppro->pd_mode-1]);
+
+ for (i=0; i<ppro->allow_list.getCount(); ++i)
+ SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_ADDSTRING, 0, (LPARAM)ppro->allow_list[i].name);
+
+ for (i=0; i<ppro->block_list.getCount(); ++i)
+ SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_ADDSTRING, 0, (LPARAM)ppro->block_list[i].name);
+
+ CheckDlgButton (hwndDlg, IDC_SIS, (ppro->pref1_flags & 0x400) ? BST_CHECKED : BST_CHECKED);
+ break;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_ALLOWADD)
+ {
+ char nick[80];
+ SendDlgItemMessageA(hwndDlg, IDC_ALLOWEDIT, WM_GETTEXT, 80, (LPARAM)nick);
+ SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_ADDSTRING, 0, (LPARAM)trim_str(nick));
+ }
+ else if (LOWORD(wParam) == IDC_BLOCKADD)
+ {
+ char nick[80];
+ SendDlgItemMessageA(hwndDlg, IDC_BLOCKEDIT, WM_GETTEXT, 80, (LPARAM)nick);
+ SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_ADDSTRING, 0, (LPARAM)trim_str(nick));
+ }
+ else if (LOWORD(wParam) == IDC_ALLOWREMOVE)
+ {
+ i = SendDlgItemMessage(hwndDlg, IDC_ALLOWLIST, LB_GETCURSEL, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_ALLOWLIST, LB_DELETESTRING, i, 0);
+ }
+ else if (LOWORD(wParam) == IDC_BLOCKREMOVE)
+ {
+ i = SendDlgItemMessage(hwndDlg, IDC_BLOCKLIST, LB_GETCURSEL, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDC_BLOCKLIST, LB_DELETESTRING, i, 0);
+ }
+
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->code == PSN_APPLY)
+ {
+ ppro->aim_ssi_update(ppro->hServerConn, ppro->seqno, true);
+ for (i=0; i<5; ++i)
+ {
+ if (IsDlgButtonChecked(hwndDlg, btns[i]) && ppro->pd_mode != i + 1)
+ {
+ ppro->pd_mode = (char)(i + 1);
+ ppro->pd_flags = 1;
+ ppro->aim_set_pd_info(ppro->hServerConn, ppro->seqno);
+ break;
+ }
+ }
+ for (i=0; i<ppro->block_list.getCount(); ++i)
+ {
+ BdListItem& pd = ppro->block_list[i];
+ if (SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pd.name) == LB_ERR)
+ {
+ ppro->aim_delete_contact(ppro->hServerConn, ppro->seqno, pd.name, pd.item_id, 0, 3, false);
+ ppro->block_list.remove(i--);
+ }
+ }
+ i = SendDlgItemMessage(hwndDlg, IDC_BLOCKLIST, LB_GETCOUNT, 0, 0);
+ for (; i--;)
+ {
+ char nick[80];
+ SendDlgItemMessageA(hwndDlg, IDC_BLOCKLIST, LB_GETTEXT, i, (LPARAM)nick);
+ if (ppro->block_list.find_id(nick) == 0)
+ {
+ unsigned short id = ppro->block_list.add(nick);
+ ppro->aim_add_contact(ppro->hServerConn, ppro->seqno, nick, id, 0, 3);
+ }
+ }
+
+ for (i=0; i<ppro->allow_list.getCount(); ++i)
+ {
+ BdListItem& pd = ppro->allow_list[i];
+ if (SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_FINDSTRING, (WPARAM)-1, (LPARAM)pd.name) == LB_ERR)
+ {
+ ppro->aim_delete_contact(ppro->hServerConn, ppro->seqno, pd.name, pd.item_id, 0, 2, false);
+ ppro->allow_list.remove(i--);
+ }
+ }
+ i = SendDlgItemMessage(hwndDlg, IDC_ALLOWLIST, LB_GETCOUNT, 0, 0);
+ for (; i--;)
+ {
+ char nick[80];
+ SendDlgItemMessageA(hwndDlg, IDC_ALLOWLIST, LB_GETTEXT, i, (LPARAM)nick);
+ if (ppro->allow_list.find_id(nick) == 0)
+ {
+ unsigned short id = ppro->allow_list.add(nick);
+ ppro->aim_add_contact(ppro->hServerConn, ppro->seqno, nick, id, 0, 2);
+ }
+ }
+
+ unsigned mask = (IsDlgButtonChecked(hwndDlg, IDC_SIS) == BST_CHECKED) << 10;
+ if ((ppro->pref1_flags & 0x400) ^ mask)
+ {
+ ppro->pref1_flags = (ppro->pref1_flags & ~0x400) | mask;
+ ppro->aim_ssi_update_preferences(ppro->hServerConn, ppro->seqno);
+ }
+
+ ppro->aim_ssi_update(ppro->hServerConn, ppro->seqno, false);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+int CAimProto::OnOptionsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 1003000;
+ odp.hInstance = hInstance;
+ odp.ptszGroup = LPGENT("Network");
+ odp.ptszTitle = m_tszUserName;
+ odp.dwInitParam = LPARAM(this);
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE;
+
+ odp.ptszTab = LPGENT("Basic");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_AIM);
+ odp.pfnDlgProc = options_dialog;
+ odp.nIDBottomSimpleControl = IDC_OPTIONS;
+ Options_AddPage(wParam, &odp);
+
+ odp.ptszTab = LPGENT("Privacy");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_PRIVACY);
+ odp.pfnDlgProc = privacy_dialog;
+ odp.nIDBottomSimpleControl = 0;
+ Options_AddPage(wParam, &odp);
+
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Brief account info dialog
+
+INT_PTR CALLBACK first_run_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+
+ CAimProto* ppro = (CAimProto*)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+
+ DBVARIANT dbv;
+ if (!ppro->getString(AIM_KEY_SN, &dbv))
+ {
+ SetDlgItemTextA(hwndDlg, IDC_SN, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (!ppro->getString(AIM_KEY_PW, &dbv))
+ {
+ CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM) dbv.pszVal);
+ SetDlgItemTextA(hwndDlg, IDC_PW, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_NEWAIMACCOUNTLINK)
+ {
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)"http://www.aim.com/redirects/inclient/register.adp");
+ return TRUE;
+ }
+
+ if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus())
+ {
+ switch(LOWORD(wParam))
+ {
+ case IDC_SN: case IDC_PW:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
+ {
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ char str[128];
+ GetDlgItemTextA(hwndDlg, IDC_SN, str, sizeof(str));
+ ppro->setString(AIM_KEY_SN, str);
+ GetDlgItemTextA(hwndDlg, IDC_PW, str, sizeof(str));
+ CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(str), (LPARAM) str);
+ ppro->setString(AIM_KEY_PW, str);
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+INT_PTR CAimProto::SvcCreateAccMgrUI(WPARAM wParam, LPARAM lParam)
+{
+ return (INT_PTR)CreateDialogParam (hInstance, MAKEINTRESOURCE(IDD_AIMACCOUNT),
+ (HWND)lParam, first_run_dialog, (LPARAM)this);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Instant idle dialog
+
+INT_PTR CALLBACK instant_idle_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ ppro = (CAimProto*)lParam;
+ {
+ WindowSetIcon(hwndDlg, "idle");
+ unsigned long it = ppro->getDword(AIM_KEY_IIT, 0);
+ unsigned long hours = it / 60;
+ unsigned long minutes = it % 60;
+ SetDlgItemInt(hwndDlg, IDC_IIH, hours,0);
+ SetDlgItemInt(hwndDlg, IDC_IIM, minutes,0);
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 0);
+ break;
+
+ case WM_DESTROY:
+ WindowFreeIcon(hwndDlg);
+ break;
+
+ case WM_COMMAND:
+ {
+ unsigned long hours=GetDlgItemInt(hwndDlg, IDC_IIH,0,0);
+ unsigned short minutes=(unsigned short)GetDlgItemInt(hwndDlg, IDC_IIM,0,0);
+ if (minutes > 59)
+ minutes = 59;
+ ppro->setDword(AIM_KEY_IIT, hours*60+minutes);
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ //Instant Idle
+ if (ppro->state==1)
+ {
+ ppro->aim_set_idle(ppro->hServerConn,ppro->seqno,hours * 60 * 60 + minutes * 60);
+ ppro->instantidle=1;
+ }
+ EndDialog(hwndDlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ ppro->aim_set_idle(ppro->hServerConn,ppro->seqno,0);
+ ppro->instantidle=0;
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Join chat dialog
+
+INT_PTR CALLBACK join_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAimProto* ppro = (CAimProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ ppro = (CAimProto*)lParam;
+ WindowSetIcon(hwndDlg, "aol");
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 0);
+ break;
+
+ case WM_DESTROY:
+ WindowFreeIcon(hwndDlg);
+ break;
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ char room[128];
+ GetDlgItemTextA(hwndDlg, IDC_ROOM, room, sizeof(room));
+ if (ppro->state==1 && strlen(room) > 0)
+ {
+ chatnav_param* par = new chatnav_param(room, 4);
+ ppro->ForkThread(&CAimProto::chatnav_request_thread, par);
+ }
+ EndDialog(hwndDlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
+/////////////////////////////////////////////////////////////////////////////////////////
+// Invite to chat dialog
+
+static void clist_chat_invite_send(HANDLE hItem, HWND hwndList, chat_list_item* item, CAimProto* ppro, char *msg)
+{
+ if (hItem == NULL)
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
+
+ while (hItem)
+ {
+ if (IsHContactGroup(hItem))
+ {
+ HANDLE hItemT = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hItemT) clist_chat_invite_send(hItemT, hwndList, item, ppro, msg);
+ }
+ else
+ {
+ int chk = SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0);
+ if (chk)
+ {
+ if (IsHContactInfo(hItem))
+ {
+ TCHAR buf[128] = _T("");
+ SendMessage(hwndList, CLM_GETITEMTEXT, (WPARAM)hItem, (LPARAM)buf);
+
+ char* sn = mir_t2a(buf);
+ ppro->aim_chat_invite(ppro->hServerConn, ppro->seqno,
+ item->cookie, item->exchange, item->instance, sn, msg);
+ mir_free(sn);
+ }
+ else
+ {
+ DBVARIANT dbv;
+ if (!ppro->getString(hItem, AIM_KEY_SN, &dbv))
+ {
+ ppro->aim_chat_invite(ppro->hServerConn, ppro->seqno,
+ item->cookie, item->exchange, item->instance, dbv.pszVal, msg);
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+ }
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
+ }
+}
+
+static void clist_validate_contact(HANDLE hItem, HWND hwndList, CAimProto* ppro)
+{
+ if (!ppro->is_my_contact(hItem) || ppro->getByte(hItem, "ChatRoom", 0) ||
+ ppro->getWord(hItem, AIM_KEY_ST, ID_STATUS_OFFLINE) == ID_STATUS_ONTHEPHONE)
+ SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
+}
+
+static void clist_chat_prepare(HANDLE hItem, HWND hwndList, CAimProto* ppro)
+{
+ if (hItem == NULL)
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
+
+ while (hItem)
+ {
+ HANDLE hItemN = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
+
+ if (IsHContactGroup(hItem))
+ {
+ HANDLE hItemT = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hItemT) clist_chat_prepare(hItemT, hwndList, ppro);
+ }
+ else if (IsHContactContact(hItem))
+ clist_validate_contact(hItem, hwndList, ppro);
+
+ hItem = hItemN;
+ }
+}
+
+
+INT_PTR CALLBACK invite_to_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ invite_chat_param* param = (invite_chat_param*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ param = (invite_chat_param*)lParam;
+
+ WindowSetIcon(hwndDlg, "aol");
+ SetDlgItemTextA(hwndDlg, IDC_ROOMNAME, param->id);
+ SetDlgItemTextA(hwndDlg, IDC_MSG, Translate("Join me in this buddy chat!"));
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 0);
+ break;
+
+ case WM_NCDESTROY:
+ WindowFreeIcon(hwndDlg);
+ delete param;
+ break;
+
+ case WM_NOTIFY:
+ {
+ NMCLISTCONTROL* nmc = (NMCLISTCONTROL*)lParam;
+ if (nmc->hdr.idFrom == IDC_CCLIST)
+ {
+ switch (nmc->hdr.code)
+ {
+ case CLN_NEWCONTACT:
+ if (param && (nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0)
+ clist_validate_contact(nmc->hItem, nmc->hdr.hwndFrom, param->ppro);
+ break;
+
+ case CLN_LISTREBUILT:
+ if (param)
+ clist_chat_prepare(NULL, nmc->hdr.hwndFrom, param->ppro);
+ break;
+ }
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_ADDSCR:
+ if (param->ppro->state == 1)
+ {
+ TCHAR sn[64];
+ GetDlgItemText(hwndDlg, IDC_EDITSCR, sn, SIZEOF(sn));
+
+ CLCINFOITEM cii = {0};
+ cii.cbSize = sizeof(cii);
+ cii.flags = CLCIIF_CHECKBOX | CLCIIF_BELOWCONTACTS;
+ cii.pszText = sn;
+
+ HANDLE hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CCLIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii);
+ SendDlgItemMessage(hwndDlg, IDC_CCLIST, CLM_SETCHECKMARK, (LPARAM)hItem, 1);
+ }
+ break;
+
+ case IDOK:
+ {
+ chat_list_item* item = param->ppro->find_chat_by_id(param->id);
+ if (item)
+ {
+ char msg[1024];
+ GetDlgItemTextA(hwndDlg, IDC_MSG, msg, sizeof(msg));
+
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_CCLIST);
+ clist_chat_invite_send(NULL, hwndList, item, param->ppro, msg);
+ }
+ EndDialog(hwndDlg, IDOK);
+ }
+ break;
+
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Chat request dialog
+
+INT_PTR CALLBACK chat_request_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ invite_chat_req_param* param = (invite_chat_req_param*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ param = (invite_chat_req_param*)lParam;
+
+ WindowSetIcon(hwndDlg, "aol");
+
+ SetDlgItemTextA(hwndDlg, IDC_ROOMNAME, strrchr(param->cnp->id, '-')+1);
+ SetDlgItemTextA(hwndDlg, IDC_SCREENNAME, param->name);
+ SetDlgItemTextA(hwndDlg, IDC_MSG, param->message);
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hwndDlg, 0);
+ break;
+
+ case WM_DESTROY:
+ WindowFreeIcon(hwndDlg);
+ delete param;
+ break;
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ param->ppro->ForkThread(&CAimProto::chatnav_request_thread, param->cnp);
+ EndDialog(hwndDlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ param->ppro->aim_chat_deny(param->ppro->hServerConn,param->ppro->seqno,param->name,param->icbm_cookie);
+ delete param->cnp;
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+void CALLBACK chat_request_cb(PVOID dwParam)
+{
+ CreateDialogParam (hInstance, MAKEINTRESOURCE(IDD_CHATROOM_INVITE_REQ),
+ NULL, chat_request_dialog, (LPARAM)dwParam);
+}
diff --git a/protocols/AimOscar/src/ui.h b/protocols/AimOscar/src/ui.h
new file mode 100644
index 0000000000..e6a1b984c0
--- /dev/null
+++ b/protocols/AimOscar/src/ui.h
@@ -0,0 +1,61 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef WINDOWS_H
+#define WINDOWS_H
+
+#ifndef CFM_BACKCOLOR
+#define CFM_BACKCOLOR 0x04000000
+#endif
+#ifndef CFE_AUTOBACKCOLOR
+#define CFE_AUTOBACKCOLOR CFM_BACKCOLOR
+#endif
+
+struct invite_chat_param
+{
+ char* id;
+ CAimProto* ppro;
+
+ invite_chat_param(const char* idt, CAimProto* prt)
+ { id = mir_strdup(idt); ppro = prt; }
+};
+
+struct invite_chat_req_param
+{
+ chatnav_param* cnp;
+ CAimProto* ppro;
+ char* message;
+ char* name;
+ char* icbm_cookie;
+
+ invite_chat_req_param(chatnav_param* cnpt, CAimProto* prt, char* msg, char* nm, char* icki)
+ { cnp = cnpt; ppro = prt; message = mir_strdup(msg); name = mir_strdup(nm);
+ icbm_cookie = (char*)mir_alloc(8); memcpy(icbm_cookie, icki, 8); }
+
+ ~invite_chat_req_param()
+ { mir_free(message); mir_free(name); mir_free(icbm_cookie); }
+};
+
+INT_PTR CALLBACK instant_idle_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK join_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK invite_to_chat_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK chat_request_dialog(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void CALLBACK chat_request_cb(PVOID dwParam);
+
+#endif
diff --git a/protocols/AimOscar/src/utility.cpp b/protocols/AimOscar/src/utility.cpp
new file mode 100644
index 0000000000..4c487cf818
--- /dev/null
+++ b/protocols/AimOscar/src/utility.cpp
@@ -0,0 +1,878 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2012 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aim.h"
+#include "utility.h"
+
+void CAimProto::broadcast_status(int status)
+{
+ LOG("Broadcast Status: %d",status);
+ int old_status = m_iStatus;
+ m_iStatus = status;
+ if (m_iStatus == ID_STATUS_OFFLINE)
+ {
+ shutdown_file_transfers();
+ shutdown_chat_conn();
+
+ if (hServerConn)
+ {
+ aim_sendflap(hServerConn,0x04,0,NULL,seqno);
+ Netlib_Shutdown(hServerConn);
+ }
+
+ if (hMailConn && hMailConn != (HANDLE)1)
+ {
+ aim_sendflap(hMailConn,0x04,0,NULL,mail_seqno);
+ Netlib_Shutdown(hMailConn);
+ }
+ else if (hMailConn == (HANDLE)1)
+ hMailConn = NULL;
+
+ if (hAvatarConn && hAvatarConn != (HANDLE)1)
+ {
+ aim_sendflap(hAvatarConn,0x04,0,NULL,avatar_seqno);
+ Netlib_Shutdown(hAvatarConn);
+ }
+ else if (hAvatarConn == (HANDLE)1)
+ hAvatarConn = NULL;
+
+ if (hChatNavConn && hChatNavConn != (HANDLE)1)
+ {
+ aim_sendflap(hChatNavConn,0x04,0,NULL,chatnav_seqno);
+ Netlib_Shutdown(hChatNavConn);
+ }
+ else if (hChatNavConn == (HANDLE)1)
+ hChatNavConn = NULL;
+
+ idle = false;
+ instantidle = false;
+ list_received = false;
+ state = 0;
+ m_iDesiredStatus = ID_STATUS_OFFLINE;
+ mir_free(last_status_msg); last_status_msg = NULL;
+
+ avatar_id_lg = 0;
+ avatar_id_sm = 0;
+ mir_free(hash_lg); hash_lg = NULL;
+ mir_free(hash_sm); hash_sm = NULL;
+
+ pd_flags = 0;
+ pd_info_id = 0;
+ pd_mode = 0;
+
+ seqno = 0;
+ mail_seqno = 0;
+ avatar_seqno = 0;
+ chatnav_seqno = 0;
+ admin_seqno = 0;
+
+ }
+ sendBroadcast(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+}
+
+void CAimProto::start_connection(void *arg)
+{
+ int status = (int)arg;
+
+ if(m_iStatus<=ID_STATUS_OFFLINE)
+ {
+ offline_contacts();
+ DBVARIANT dbv;
+ if (!getString(AIM_KEY_SN, &dbv))
+ DBFreeVariant(&dbv);
+ else
+ {
+ ShowPopup(LPGEN("Please, enter a username in the options dialog."), 0);
+ broadcast_status(ID_STATUS_OFFLINE);
+ return;
+ }
+ if (!getString(AIM_KEY_PW, &dbv))
+ DBFreeVariant(&dbv);
+ else
+ {
+ ShowPopup(LPGEN("Please, enter a password in the options dialog."), 0);
+ broadcast_status(ID_STATUS_OFFLINE);
+ return;
+ }
+
+ bool use_ssl = !getByte(AIM_KEY_DSSL, 0);
+
+ char* login_url = getSetting(AIM_KEY_HN);
+ if (login_url == NULL) login_url = mir_strdup(use_ssl ? AIM_DEFAULT_SERVER : AIM_DEFAULT_SERVER_NS);
+
+ hServerConn = aim_connect(login_url, get_default_port(), use_ssl, login_url);
+
+ mir_free(login_url);
+
+ pref1_flags = 0x77ffff;
+ pref1_set_flags = 0x77ffff;
+ mir_free(pref2_flags); pref2_flags = NULL; pref2_len = 0;
+ mir_free(pref2_set_flags); pref2_set_flags = NULL; pref2_set_len = 0;
+
+ if (hServerConn)
+ aim_connection_authorization();
+ else
+ broadcast_status(ID_STATUS_OFFLINE);
+ }
+}
+
+bool CAimProto::wait_conn(HANDLE& hConn, HANDLE& hEvent, unsigned short service)
+{
+ if (m_iStatus == ID_STATUS_OFFLINE)
+ return false;
+
+ EnterCriticalSection(&connMutex);
+ if (hConn == NULL && hServerConn)
+ {
+ LOG("Starting Connection.");
+ hConn = (HANDLE)1; //set so no additional service request attempts are made while aim is still processing the request
+ aim_new_service_request(hServerConn, seqno, service) ;//general service connection!
+ }
+ LeaveCriticalSection(&connMutex);
+
+ if (WaitForSingleObjectEx(hEvent, 10000, TRUE) != WAIT_OBJECT_0)
+ return false;
+
+ if (Miranda_Terminated() || m_iStatus == ID_STATUS_OFFLINE)
+ return false;
+
+ return true;
+}
+
+
+unsigned short CAimProto::get_default_port(void)
+{
+ return getWord(AIM_KEY_PN, getByte(AIM_KEY_DSSL, 0) ? AIM_DEFAULT_PORT : AIM_DEFAULT_SSL_PORT);
+}
+
+bool CAimProto::is_my_contact(HANDLE hContact)
+{
+ const char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ return szProto != NULL && strcmp(m_szModuleName, szProto) == 0;
+}
+
+HANDLE CAimProto::find_chat_contact(const char* room)
+{
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (is_my_contact(hContact))
+ {
+ DBVARIANT dbv;
+ if (!getString(hContact, "ChatRoomID", &dbv))
+ {
+ bool found = !strcmp(room, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if (found) return hContact;
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+ return NULL;
+}
+
+HANDLE CAimProto::contact_from_sn(const char* sn, bool addIfNeeded, bool temporary)
+{
+ char* norm_sn = normalize_name(sn);
+
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (is_my_contact(hContact))
+ {
+ DBVARIANT dbv;
+ if (!getString(hContact, AIM_KEY_SN, &dbv))
+ {
+ bool found = !strcmp(norm_sn, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if (found)
+ {
+ mir_free(norm_sn);
+ return hContact;
+ }
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+
+ if (addIfNeeded)
+ {
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_ADD, 0, 0);
+ if (hContact)
+ {
+ if (CallService(MS_PROTO_ADDTOCONTACT, (WPARAM) hContact, (LPARAM) m_szModuleName) == 0)
+ {
+ setString(hContact, AIM_KEY_SN, norm_sn);
+ setString(hContact, AIM_KEY_NK, sn);
+ LOG("Adding contact %s to client side list.",norm_sn);
+ if (temporary)
+ DBWriteContactSettingByte(hContact, "CList", "NotOnList", 1);
+ mir_free(norm_sn);
+ return hContact;
+ }
+ else
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ }
+ }
+
+ mir_free(norm_sn);
+ return NULL;
+}
+
+void CAimProto::update_server_group(const char* group, unsigned short group_id)
+{
+ unsigned short user_id_array_size;
+ unsigned short* user_id_array;
+
+ if (group_id)
+ user_id_array = get_members_of_group(group_id, user_id_array_size);
+ else
+ {
+ user_id_array_size = (unsigned short)group_list.getCount();
+ user_id_array = (unsigned short*)mir_alloc(user_id_array_size * sizeof(unsigned short));
+ for (unsigned short i=0; i<user_id_array_size; ++i)
+ user_id_array[i] = _htons(group_list[i].item_id);
+ }
+
+ LOG("Modifying group %s:%u on the serverside list",group, group_id);
+ aim_mod_group(hServerConn, seqno, group, group_id, (char*)user_id_array,
+ user_id_array_size * sizeof(unsigned short));
+
+ mir_free(user_id_array);
+}
+
+void CAimProto::add_contact_to_group(HANDLE hContact, const char* new_group)
+{
+ if (new_group == NULL) return;
+
+ if (strcmp(new_group, "MetaContacts Hidden Group") == 0)
+ return;
+
+ unsigned short old_group_id = getGroupId(hContact, 1);
+ char* old_group = group_list.find_name(old_group_id);
+
+ if (old_group && strcmp(new_group, old_group) == 0)
+ return;
+
+ DBVARIANT dbv;
+ char *nick = NULL;
+ if (!DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, "MyHandle", &dbv))
+ {
+ nick = NEWSTR_ALLOCA(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+
+ if (getString(hContact, AIM_KEY_SN, &dbv)) return;
+
+ unsigned short item_id = getBuddyId(hContact, 1);
+ unsigned short new_item_id = search_for_free_item_id(hContact);
+ unsigned short new_group_id = group_list.find_id(new_group);
+
+ if (!item_id)
+ LOG("Contact %u not on list.", hContact);
+
+ setGroupId(hContact, 1, new_group_id);
+ if (new_group && strcmp(new_group, AIM_DEFAULT_GROUP))
+ DBWriteContactSettingStringUtf(hContact, MOD_KEY_CL, OTH_KEY_GP, new_group);
+ else
+ DBDeleteContactSetting(hContact, MOD_KEY_CL, OTH_KEY_GP);
+
+ aim_ssi_update(hServerConn, seqno, true);
+
+ if (new_group_id == 0)
+ {
+ create_group(new_group);
+ LOG("Group %s not on list.", new_group);
+ new_group_id = group_list.add(new_group);
+ LOG("Adding group %s:%u to the serverside list", new_group, new_group_id);
+ aim_add_contact(hServerConn, seqno, new_group, 0, new_group_id, 1);//add the group server-side even if it exist
+ }
+
+ LOG("Adding buddy %s:%u %s:%u to the serverside list", dbv.pszVal, new_item_id, new_group, new_group_id);
+ aim_add_contact(hServerConn, seqno, dbv.pszVal, new_item_id, new_group_id, 0, nick);
+
+ update_server_group(new_group, new_group_id);
+
+ if (old_group_id && item_id)
+ {
+ bool is_not_in_list = getBool(hContact, AIM_KEY_NIL, false);
+ LOG("Removing buddy %s:%u %s:%u from the serverside list", dbv.pszVal, item_id, old_group, old_group_id);
+ aim_delete_contact(hServerConn, seqno, dbv.pszVal, item_id, old_group_id, 0, is_not_in_list);
+ update_server_group(old_group, old_group_id);
+ deleteSetting(hContact, AIM_KEY_NIL);
+ }
+
+ aim_ssi_update(hServerConn, seqno, false);
+
+ DBFreeVariant(&dbv);
+}
+
+void CAimProto::offline_contact(HANDLE hContact, bool remove_settings)
+{
+ if(remove_settings)
+ {
+ //We need some of this stuff if we are still online.
+ for(int i=1;;++i)
+ {
+ if (deleteBuddyId(hContact, i)) break;
+ deleteGroupId(hContact, i);
+ }
+
+ DBDeleteContactSetting(hContact, MOD_KEY_CL, OTH_KEY_SM);
+ }
+ setWord(hContact, AIM_KEY_ST, ID_STATUS_OFFLINE);
+}
+
+void CAimProto::offline_contacts(void)
+{
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (is_my_contact(hContact))
+ offline_contact(hContact,true);
+ hContact = db_find_next(hContact);
+ }
+ allow_list.destroy();
+ block_list.destroy();
+ group_list.destroy();
+}
+
+char *normalize_name(const char *s)
+{
+ if (s == NULL) return NULL;
+
+ char* buf = mir_strdup(s);
+ _strlwr(buf);
+/*
+ char *p = strchr(buf, ' ');
+ if (p)
+ {
+ char *q = p;
+ while (*p)
+ {
+ if (*p != ' ') *(q++) = *p;
+ ++p;
+ }
+ *q = '\0';
+ }
+*/
+ return buf;
+}
+
+char* trim_str(char* s)
+{
+ if (s == NULL) return NULL;
+ size_t len = strlen(s);
+
+ while (len)
+ {
+ if (isspace(s[len-1])) --len;
+ else break;
+ }
+ s[len]=0;
+
+ char* sc = s;
+ while (isspace(*sc)) ++sc;
+ memcpy(s,sc,strlen(sc)+1);
+
+ return s;
+}
+
+void create_group(const char *group)
+{
+ if (strcmp(group, AIM_DEFAULT_GROUP) == 0) return;
+
+ TCHAR* szGroupName = mir_utf8decodeT(group);
+ CallService(MS_CLIST_GROUPCREATE, 0, (LPARAM)szGroupName);
+ mir_free(szGroupName);
+}
+
+unsigned short CAimProto::search_for_free_item_id(HANDLE hbuddy)//returns a free item id and links the id to the buddy
+{
+ unsigned short id;
+
+retry:
+ id = get_random();
+
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (is_my_contact(hContact))
+ {
+ for(int i=1; ;++i)
+ {
+ unsigned short item_id = getBuddyId(hContact, i);
+ if (item_id == 0) break;
+
+ if (item_id == id) goto retry; //found one no need to look through anymore
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+
+ setBuddyId(hbuddy, 1, id);
+ return id;
+}
+
+//returns the size of the list array aquired with data
+unsigned short* CAimProto::get_members_of_group(unsigned short group_id, unsigned short &size)
+{
+ unsigned short* list = NULL;
+ size = 0;
+
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ if (is_my_contact(hContact))
+ {
+ for(int i=1; ;++i)
+ {
+ unsigned short user_group_id = getGroupId(hContact, i);
+ if (user_group_id == 0) break;
+
+ if (group_id == user_group_id)
+ {
+ unsigned short buddy_id = getBuddyId(hContact, i);
+ if (buddy_id)
+ {
+ list = (unsigned short*)mir_realloc(list, ++size*sizeof(list[0]));
+ list[size-1] = _htons(buddy_id);
+ }
+ }
+ }
+ }
+ hContact = db_find_next(hContact);
+ }
+ return list;
+}
+
+void CAimProto::upload_nicks(void)
+{
+ HANDLE hContact = db_find_first();
+ while (hContact)
+ {
+ DBVARIANT dbv;
+ if (is_my_contact(hContact) && !DBGetContactSettingStringUtf(hContact, MOD_KEY_CL, "MyHandle", &dbv))
+ {
+ set_local_nick(hContact, dbv.pszVal, NULL);
+ DBFreeVariant(&dbv);
+ }
+ hContact = db_find_next(hContact);
+ }
+}
+
+void CAimProto::set_local_nick(HANDLE hContact, char* nick, char* note)
+{
+ DBVARIANT dbv;
+ if (getString(hContact, AIM_KEY_SN, &dbv)) return;
+
+ for(int i=1; ;++i)
+ {
+ unsigned short group_id = getGroupId(hContact, i);
+ if (group_id == 0) break;
+
+ unsigned short buddy_id = getBuddyId(hContact, i);
+ if (buddy_id == 0) break;
+
+ aim_mod_buddy(hServerConn, seqno, dbv.pszVal, group_id, buddy_id, nick, note);
+ }
+ DBFreeVariant(&dbv);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+unsigned short BdList::get_free_id(void)
+{
+ unsigned short id;
+
+retry:
+ id = get_random();
+
+ for (int i=0; i<count; ++i)
+ if (items[i]->item_id == id) goto retry;
+
+ return id;
+}
+
+unsigned short BdList::find_id(const char* name)
+{
+ for (int i=0; i<count; ++i)
+ {
+ if (_stricmp(items[i]->name, name) == 0)
+ return items[i]->item_id;
+ }
+ return 0;
+}
+
+char* BdList::find_name(unsigned short id)
+{
+ for (int i=0; i<count; ++i)
+ {
+ if (items[i]->item_id == id)
+ return items[i]->name;
+ }
+ return NULL;
+}
+
+void BdList::remove_by_id(unsigned short id)
+{
+ for (int i=0; i<count; ++i)
+ {
+ if (items[i]->item_id == id)
+ {
+ remove(i);
+ break;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+unsigned short CAimProto::getBuddyId(HANDLE hContact, int i)
+{
+ char item[sizeof(AIM_KEY_BI)+10];
+ mir_snprintf(item, sizeof(AIM_KEY_BI)+10, AIM_KEY_BI"%d", i);
+ return getWord(hContact, item, 0);
+}
+
+void CAimProto::setBuddyId(HANDLE hContact, int i, unsigned short id)
+{
+ char item[sizeof(AIM_KEY_BI)+10];
+ mir_snprintf(item, sizeof(AIM_KEY_BI)+10, AIM_KEY_BI"%d", i);
+ setWord(hContact, item, id);
+}
+
+int CAimProto::deleteBuddyId(HANDLE hContact, int i)
+{
+ char item[sizeof(AIM_KEY_BI)+10];
+ mir_snprintf(item, sizeof(AIM_KEY_BI)+10, AIM_KEY_BI"%d", i);
+ return deleteSetting(hContact, item);
+}
+
+unsigned short CAimProto::getGroupId(HANDLE hContact, int i)
+{
+ char item[sizeof(AIM_KEY_GI)+10];
+ mir_snprintf(item, sizeof(AIM_KEY_GI)+10, AIM_KEY_GI"%d", i);
+ return getWord(hContact, item, 0);
+}
+
+void CAimProto::setGroupId(HANDLE hContact, int i, unsigned short id)
+{
+ char item[sizeof(AIM_KEY_GI)+10];
+ mir_snprintf(item, sizeof(AIM_KEY_GI)+10, AIM_KEY_GI"%d", i);
+ setWord(hContact, item, id);
+}
+
+int CAimProto::deleteGroupId(HANDLE hContact, int i)
+{
+ char item[sizeof(AIM_KEY_GI)+10];
+ mir_snprintf(item, sizeof(AIM_KEY_GI)+10, AIM_KEY_GI"%d", i);
+ return deleteSetting(hContact, item);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CAimProto::open_contact_file(const char* sn, const TCHAR* file, const char* mode, TCHAR* &path, bool contact_dir)
+{
+ path = (TCHAR*)mir_alloc(MAX_PATH * sizeof(TCHAR));
+
+ TCHAR *tmpPath = Utils_ReplaceVarsT(_T("%miranda_userdata%"));
+ TCHAR *sztModuleName = mir_a2t(m_szModuleName);
+ int pos = mir_sntprintf(path, MAX_PATH, _T("%s\\%s"), tmpPath, sztModuleName);
+ mir_free(sztModuleName);
+ mir_free(tmpPath);
+ if (contact_dir)
+ {
+ char* norm_sn = normalize_name(sn);
+ TCHAR *norm_snt = mir_a2t(m_szModuleName);
+ pos += mir_sntprintf(path + pos, MAX_PATH - pos, _T("\\%s"), norm_snt);
+ mir_free(norm_snt);
+ mir_free(norm_sn);
+ }
+
+ if (_taccess(path, 0))
+ CallService(MS_UTILS_CREATEDIRTREET, 0, (LPARAM)path);
+
+ mir_sntprintf(path + pos, MAX_PATH - pos, _T("\\%s"), file);
+ int fid = _topen(path, _O_CREAT | _O_RDWR | _O_BINARY, _S_IREAD);
+ if (fid < 0)
+ {
+ TCHAR errmsg[512];
+ #if _MSC_VER > 1200
+ mir_sntprintf(errmsg, SIZEOF(errmsg), TranslateT("Failed to open file: %s %s"), path, __tcserror(NULL));
+ #else
+ TCHAR* err = mir_a2t(_strerror(NULL));
+ mir_sntprintf(errmsg, SIZEOF(errmsg), TranslateT("Failed to open file: %s %s"), path, err);
+ mir_free(err);
+ #endif
+ ShowPopup((char*)errmsg, ERROR_POPUP | TCHAR_POPUP);
+ }
+ return fid;
+}
+
+void CAimProto::write_away_message(const char* sn, const char* msg, bool utf)
+{
+ TCHAR* path;
+ int fid = open_contact_file(sn, _T("away.html"), "wb", path, 1);
+ if (fid >= 0)
+ {
+ if (utf) _write(fid, "\xEF\xBB\xBF", 3);
+ char* s_msg=process_status_msg(msg, sn);
+ _write(fid, "<h3>", 4);
+ _write(fid, sn, (unsigned)strlen(sn));
+ _write(fid, "'s Away Message:</h3>", 21);
+ _write(fid, s_msg, (unsigned)strlen(s_msg));
+ _close(fid);
+ ShellExecute(NULL, _T("open"), path, NULL, NULL, SW_SHOW);
+ mir_free(path);
+ mir_free(s_msg);
+ }
+}
+
+void CAimProto::write_profile(const char* sn, const char* msg, bool utf)
+{
+ TCHAR* path;
+ int fid = open_contact_file(sn, _T("profile.html"),"wb", path, 1);
+ if (fid >= 0)
+ {
+ if (utf) _write(fid, "\xEF\xBB\xBF", 3);
+ char* s_msg=process_status_msg(msg, sn);
+ _write(fid, "<h3>", 4);
+ _write(fid, sn, (unsigned)strlen(sn));
+ _write(fid, "'s Profile:</h3>", 16);
+ _write(fid, s_msg, (unsigned)strlen(s_msg));
+ _close(fid);
+ ShellExecute(NULL, _T("open"), path, NULL, NULL, SW_SHOW);
+ mir_free(path);
+ mir_free(s_msg);
+ }
+}
+
+unsigned long aim_oft_checksum_chunk(unsigned long dwChecksum, const unsigned char *buffer, int len)
+{
+ unsigned long checksum = (dwChecksum >> 16) & 0xffff;
+
+ for (int i = 0; i < len; i++)
+ {
+ unsigned val = buffer[i];
+
+ if ((i & 1) == 0)
+ val <<= 8;
+
+ if (checksum < val) ++val;
+ checksum -= val;
+ }
+ checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
+ checksum = ((checksum & 0x0000ffff) + (checksum >> 16));
+ return checksum << 16;
+}
+
+unsigned int aim_oft_checksum_file(TCHAR *filename, unsigned __int64 size)
+{
+ unsigned long checksum = 0xffff0000;
+ int fid = _topen(filename, _O_RDONLY | _O_BINARY, _S_IREAD);
+ if (fid >= 0)
+ {
+ unsigned __int64 sz = _filelengthi64(fid);
+ if (size > sz) size = sz;
+ while (size)
+ {
+ unsigned char buffer[8912];
+ int bytes = (int)min(size, sizeof(buffer));
+ bytes = _read(fid, buffer, bytes);
+ size -= bytes;
+ checksum = aim_oft_checksum_chunk(checksum, buffer, bytes);
+ }
+ _close(fid);
+ }
+ return checksum;
+}
+
+char* long_ip_to_char_ip(unsigned long host, char* ip)
+{
+ host = _htonl(host);
+ unsigned char* bytes = (unsigned char*)&host;
+ size_t buf_loc = 0;
+ for(int i=0; i<4; i++)
+ {
+ char store[16];
+ _itoa(bytes[i], store, 10);
+ size_t len = strlen(store);
+
+ memcpy(&ip[buf_loc], store, len);
+ buf_loc += len;
+ ip[buf_loc++] = '.';
+ }
+ ip[buf_loc - 1] = '\0';
+
+ return ip;
+}
+
+unsigned long char_ip_to_long_ip(char* ip)
+{
+ unsigned char chost[4] = {0};
+ char *c = ip;
+ for(int i=0; i<4; ++i)
+ {
+ chost[i] = (unsigned char)atoi(c);
+ c = strchr(c, '.');
+ if (c) ++c;
+ else break;
+ }
+ return *(unsigned long*)&chost;
+}
+
+unsigned short get_random(void)
+{
+ unsigned short id;
+ CallService(MS_UTILS_GETRANDOM, sizeof(id), (LPARAM)&id);
+ id &= 0x7fff;
+ return id;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Standard functions
+
+int CAimProto::deleteSetting(HANDLE hContact, const char* setting)
+{ return DBDeleteContactSetting(hContact, m_szModuleName, setting);
+}
+
+bool CAimProto::getBool(HANDLE hContact, const char* name, bool defaultValue)
+{ return DBGetContactSettingByte(hContact, m_szModuleName, name, defaultValue) != 0;
+}
+
+int CAimProto::getByte(const char* name, BYTE defaultValue)
+{ return DBGetContactSettingByte(NULL, m_szModuleName, name, defaultValue);
+}
+
+int CAimProto::getByte(HANDLE hContact, const char* name, BYTE defaultValue)
+{ return DBGetContactSettingByte(hContact, m_szModuleName, name, defaultValue);
+}
+
+int CAimProto::getDword(const char* name, DWORD defaultValue)
+{ return DBGetContactSettingDword(NULL, m_szModuleName, name, defaultValue);
+}
+
+int CAimProto::getDword(HANDLE hContact, const char* name, DWORD defaultValue)
+{ return DBGetContactSettingDword(hContact, m_szModuleName, name, defaultValue);
+}
+
+int CAimProto::getString(const char* name, DBVARIANT* result)
+{ return DBGetContactSettingString(NULL, m_szModuleName, name, result);
+}
+
+int CAimProto::getString(HANDLE hContact, const char* name, DBVARIANT* result)
+{ return DBGetContactSettingString(hContact, m_szModuleName, name, result);
+}
+
+int CAimProto::getTString(const char* name, DBVARIANT* result)
+{ return DBGetContactSettingTString(NULL, m_szModuleName, name, result);
+}
+
+int CAimProto::getTString(HANDLE hContact, const char* name, DBVARIANT* result)
+{ return DBGetContactSettingTString(hContact, m_szModuleName, name, result);
+}
+
+WORD CAimProto::getWord(const char* name, WORD defaultValue)
+{ return (WORD)DBGetContactSettingWord(NULL, m_szModuleName, name, defaultValue);
+}
+
+WORD CAimProto::getWord(HANDLE hContact, const char* name, WORD defaultValue)
+{ return (WORD)DBGetContactSettingWord(hContact, m_szModuleName, name, defaultValue);
+}
+
+char* CAimProto::getSetting(HANDLE hContact, const char* setting)
+{
+ DBVARIANT dbv;
+ return DBGetContactSettingString(hContact, m_szModuleName, setting, &dbv) ?
+ NULL : dbv.pszVal;
+}
+
+char* CAimProto::getSetting(const char* setting)
+{
+ DBVARIANT dbv;
+ return DBGetContactSettingString(NULL, m_szModuleName, setting, &dbv) ?
+ NULL : dbv.pszVal;
+}
+
+void CAimProto::setByte(const char* name, BYTE value)
+{ DBWriteContactSettingByte(NULL, m_szModuleName, name, value);
+}
+
+void CAimProto::setByte(HANDLE hContact, const char* name, BYTE value)
+{ DBWriteContactSettingByte(hContact, m_szModuleName, name, value);
+}
+
+void CAimProto::setDword(const char* name, DWORD value)
+{ DBWriteContactSettingDword(NULL, m_szModuleName, name, value);
+}
+
+void CAimProto::setDword(HANDLE hContact, const char* name, DWORD value)
+{ DBWriteContactSettingDword(hContact, m_szModuleName, name, value);
+}
+
+void CAimProto::setString(const char* name, const char* value)
+{ DBWriteContactSettingString(NULL, m_szModuleName, name, value);
+}
+
+void CAimProto::setString(HANDLE hContact, const char* name, const char* value)
+{ DBWriteContactSettingString(hContact, m_szModuleName, name, value);
+}
+
+void CAimProto::setTString(const char* name, const TCHAR* value)
+{ DBWriteContactSettingTString(NULL, m_szModuleName, name, value);
+}
+
+void CAimProto::setTString(HANDLE hContact, const char* name, const TCHAR* value)
+{ DBWriteContactSettingTString(hContact, m_szModuleName, name, value);
+}
+
+void CAimProto::setWord(const char* name, WORD value)
+{ DBWriteContactSettingWord(NULL, m_szModuleName, name, value);
+}
+
+void CAimProto::setWord(HANDLE hContact, const char* name, WORD value)
+{ DBWriteContactSettingWord(hContact, m_szModuleName, name, value);
+}
+
+int CAimProto::sendBroadcast(HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam)
+{
+ return ProtoBroadcastAck(m_szModuleName, hContact, type, result, hProcess, lParam);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CAimProto::CreateProtoService(const char* szService, AimServiceFunc serviceProc)
+{
+ char temp[MAX_PATH*2];
+
+ mir_snprintf(temp, sizeof(temp), "%s%s", m_szModuleName, szService);
+ CreateServiceFunctionObj(temp, (MIRANDASERVICEOBJ)*(void**)&serviceProc, this);
+}
+
+void CAimProto::HookProtoEvent(const char* szEvent, AimEventFunc pFunc)
+{
+ ::HookEventObj(szEvent, (MIRANDAHOOKOBJ)*(void**)&pFunc, this);
+}
+
+void CAimProto::ForkThread(AimThreadFunc pFunc, void* param)
+{
+ UINT threadID;
+ CloseHandle((HANDLE)mir_forkthreadowner((pThreadFuncOwner)*(void**)&pFunc, this, param, &threadID));
+}
diff --git a/protocols/AimOscar/src/utility.h b/protocols/AimOscar/src/utility.h
new file mode 100644
index 0000000000..a6608d38f3
--- /dev/null
+++ b/protocols/AimOscar/src/utility.h
@@ -0,0 +1,66 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+Copyright (C) 2005-2006 Aaron Myles Landwehr
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef UTILITY_H
+#define UTILITY_H
+
+char *normalize_name(const char *s);
+char* trim_str(char* s);
+void create_group(const char *group);
+void set_extra_icon(HANDLE hContact, HANDLE hImage, int column_type);
+unsigned int aim_oft_checksum_file(TCHAR *filename, unsigned __int64 size = -1);
+char* long_ip_to_char_ip(unsigned long host, char* ip);
+unsigned long char_ip_to_long_ip(char* ip);
+unsigned short get_random(void);
+
+inline int cap_cmp(const char* cap, const char* cap2) { return memcmp(cap, cap2, 16); }
+inline const char* alpha_cap_str(char ver) { return (ver & 0x80) ? " Alpha" : ""; }
+inline const char* secure_cap_str(char* ver) { return (*(int*)ver == 0xDEC0FE5A) ? " + SecureIM" : ""; }
+
+
+struct BdListItem
+{
+ char* name;
+ unsigned short item_id;
+
+ BdListItem() { name = NULL; item_id = 0; }
+ BdListItem(const char* snt, unsigned short id) { name = mir_strdup(snt); item_id = id; }
+ ~BdListItem() { mir_free(name); }
+};
+
+struct BdList : public OBJLIST<BdListItem>
+{
+ BdList() : OBJLIST<BdListItem>(5) {}
+
+ void add(const char* snt, unsigned short id)
+ { insert(new BdListItem(snt, id)); }
+
+ unsigned short add(const char* snt)
+ {
+ unsigned short id = get_free_id();
+ insert(new BdListItem(snt, id));
+ return id;
+ }
+
+ unsigned short get_free_id(void);
+ unsigned short find_id(const char* name);
+ char* find_name(unsigned short id);
+ void remove_by_id(unsigned short id);
+};
+
+#endif
diff --git a/protocols/AimOscar/src/version.h b/protocols/AimOscar/src/version.h
new file mode 100644
index 0000000000..cd1ad86ac6
--- /dev/null
+++ b/protocols/AimOscar/src/version.h
@@ -0,0 +1,20 @@
+/*
+Plugin of Miranda IM for communicating with users of the AIM protocol.
+Copyright (c) 2008-2009 Boris Krasnovskiy
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#define __FILEVERSION_STRING 0,11,0,1
+#define __VERSION_STRING "0.11.0.1"
+#define __VERSION_DWORD PLUGIN_MAKE_VERSION(0,11,0,1)