summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorRobert Pösel <robyer@seznam.cz>2013-10-29 08:13:04 +0000
committerRobert Pösel <robyer@seznam.cz>2013-10-29 08:13:04 +0000
commit7091c867afd1f44281c8cb8e83d5fafb208a18d9 (patch)
treea6b610c045d69e9bd4bc9f41e29c3a57772b1ce4 /protocols
parente729878cc8be1ab69820d1243bf50e8f6ce417d0 (diff)
Adopted Skype plugin from IM, which is now known as SkypeClassic
One of first compilable versions, may contain various bugs. git-svn-id: http://svn.miranda-ng.org/main/trunk@6664 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols')
-rw-r--r--protocols/SkypeClassic/Skript1.apsbin0 -> 122080 bytes
-rw-r--r--protocols/SkypeClassic/Skript1.rc484
-rw-r--r--protocols/SkypeClassic/SkypeClassic_10.filters191
-rw-r--r--protocols/SkypeClassic/SkypeClassic_10.sln26
-rw-r--r--protocols/SkypeClassic/SkypeClassic_10.vcxproj1249
-rw-r--r--protocols/SkypeClassic/alogon.cpp129
-rw-r--r--protocols/SkypeClassic/alogon.h1
-rw-r--r--protocols/SkypeClassic/changelog.txt330
-rw-r--r--protocols/SkypeClassic/contacts.cpp419
-rw-r--r--protocols/SkypeClassic/contacts.h11
-rw-r--r--protocols/SkypeClassic/debug.cpp75
-rw-r--r--protocols/SkypeClassic/debug.h23
-rw-r--r--protocols/SkypeClassic/ezxml/ezxml.c1033
-rw-r--r--protocols/SkypeClassic/ezxml/ezxml.h167
-rw-r--r--protocols/SkypeClassic/gchat.cpp910
-rw-r--r--protocols/SkypeClassic/gchat.h47
-rw-r--r--protocols/SkypeClassic/memlist.cpp248
-rw-r--r--protocols/SkypeClassic/memlist.h43
-rw-r--r--protocols/SkypeClassic/msglist.cpp86
-rw-r--r--protocols/SkypeClassic/msglist.h15
-rw-r--r--protocols/SkypeClassic/msgq.cpp90
-rw-r--r--protocols/SkypeClassic/msgq.h64
-rw-r--r--protocols/SkypeClassic/pthread.cpp70
-rw-r--r--protocols/SkypeClassic/pthread.h26
-rw-r--r--protocols/SkypeClassic/readme.txt47
-rw-r--r--protocols/SkypeClassic/res/8060.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/Copy of online.icobin0 -> 1406 bytes
-rw-r--r--protocols/SkypeClassic/res/DND.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/Invite.icobin0 -> 1886 bytes
-rw-r--r--protocols/SkypeClassic/res/NA.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/add.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/add2.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/auth.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/away.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/call.bmpbin0 -> 214 bytes
-rw-r--r--protocols/SkypeClassic/res/call.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/chat.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/conference.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/error.icobin0 -> 9062 bytes
-rw-r--r--protocols/SkypeClassic/res/hang_up.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/history.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/hold.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/import.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/invisible.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/message.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/occupied.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/offline.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/online.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/pause.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/phone.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/resume.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/search.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/skype.icobin0 -> 13270 bytes
-rw-r--r--protocols/SkypeClassic/res/skypeout.icobin0 -> 2550 bytes
-rw-r--r--protocols/SkypeClassic/res/skyping.icobin0 -> 2038 bytes
-rw-r--r--protocols/SkypeClassic/resource.h124
-rw-r--r--protocols/SkypeClassic/skype.cpp3381
-rw-r--r--protocols/SkypeClassic/skype.h181
-rw-r--r--protocols/SkypeClassic/skypeapi.cpp1706
-rw-r--r--protocols/SkypeClassic/skypeapi.h69
-rw-r--r--protocols/SkypeClassic/skypeopt.cpp968
-rw-r--r--protocols/SkypeClassic/skypeopt.h49
-rw-r--r--protocols/SkypeClassic/skypeprofile.cpp145
-rw-r--r--protocols/SkypeClassic/skypeprofile.h33
-rw-r--r--protocols/SkypeClassic/skypeproxy.h7
-rw-r--r--protocols/SkypeClassic/skypeproxy/skypeproxy.c651
-rw-r--r--protocols/SkypeClassic/skypeproxy/skypeproxy.h36
-rw-r--r--protocols/SkypeClassic/skypesvc.cpp188
-rw-r--r--protocols/SkypeClassic/skypesvc.h24
-rw-r--r--protocols/SkypeClassic/utf8.cpp334
-rw-r--r--protocols/SkypeClassic/utf8.h47
-rw-r--r--protocols/SkypeClassic/util.cpp57
-rw-r--r--protocols/SkypeClassic/util.h7
-rw-r--r--protocols/SkypeClassic/voiceservice.cpp156
-rw-r--r--protocols/SkypeClassic/voiceservice.h18
75 files changed, 13965 insertions, 0 deletions
diff --git a/protocols/SkypeClassic/Skript1.aps b/protocols/SkypeClassic/Skript1.aps
new file mode 100644
index 0000000000..d99f14a71e
--- /dev/null
+++ b/protocols/SkypeClassic/Skript1.aps
Binary files differ
diff --git a/protocols/SkypeClassic/Skript1.rc b/protocols/SkypeClassic/Skript1.rc
new file mode 100644
index 0000000000..f93a1fae83
--- /dev/null
+++ b/protocols/SkypeClassic/Skript1.rc
@@ -0,0 +1,484 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_SETAVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Set",IDC_SETAVATAR,10,108,45,13,WS_GROUP
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,57,108,45,13
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN | WS_GROUP,10,10,96,93
+END
+
+IDD_OPT_DEFAULT DIALOGEX 0, 0, 310, 223
+STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Start Skype with Miranda IM if not running using the following command line options:",
+ IDC_STARTSKYPE,"Button",BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP,10,4,290,10
+ CONTROL "/NOSPLASH - Don't show splash screen on startup",
+ IDC_NOSPLASH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,36,17,
+ 264,12
+ CONTROL "/MINIMIZED - Start Skype minimized",IDC_MINIMIZED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,36,28,264,12
+ CONTROL "/NOTRAY - Skype tray icon becomes grey and is therefore ""invisible""",
+ IDC_NOTRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,36,40,
+ 264,12
+ CONTROL "/REMOVEABLE - For running portable skype",
+ IDC_REMOVEABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,36,
+ 51,264,12
+ CONTROL "/SECONDARY - This is the second instance",IDC_SECONDARY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,36,62,264,12
+ CONTROL "/DATAPATH - Specify Skype data folder*",IDC_DATAPATHO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,36,74,264,12
+ EDITTEXT IDC_DATAPATH,47,88,236,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSEDP,285,87,16,15
+ CONTROL "Use custom Skype executable*",IDC_CUSTOMCOMMAND,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,36,103,264,10
+ EDITTEXT IDC_COMMANDLINE,47,116,236,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSECMDL,285,115,16,15
+ CTEXT "* Relative path root is Miranda IM folder",
+ IDC_STATIC_PATHINFO,10,136,290,8,NOT WS_GROUP
+ CONTROL "Shutdown Skype when you close Miranda IM",IDC_SHUTDOWN,
+ "Button",BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,10,151,
+ 290,10
+ CONTROL "Unload Skype when you change to Offline status",
+ IDC_UNLOADOFFLINE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 10,164,290,11
+ LTEXT "Try at least",IDC_STATIC,10,185,39,8
+ EDITTEXT IDC_CONNATTEMPTS,52,183,21,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "times to connect to Skype API before giving up",
+ IDC_STATIC,78,185,224,8,NOT WS_GROUP
+ LTEXT "User name:",IDC_STATIC,10,206,38,8
+ EDITTEXT IDC_USERNAME,52,204,79,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,148,206,34,8
+ EDITTEXT IDC_PASSWORD,186,204,79,12,ES_PASSWORD | ES_AUTOHSCROLL
+END
+
+IDD_DIAL DIALOGEX 0, 0, 198, 46
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Dial"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Number:",IDC_STATIC,7,8,30,11
+ COMBOBOX IDC_NUMBER,41,6,149,13,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ DEFPUSHBUTTON "Dial",IDDIAL,88,25,50,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,141,25,50,14
+END
+
+IDD_CALLSTAT DIALOGEX 0, 0, 220, 67
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "%s is calling"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Join conference with %s",IDC_JOIN,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,7,7,206,10
+ CONTROL "Answer call; set call to %s on hold",IDC_HOLD,"Button",
+ BS_AUTORADIOBUTTON,7,19,206,10
+ CONTROL "Hang up",IDC_HANGUP,"Button",BS_AUTORADIOBUTTON,7,31,
+ 206,10
+ DEFPUSHBUTTON "OK",IDOK,163,46,50,14,WS_GROUP
+END
+
+IDD_INPUTBOX DIALOGEX 0, 0, 221, 46
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_TEXT,7,7,207,13,ES_AUTOHSCROLL | WS_GROUP
+ DEFPUSHBUTTON "OK",IDOK,112,25,50,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,165,25,50,14
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 313, 249
+STYLE DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Tab1",IDC_OPTIONSTAB,"SysTabControl32",0x0,0,-1,313,250
+END
+
+IDD_OPT_PROXY DIALOGEX 0, 0, 310, 223
+STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Use Skype proxy connection over network instead of local Skype API",
+ IDC_USES2S,"Button",BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP,10,4,290,9
+ LTEXT "Host:",IDC_STATIC_HOST,20,21,18,10
+ EDITTEXT IDC_HOST,41,19,133,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC_PORT,180,21,16,10,0,WS_EX_RIGHT
+ EDITTEXT IDC_PORT,200,19,29,12,ES_AUTOHSCROLL | ES_NUMBER
+ CTEXT "* You must restart Miranda IM in order to let the settings take effect",
+ IDC_STATIC_RESTART,10,54,290,8,NOT WS_GROUP
+ CONTROL "This Skype proxy requires password authentication:",
+ IDC_REQPASS,"Button",BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP,20,38,176,9
+ EDITTEXT IDC_PASSWORD,200,36,82,12,ES_PASSWORD | ES_AUTOHSCROLL
+END
+
+IDD_SETDETAILS DIALOGEX 0, 0, 216, 151
+STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Name:",IDC_STATIC,7,6,61,9
+ EDITTEXT IDC_FULLNAME,73,4,141,12,ES_AUTOHSCROLL
+ LTEXT "Birthday:",IDC_STATIC,7,20,61,9
+ CONTROL "DateTimePicker1",IDC_BIRTHDAY,"SysDateTimePick32",
+ DTS_RIGHTALIGN | DTS_APPCANPARSE | WS_TABSTOP,73,18,62,
+ 12
+ LTEXT "Sex:",IDC_STATIC,7,34,61,9
+ COMBOBOX IDC_SEX,73,32,141,12,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "City:",IDC_STATIC,7,48,61,9
+ EDITTEXT IDC_CITY,73,46,141,12,ES_AUTOHSCROLL
+ LTEXT "Country:",IDC_STATIC,7,62,61,9
+ EDITTEXT IDC_COUNTRY,73,60,141,12,ES_AUTOHSCROLL
+ LTEXT "Province:",IDC_STATIC,7,76,61,9
+ EDITTEXT IDC_PROVINCE,73,74,141,12,ES_AUTOHSCROLL
+ LTEXT "Home phone:",IDC_STATIC,7,90,61,9
+ EDITTEXT IDC_HOMEPHONE,73,88,141,12,ES_AUTOHSCROLL
+ LTEXT "Office phone:",IDC_STATIC,7,104,61,9
+ EDITTEXT IDC_OFFICEPHONE,73,102,141,12,ES_AUTOHSCROLL
+ LTEXT "Homepage:",IDC_STATIC,7,118,61,9
+ EDITTEXT IDC_HOMEPAGE,73,116,141,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Save",IDC_SAVEDETAILS,170,134,45,14,WS_GROUP
+END
+
+IDD_OPT_ADVANCED DIALOGEX 0, 0, 310, 223
+STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Enable Skype menu options (currently: Find/Add user)",
+ IDC_ENABLEMENU,"Button",BS_AUTOCHECKBOX | WS_GROUP |
+ WS_TABSTOP,10,4,290,9
+ CONTROL "Use popup plugin for displaying messages ",IDC_USEPOPUP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,19,290,9
+ CONTROL "Suppress all error messages (not recommended, but if it annoys you... ;)",
+ IDC_NOERRORS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,34,
+ 290,9
+ CONTROL "Use group chat interface for conversations (requires group chat module)",
+ IDC_GROUPCHAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,
+ 49,290,9
+ CONTROL "Mark group chat message as read to avoid notification",
+ IDC_GROUPCHATREAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 10,64,290,9
+ CONTROL "Keep requested online status on startup under every circumstance",
+ IDC_KEEPSTATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,
+ 79,290,9
+ CONTROL "Use time zone patch",IDC_TIMEZONE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,94,290,9
+ CONTROL "Ignore time zones",IDC_IGNTZ,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,10,109,290,9
+ CONTROL "Show default skype avatar for contacts",
+ IDC_SHOWDEFAULTAVATAR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,10,124,290,9
+ CONTROL "Suppress call summary chat message",
+ IDC_SUPPRESSCALLSUMMARYMESSAGE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,10,139,290,9
+ CONTROL "Disable support for N/A and SkypeMe status (for Skype 4+)",
+ IDC_NOSKYPE3STATS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 10,154,290,9
+ CONTROL "Show full name in contact list instead of nickname",
+ IDC_SHOWFULLNAME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 10,169,290,9
+ LTEXT "SkypeOut contacts are in status:",IDC_STATIC,10,186,108,
+ 8
+ COMBOBOX IDC_SKYPEOUTSTAT,120,184,79,54,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Cleanup Nicknames",IDC_CLEANUP,9,201,80,14,BS_MULTILINE |
+ WS_GROUP
+END
+
+IDD_OPT_POPUP DIALOGEX 0, 0, 310, 228
+STYLE DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Skype Popups",IDC_STATIC,0,1,309,227
+ GROUPBOX "Incoming Calls",IDC_STATIC,6,16,297,62,WS_GROUP
+ CONTROL "Show incoming calls",IDC_POPUPINCOMING,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,10,28,278,8
+ EDITTEXT IDC_POPUPTIME,16,41,20,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "seconds",IDC_STATIC,41,43,92,8,NOT WS_GROUP
+ CONTROL "",IDC_POPUPBACKCOLOR,"ColourPicker",WS_GROUP |
+ WS_TABSTOP,142,40,39,12
+ LTEXT "Background",IDC_STATIC_POPUPBACKCOLOR,186,42,50,8,
+ SS_CENTERIMAGE | NOT WS_GROUP
+ CONTROL "Use Windows colors",IDC_USEWINCOLORS,"Button",
+ BS_AUTOCHECKBOX | BS_NOTIFY | BS_FLAT | WS_TABSTOP,16,58,
+ 121,8
+ CONTROL "",IDC_POPUPTEXTCOLOR,"ColourPicker",WS_TABSTOP,142,55,
+ 39,12
+ LTEXT "Text",IDC_STATIC_POPUPTEXTCOLOR,186,56,50,8,
+ SS_CENTERIMAGE | NOT WS_GROUP
+ PUSHBUTTON "Preview",IDC_PREVIEW,247,58,50,14,WS_GROUP
+ GROUPBOX "Error Messages",IDC_STATIC,6,81,297,62,WS_GROUP
+ CONTROL "Display error messages",IDC_POPUPERROR,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,10,94,278,8
+ EDITTEXT IDC_POPUPTIMEERR,16,107,20,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "seconds",IDC_STATIC,41,109,92,8,NOT WS_GROUP
+ CONTROL "",IDC_POPUPBACKCOLORERR,"ColourPicker",WS_GROUP |
+ WS_TABSTOP,142,106,39,12
+ LTEXT "Background",IDC_STATIC_POPUPBACKCOLORERR,186,108,50,8,
+ SS_CENTERIMAGE | NOT WS_GROUP
+ CONTROL "Use Windows colors",IDC_USEWINCOLORSERR,"Button",
+ BS_AUTOCHECKBOX | BS_NOTIFY | BS_FLAT | WS_TABSTOP,16,
+ 124,121,8
+ CONTROL "",IDC_POPUPTEXTCOLORERR,"ColourPicker",WS_TABSTOP,142,
+ 121,39,12
+ LTEXT "Text",IDC_STATIC_POPUPTEXTCOLORERR,186,123,50,8,
+ SS_CENTERIMAGE | NOT WS_GROUP
+ PUSHBUTTON "Preview",IDC_PREVIEWERR,247,124,50,14,WS_GROUP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO MOVEABLE PURE
+BEGIN
+ IDD_SETAVATAR, DIALOG
+ BEGIN
+ LEFTMARGIN, 10
+ RIGHTMARGIN, 212
+ TOPMARGIN, 10
+ BOTTOMMARGIN, 121
+ END
+
+ IDD_OPT_DEFAULT, DIALOG
+ BEGIN
+ LEFTMARGIN, 1
+ VERTGUIDE, 10
+ VERTGUIDE, 300
+ TOPMARGIN, 4
+ END
+
+ IDD_DIAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 190
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 39
+ END
+
+ IDD_CALLSTAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 213
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 60
+ END
+
+ IDD_INPUTBOX, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 214
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 39
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ RIGHTMARGIN, 311
+ BOTTOMMARGIN, 243
+ END
+
+ IDD_OPT_PROXY, DIALOG
+ BEGIN
+ LEFTMARGIN, 10
+ RIGHTMARGIN, 300
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 221
+ END
+
+ IDD_SETDETAILS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 214
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 148
+ END
+
+ IDD_OPT_ADVANCED, DIALOG
+ BEGIN
+ LEFTMARGIN, 10
+ RIGHTMARGIN, 300
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 221
+ HORZGUIDE, 4
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_SKYPE ICON DISCARDABLE "res\\skype.ico"
+IDI_INVITE ICON DISCARDABLE "res\\Invite.ico"
+IDI_ADD ICON DISCARDABLE "res\\add.ico"
+IDI_IMPORT ICON DISCARDABLE "res\\import.ico"
+IDI_ERRORS ICON DISCARDABLE "res\\error.ico"
+IDI_MESSAGE ICON DISCARDABLE "res\\message.ico"
+IDI_CALL ICON DISCARDABLE "res\\call.ico"
+IDI_CALLSKYPEOUT ICON DISCARDABLE "res\\skypeout.ico"
+IDI_HOLD ICON DISCARDABLE "res\\hold.ico"
+IDI_RESUME ICON DISCARDABLE "res\\resume.ico"
+IDI_HANGUP ICON DISCARDABLE "res\\hang_up.ico"
+IDI_ONLINE ICON DISCARDABLE "res\\online.ico"
+IDI_CHAT ICON DISCARDABLE "res\\chat.ico"
+IDI_AWAY ICON DISCARDABLE "res\\away.ico"
+IDI_NA ICON DISCARDABLE "res\\na.ico"
+IDI_OCCUPIED ICON DISCARDABLE "res\\occupied.ico"
+IDI_DND ICON DISCARDABLE "res\\dnd.ico"
+IDI_INVISIBLE ICON DISCARDABLE "res\\invisible.ico"
+IDI_OFFLINE ICON DISCARDABLE "res\\offline.ico"
+IDI_PHONE ICON DISCARDABLE "res\\phone.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,0,0,54
+ PRODUCTVERSION 0,0,0,54
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "Miranda IM community\0"
+ VALUE "FileDescription", "Skype\0"
+ VALUE "FileVersion", "0, 0, 0, 54\0"
+ VALUE "InternalName", "Skype\0"
+ VALUE "LegalCopyright", "Copyright © 2007-2012 leecher - tweety - jls17\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "Skype.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Skype Protocol for Miranda IM\0"
+ VALUE "ProductVersion", "0, 0, 0, 54\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_CALL BITMAP MOVEABLE PURE "res\\call.bmp"
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Deutsch (Österreich) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEA)
+#ifdef _WIN32
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Deutsch (Österreich) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/SkypeClassic/SkypeClassic_10.filters b/protocols/SkypeClassic/SkypeClassic_10.filters
new file mode 100644
index 0000000000..2dbd1f22c6
--- /dev/null
+++ b/protocols/SkypeClassic/SkypeClassic_10.filters
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{4d6279cf-842d-458b-95b8-c0cebb4a5d71}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{eb3a2f1b-05b7-4a39-b7d9-41be6256999e}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{611796ce-4528-47d4-872f-4744f22bd19d}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="alogon.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="contacts.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="gchat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="memlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="msglist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="msgq.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pthread.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skype.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skypeapi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skypeopt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skypeprofile.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="skypesvc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utf8.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="voiceservice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="contacts.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="gchat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="memlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="msglist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pthread.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skype.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skypeapi.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skypeopt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skypeprofile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="skypesvc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="utf8.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="util.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="voiceservice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="alogon.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="msgq.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\add.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\away.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\call.bmp">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\call.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\chat.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\DND.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\error.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\hang_up.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\hold.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\import.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\invisible.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\Invite.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\message.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\NA.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\occupied.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\offline.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\online.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\phone.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\resume.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\skype.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="res\skypeout.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="changelog.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="Skript1.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/SkypeClassic/SkypeClassic_10.sln b/protocols/SkypeClassic/SkypeClassic_10.sln
new file mode 100644
index 0000000000..bf1063be79
--- /dev/null
+++ b/protocols/SkypeClassic/SkypeClassic_10.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SkypeClassic", "SkypeClassic_10.vcxproj", "{5F9243AE-C6C9-4F42-B670-67A97767A50B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Debug|Win32.Build.0 = Debug|Win32
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Debug|x64.ActiveCfg = Debug|x64
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Debug|x64.Build.0 = Debug|x64
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Release|Win32.ActiveCfg = Release|Win32
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Release|Win32.Build.0 = Release|Win32
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Release|x64.ActiveCfg = Release|x64
+ {5F9243AE-C6C9-4F42-B670-67A97767A50B}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/protocols/SkypeClassic/SkypeClassic_10.vcxproj b/protocols/SkypeClassic/SkypeClassic_10.vcxproj
new file mode 100644
index 0000000000..78f59c77ca
--- /dev/null
+++ b/protocols/SkypeClassic/SkypeClassic_10.vcxproj
@@ -0,0 +1,1249 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="ANSI Debug|Win32">
+ <Configuration>ANSI Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="ANSI Debug|x64">
+ <Configuration>ANSI Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="ANSI Release|Win32">
+ <Configuration>ANSI Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="ANSI Release|x64">
+ <Configuration>ANSI Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x64 Debug|Win32">
+ <Configuration>x64 Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x64 Debug|x64">
+ <Configuration>x64 Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x64 Release|Win32">
+ <Configuration>x64 Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x64 Release|x64">
+ <Configuration>x64 Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{5F9243AE-C6C9-4F42-B670-67A97767A50B}</ProjectGuid>
+ <RootNamespace>Skype_protocol</RootNamespace>
+ <ProjectName>SkypeClassic</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">false</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">false</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">false</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">false</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">false</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">false</EmbedManifest>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">false</LinkIncremental>
+ <EmbedManifest Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">false</EmbedManifest>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'" />
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">true</IgnoreImportLibrary>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">true</IgnoreImportLibrary>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>
+ </MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)Skype.pdb</ProgramDatabaseFile>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)Skype.pdb</ProgramDatabaseFile>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>
+ </RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <MinimalRebuild>
+ </MinimalRebuild>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>
+ </ProgramDatabaseFile>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>
+ </RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>
+ </ProgramDatabaseFile>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>
+ </RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_WIN64;_DEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>
+ </MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)Skype.pdb</ProgramDatabaseFile>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_WIN64;_DEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)Skype.pdb</ProgramDatabaseFile>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PreprocessorDefinitions>_WIN64;NDEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <MinimalRebuild>
+ </MinimalRebuild>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>
+ </ProgramDatabaseFile>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>
+ </RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PreprocessorDefinitions>_WIN64;NDEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>
+ </ProgramDatabaseFile>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>
+ </RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_MBCS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>
+ </MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)Skype.pdb</ProgramDatabaseFile>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)Skype.pdb</ProgramDatabaseFile>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_MBCS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <MinimalRebuild>
+ </MinimalRebuild>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>
+ </ProgramDatabaseFile>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>
+ </RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>
+ </TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SKYPE_PROTOCOL_EXPORTS;UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <CompileAs>Default</CompileAs>
+ <AdditionalIncludeDirectories>..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>skype.h</PrecompiledHeaderFile>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0000</Culture>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <ProgramDatabaseFile>
+ </ProgramDatabaseFile>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>
+ </RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ <AdditionalLibraryDirectories>$(ProfileDir)..\..\bin10\lib;</AdditionalLibraryDirectories>
+ </Link>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>
+ </OutputFile>
+ </Bscmake>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="alogon.cpp" />
+ <ClCompile Include="contacts.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="debug.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="gchat.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="memlist.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="msglist.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="msgq.cpp" />
+ <ClCompile Include="pthread.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="skype.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="skypeapi.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="skypeopt.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="skypeprofile.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="skypesvc.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="utf8.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <ClCompile Include="util.cpp" />
+ <ClCompile Include="voiceservice.cpp">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="alogon.h" />
+ <ClInclude Include="contacts.h" />
+ <ClInclude Include="debug.h" />
+ <ClInclude Include="gchat.h" />
+ <ClInclude Include="msgq.h" />
+ <ClInclude Include="memlist.h" />
+ <ClInclude Include="msglist.h" />
+ <ClInclude Include="pthread.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="skype.h" />
+ <ClInclude Include="skypeapi.h" />
+ <ClInclude Include="skypeopt.h" />
+ <ClInclude Include="skypeprofile.h" />
+ <ClInclude Include="skypesvc.h" />
+ <ClInclude Include="utf8.h" />
+ <ClInclude Include="util.h" />
+ <ClInclude Include="voiceservice.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\add.ico" />
+ <None Include="res\away.ico" />
+ <None Include="res\call.bmp" />
+ <None Include="res\call.ico" />
+ <None Include="res\chat.ico" />
+ <None Include="res\DND.ico" />
+ <None Include="res\error.ico" />
+ <None Include="res\hang_up.ico" />
+ <None Include="res\hold.ico" />
+ <None Include="res\import.ico" />
+ <None Include="res\invisible.ico" />
+ <None Include="res\Invite.ico" />
+ <None Include="res\message.ico" />
+ <None Include="res\NA.ico" />
+ <None Include="res\occupied.ico" />
+ <None Include="res\offline.ico" />
+ <None Include="res\online.ico" />
+ <None Include="res\phone.ico" />
+ <None Include="res\resume.ico" />
+ <None Include="res\skype.ico" />
+ <None Include="res\skypeout.ico" />
+ <None Include="changelog.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="Skript1.rc">
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='ANSI Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='x64 Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/SkypeClassic/alogon.cpp b/protocols/SkypeClassic/alogon.cpp
new file mode 100644
index 0000000000..8002d495fc
--- /dev/null
+++ b/protocols/SkypeClassic/alogon.cpp
@@ -0,0 +1,129 @@
+#include "skype.h"
+#include "debug.h"
+
+extern char g_szProtoName[];
+extern HANDLE SkypeReady;
+
+/**
+ * Purpose: Retrieves class name from window
+ *
+ * Note: This is some sort of hack to return static local variable,
+ * but it works :)
+ */
+static const TCHAR* getClassName(HWND wnd)
+{
+ static TCHAR className[256];
+
+ *className=0;
+ GetClassName(wnd, &className[0], sizeof(className)/sizeof(className[0]));
+ return className;
+}
+
+/**
+ * Purpose: Finds a window
+ *
+ * Note: This function relies on Skype window placement.
+ * It should work for Skype 3.x
+ */
+static HWND findWindow(HWND parent, const TCHAR* childClassName)
+{
+ // Get child window
+ // This window is not combo box or edit box
+ HWND wnd = GetWindow(parent, GW_CHILD);
+ while(wnd != NULL && _tcscmp(getClassName(wnd), childClassName) != 0)
+ wnd = GetWindow(wnd, GW_HWNDNEXT);
+
+ return wnd;
+}
+
+static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
+{
+ DWORD dwPID;
+ const TCHAR *lpszClassName;
+
+
+ GetWindowThreadProcessId(hWnd,&dwPID);
+ if (lParam != 0 && dwPID != (DWORD)lParam) return TRUE;
+ lpszClassName = getClassName(hWnd);
+ if(_tcscmp(lpszClassName, _T("tSkMainForm.UnicodeClass")) == 0 ||
+ _tcscmp(lpszClassName, _T("TLoginForm.UnicodeClass")) == 0)
+ {
+ HWND loginControl = GetWindow(hWnd, GW_CHILD);
+
+ LOG(("setUserNamePasswordThread: Skype window found!"));
+
+ // Sleep for some time, while Skype is loading
+ // It loads slowly :(
+ //Sleep(5000);
+ LOG (("TLoginControl = %S", getClassName(loginControl)));
+
+ // Check for login control
+ if(_tcscmp(getClassName(loginControl), _T("TLoginControl")) == 0)
+ {
+ // Find user name window
+ HWND userName = findWindow(loginControl, _T("TNavigableTntComboBox.UnicodeClass"));
+ HWND password = findWindow(loginControl, _T("TNavigableTntEdit.UnicodeClass"));
+
+ LOG (("userName=%08X; password=%08X", userName, password));
+ if (userName && password)
+ {
+ // Set user name and password
+ DBVARIANT dbv;
+
+ if(!db_get_ws(NULL,SKYPE_PROTONAME,"LoginUserName",&dbv))
+ {
+ SendMessageW(userName, WM_SETTEXT, 0, (LPARAM)dbv.pwszVal);
+ db_free(&dbv);
+ }
+
+ if(!db_get_ws(NULL,SKYPE_PROTONAME,"LoginPassword",&dbv))
+ {
+ SendMessageW(password, WM_SETTEXT, 0, (LPARAM)dbv.pwszVal);
+ db_free(&dbv);
+ SendMessageW(password, WM_CHAR, 13, 0);
+ }
+
+
+ SendMessageW(hWnd,
+ WM_COMMAND,
+ 0x4a8, // sign-in button; WARNING: This ID can change during newer Skype versions
+ (LPARAM)findWindow(loginControl, _T("TTntButton.UnicodeClass")));
+ }
+ return FALSE;
+ }
+
+ }
+ return TRUE;
+}
+
+DWORD WINAPI setUserNamePasswordThread(LPVOID lpDummy)
+{
+ DWORD dwPid = (DWORD)lpDummy;
+ HANDLE mutex = CreateMutex(NULL, TRUE, _T("setUserNamePasswordMutex"));
+
+ // Check double entrance
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ return 0;
+
+ WaitForSingleObject(SkypeReady, 5000);
+ EnumWindows (EnumWindowsProc, dwPid);
+
+ ReleaseMutex(mutex);
+ CloseHandle(mutex);
+ return 0;
+}
+
+/**
+ * Purpose: Finds Skype window and sets user name and password.
+ *
+ * Note: This function relies on Skype window placement.
+ * It should work for Skype 3.x
+ */
+void setUserNamePassword(int dwPid)
+{
+ DWORD threadId;
+ CreateThread(NULL, 0, &setUserNamePasswordThread, (LPVOID)dwPid, 0, &threadId);
+
+ // Give time to thread
+ Sleep(100);
+}
diff --git a/protocols/SkypeClassic/alogon.h b/protocols/SkypeClassic/alogon.h
new file mode 100644
index 0000000000..00d2e7e703
--- /dev/null
+++ b/protocols/SkypeClassic/alogon.h
@@ -0,0 +1 @@
+void setUserNamePassword(int dwPid);
diff --git a/protocols/SkypeClassic/changelog.txt b/protocols/SkypeClassic/changelog.txt
new file mode 100644
index 0000000000..60526b1116
--- /dev/null
+++ b/protocols/SkypeClassic/changelog.txt
@@ -0,0 +1,330 @@
+NOTES
+-----
+
+ You have to manually disable popup of messages in SKYPE, as there is
+ currently no function in the API to do this
+ Got to File/Options/Instant messages and disable the checkboxes there
+
+
+CODE
+----
+ Currently a real mess. At least I splitted it up a bit now.
+ But hey, it kinda works... ;)
+
+HISTORY
+-------
+
+0.0.0.45 - ! "NA" and "Free for chat" status are available again; NA is supported by skype and Free for chat
+ uses skypes "Skype Me" status; better leave it that way
+ ! changes to the mood message of a contact were only visible after a status change
+ ! plugin was crashing when status changed to offline and a proxy is used
+
+0.0.0.44 - ! menu item "Hang up (Skype)" was show on none skype contacts
+ ! fixed serveral bugs in skype startup (including starting skype twice)
+ ! show connecting state correctly
+ ! hangup while ringing caused a state where contact isnt callable anymore
+ * removed "NA" and "Free for chat" status
+
+0.0.0.43 - + Added option to suppress summary chat message after call is finished (jls17)
+ ! Fix hangup causes a dial command if opponent hangs up a little bit earlier (jls17)
+ ! removed empty chat message on incoming call
+ ! empty mood message is send to skype correctly
+
+
+0.0.0.42 - + Added a trick to identify skype 3 version (fingerprint)
+0.0.0.41 - + Added option to enter user name and password. (Patch by NN)
+
+0.0.0.40 - + Support for new core service: get avatar caps
+ + Option to show/hide default avatar for contacts
+ + Hide Skype Avatar page in user details if >= #27
+
+0.0.0.39 - + Voice service support in normall calls - no support for SkypeOut yet (pescuma)
+ ! Made options dialog a little bit smaller, removed frame and set bold frame for popups (pescuma)
+ + Add more status to manage for away message
+
+0.0.0.38 - ! Fix the load for pre 0.7.0 #17 build
+ * Patch by pescuma for avatar.
+
+0.0.0.37 - ! Avoid empty message from myself on first message received.
+ + Add the Get user avatar interface
+ * Change the get user info thread
+ * code cleanup
+ + Support for miranda 0.8
+ ! Correct use of folder plugin (using "avatar cache folder"\SKYPE).
+
+0.0.0.36 - ! When settings skype offline, first set proto off then contacts.
+ * move the broadcast of status change out of if statement in status change.
+ * Set contacts ofline on plugin load (avoid skype contact to be online if starts skype is not checked)
+ ! Fix the use of datapath for portable skype
+ * Allow to choose no splash - no tray - minimized even if start skype with miranda is not checked.
+ ! Fix bug with timestamp in irc
+
+0.0.0.35 - * Use unicode nick, status message, city and country in skype profile.
+ ! Fix for sending status change when offline
+ * Do not send message to skype if not attached (avoid trying to connect to api at startup)
+ ! Fix crash on recieving message with groupchat checked.
+
+0.0.0.34 - + Try to identify if chat message comes from a group chat or not
+ + Add a option to flag group chat message as read if not using chat.dll for group chat.
+ ! Fix the check of message type (group chat or normal)
+
+0.0.0.33 - ! Fix for flags of event and metacontact (thanks SJE)
+ * Next step to custom popup support (in popup option page)
+ ! Fix infinite for error popup
+
+0.0.0.32 - ! Improvemnt of the Action message support.
+ ! Fix empty message on first chat with a contact.
+
+0.0.0.31 - + First step to Action Message support ( /me )
+ + Updater support for File Listing.
+ + First step to a custom popup for call notification.
+
+0.0.0.30 - + Add an option to enable/disable the timezone patch
+
+0.0.0.29 - ! Try to fix the bug (set skype offline when closing miranda)
+
+0.0.0.28 - * Improved portable skype integration
+
+0.0.0.27 - * Try to fix the start using custom command line
+ + Close skype using custom command line too
+
+0.0.0.26 - + Add a way to use a custom command line to start skype.
+
+0.0.0.25 - ! patch from markcs about timezones.
+ ! shutdown patch by sje
+
+0.0.0.24 - * Change options dialog (use tabsrmm uxtheme)
+
+0.0.0.23 - ! Wrong db entry name for cellular (cellucar)
+ + Set mirver using is video capabale to identify skype 2.0 user
+
+0.0.0.22 - * Options page redesigned
+ * Work around to force refresh of avatar in MyDetail (w8 the avatar change service)
+ * Change Skype protocol to Skype in options->Network
+ * Free buffer in status message retrieve
+ * First step to a details info page.
+
+0.0.0.21 - * Some minor bugfixes
+ * Severe bugfix: Message sending routine worked incorrectly (no errors were shown
+ even if there were sending-errors)
+ * Removed PingPong - thread in favour of WM_TIMER
+ * Fixed critical section unlocking in skypeapi.c. In certain cases, critical sections
+ were not left correctly.
+ * Fixed a bug that caused Miranda to crash on exit with Newstatusnotify plugin
+ (thanks to TioDuke for reporting)
+ * Hopefully fixed the nasty bug that caused Miranda to lockup on exit.
+
+0.0.0.20 - * Split service and options in two new cpp file.
+ * Put the default attemps number to 10
+
+0.0.0.19 - * Add avatar support for own user only (no api to ge contacts avatar)
+ * Add set status message.
+ * Add Get status message for contact where viewing contact details
+ * Change icons (thanks to Faith Healer)
+ * Updater support (BETA ONLY)
+ * DBeEditor known module support
+ * Mods to avoid warning in VC++ 8
+ * Implement the MyDetail requested services
+
+0.0.0.18 - * HOTFIX - Double File-Transfer icon removed. Please note that you can't send files
+ via drag & drop, because of the nature of Skype API - Skype wants to open its own
+ "File/Open" dialog, so I cannot supply a path to the file to be sent, therefore I
+ had to add a seperate File-sending function rather than using Miranda's function.
+
+0.0.0.17 - * Startup of Skype in a seperate thread was not solved properly. Now it should really
+ start in background
+ * The hack for the statusmode-bug is optional in the settings and is turned off
+ per default. (Thx to Eddie Hung for reporting problems and help)
+ * Added an ugly hack for the Skype-API offline bug (grr.. )
+ * Nickname is now set correctly. To cleanup the existing Nicks, please go to
+ the options page an push the "Cleanup Nicknames" button.
+ This will clean out entries where the Nick was set to the Skype handle
+ * Fixed a bug in the message sending routine that caused errors in communication
+ (missed messages in Skype that were not fetched..)
+ * Added "Hold call" feature while calling
+ * Added support for conference calls (if a second user is calling while you
+ are in a conversation, you can now choose whether to block the call or let
+ the user join you in a conference with the existing caller or to put the
+ other caller on hold)
+ * Fixed a bug in the code for adding users that were just searched via the
+ Skype search-window but never have been in contact list.
+ * Fixed some bugs (memleak, nick error, ..) in the Search-Routine for
+ Skype-contacts. (thx to Deadman for reporting)
+ * Fixed a bug with unknown SKYPE_IN contacts
+ * Added file-sending capability (requires new Skype-version)
+ * Did a litte code-cleanup
+ * Adding / Removing contacts can now be done via the Miranda standard-dialogs if
+ you use the newest Skype-Version
+ * With the new Skype-version you are able to handle Authorisation-Requests via Miranda
+ now.
+
+0.0.0.16 - * Fixed a severe memory-allocation bug in utf8-encoded messages that caused random
+ crashes (oops :-O) - Thanks to Ary Dvoretz for reporting.
+ * Bug in SkypeStatusMode-Bug fix from last release fixed (protocol stayed offline)
+ * Now onlinestatus for SkypeOut-Contacts is configurable
+ * Made Menu-Options translatable
+ * Added support for calling SkypeOut-Phonenumbers. You can now dial a PSTN-Number
+ by calling "Do a SkypeOut call" in the main menu (or top toolbar if the
+ toptoolbar plugin is installed) and entering a number or
+ by right-clicking on a non-Skype contact and selecting "Call using SkypeOut",
+ if there is a phone-Number entry in the User's-Details.
+ This, of course, is only working if you have SkypeOut privilege
+
+0.0.0.15 - * Fixed a crash on Miranda-exit when error occured on Skype-Protocol start
+ * Fixed Bug #0000006: Now user is asked if he wants to enable the Protocol
+ for the current profile, if he starts with a new profile.
+ * Fixed Bug #0000002: Now interfacing with Skype is really stopped on going
+ offline if the option is enabled. (PingPong-thread killed)
+ - This also applies on closing Skype
+ * Fixed a memory leak in MsgFetchThread that appeared in the last version because
+ of the groupchat-implementation (free() within wrong if clause, ooops ;)
+ * Fixed Bug #0000005: When there is a msg from a user that is not on Skype's contact
+ list, the user is now added PALF_TEMPORARY and disappears again on next Miranda-start
+ * Implemented a fix for Skype API's statusmode bug reported by Markus Mützel:
+ If you change the online status while Skype is still connecting, Skype changes to
+ the FIRST state that it was requested to change to, after going online, instead of
+ the LAST state. However the bug was not reproducable for me.
+ * Fixed broken popup-support (I hope)
+ * CHANGE of behaviour (inspired by Bug #0000007):
+ If you turn off "Start Skype with Miranda", the plugin wouldn't search for a
+ running Skype instance anymore.
+ * Now when going online and Skype is not launched, Skype will be launched via a
+ seperate thread (in background) so that Miranda isn't blocked while Skype is loading
+ * Options Dlg. should now be translateable too.
+
+0.0.0.14 -
+ * Miranda crash on exit if Skype was not found installed should be
+ fixed by now.
+ * Implemented compatibility layer for Skype API Protocol V3 and above.
+ * Removed some useless code introduced in 0.0.0.12
+ * Added some fixes made by TioDuke (thank you!)
+ - Using your own Nick instead of your Skype-Handle in conversations
+ - LastName 3rd token & above are not ignored any more
+ - Status modes "On the phone" and "out to lunch" are mapped now
+ * Fixed a bug that caused "Skype API not available" messages under high load.
+ (thanks to Romeo28 for testing!)
+ * Fixed a bug that caused Message sending thread to wait forever if sending
+ a message times out (causing dead threads)
+ * Skype contact list should be synced now when Skype-Status changes.
+ (thx to Markus Mützel for Bugreport)
+ * Implemented a garbage collector that removes old messages from queue
+ in order to prevent possible memory exhaustion
+ * Added option to disable all modal Error-message dialog boxes (as people
+ keep telling me that they are annoyed by them)
+ * Added langpack support for error messages
+ * Added option to increase the time the protocol is waiting for Skype
+ * Added groupchat functions. WARNING: For testing purposes only!
+ Currently there is a memleak which I cannot find, but even worse,
+ Skype API doesn't seem to support sending to a groupchat, inviting etc.
+ So this is currently only experimental! When you send to a groupchat you
+ currently send single messages to every user seperately. Skype staff
+ didn't answer my question about sending to groupchats so far, so it
+ depends on them when this feature will be available for real use.
+
+0.0.0.13 - A few minor fixes:
+ * Logging off users shouldn't flood the StatusNotify-Plugin now.
+ * Popup-plugin can be enabled/disabled in the options dlg.
+ * Implemented support for SkypeOut contacts (they caused crashes)
+ * Now using Nick instead of Skype-Handle as Contact list name on
+ adding new users, if it is available.
+
+0.0.0.12 - Bugfixing because of strange Skype API behaviour:
+ * Adding of contacts that are just searched, but not added in Skype
+ should be prevented now.
+ * Version number correct again.
+
+0.0.0.11 - Only minor bugfixes:
+ * The gender in user-details is now saved correctly to the DB
+ (thanks to LeON for the hint!)
+ * The Apply-Button should now be disabled in the options DLG by default
+ (thanks to sje for the bug report)
+ * Contactlist should be reinitialized after a SYNC-Problem now.
+ * Bug with usernames that contain commas should be fixed
+ * Protocol messages are now shown as popups if Popup-plugin is installed
+
+0.0.0.10 - * Hopefully recovery after sync problem works a bit better now
+ (Sync-Problem Messages are no longer shown)
+ * Now you can hang up a call directly from a contact's context menu
+ * Now implemented support for using Skype over a network. You can use
+ the included skypeproxy service to in/output Skype API messages
+ on a socket and can connect to it with the plugin.
+ So you can, for example, launch the skypeproxy service on your
+ Windows-server (eeek! :P) and control Skype from your workstation
+ using Miranda. (requested feature by foosmate)
+ * Now you can accept incoming calls via Miranda (or hang them up)
+ * The status mode bug (clist status menu was not updated properly)
+ should be fixed by now.
+ * The logfile in the dbeug-build should now always be written to the
+ Miranda directory.
+
+0.0.0.9 - * Fixed bug with error when starting Skype with Miranda ("Wheee...")
+ * As Skype seems to use new, UNDOCUMENTED Message types (I think it's
+ a severe Skype-API bug) I adapted the plugin so that it works
+ with new API now. This fixes the problem of not being able to receive
+ messages in new Skype versions.
+ Skype now sends "MESSAGE TYPE SAID" instead of "MESSAGE TYPE TEXT",
+ the bug has been reported to Skype forum.
+ (http://forum.skype.com/viewtopic.php?t=15435)
+ * Fixed a memory leak in Message-receiving routine
+ * Added UTF8-support for Contact properties (does this fix something?)
+ * Fixed a memory leak in Startup-routine
+ * Finally renamed Plugin from SKYPE_PROTOCOL to SKYPE internally.
+ Hopefully it will upgrade your existing DB seamlessly.
+ * Now all threads should be sync with Miranda as I'm using the pthread-
+ functions "borrowed" from Yahoo protocol.
+
+0.0.0.8 - * Now there is support for the "Occupied" mode, which is mapped to DND
+ This is useful for users who do a global statusmodechange so that Skype
+ gets to "Occupied" state instead of staying online.
+ * Now the protocol doesn't disable itself when you chose to not start
+ Skype on startup, instead it stays offline and starts Skype when you
+ try to go online.
+
+0.0.0.7 - * Fixed a bug that caused a lockup on Plugin startup (when a Window was not
+ reacting to the HWND_BROADCAST) (thx to Cool Blue)
+ * Fixed a bug in the Startup-procedure..
+ * Now Skype doesn't go offline when you close Miranda (thx to Egodust)
+ * Now it should really work unter WIN98 (thx to TioDuke for testing)
+ * Implemented feature for Shutting down Skype on going offline and
+ restarting Skype on changing to online mode again, as many people requested.
+
+0.0.0.6 - * Added feature requests from kreisquadratur:
+ * Option to disable Skype-Menuitems
+ * Fixed bug with Apply-Button
+ * Using a nicer Skype-Icon now
+ * Now using Skype-Timestamp for messages
+ * Implementing importing history from skype (see contextmenu of contact)
+ * Fixed bug with processing first message of MESSAGES - List
+ * Found out, that RegisterClass() doesn't work for UNICODE-Programs on
+ non-UNICODE win98, therefore return-value check for RegisterClass removed
+ * Fixed a bug that caused a "We got a Sync problem :("
+
+0.0.0.5 - * Fixed a bug that caused the plugin to crash with bigger contact lists
+ (Skype API was flooded on startup)
+
+0.0.0.4 - * Missed messages are fetched now
+ * User details work now
+ * More verbose error msgs now (to help Win98 user debugging his problem)
+ * Added option for starting skype with miranda and shutting down
+ Skype when closing miranda.
+ * You can now chose the command line options to pass to Skype on startup
+ * Hopefully the bug with multiple Call - Entries per user is fixed now
+ * Protocol name is now "Skype", not "Skype_protocol" - Remember this
+ when updating, so DELETE skype_protocol.dll first!!
+ * Secured Message Queue with a Mutex
+ * Fixed a Message-receiving bug that could cause delays in message-processing
+ * Adding a Contact in Skype now also adds it to Miranda immediately
+ (Deleting should also work, but doesn't because of a Skype API bug)
+ * Added searching for contacts, but this feature seems to be quite useless,
+ as Skype API doesn't support adding contacts, so you still have to add
+ your contacts in the Skype program, sorry
+ In order to do this comfortably, I added a Miranda Menu-Item for adding
+ Skype-contacts.
+
+0.0.0.3 - * I hope it's thread-safe now
+ * Changing the Online-Status should work correctly now
+ * Fixed "We got a sync problem :(" bug - big thx to Azzie
+ * Now starts Skype more in the background as proposed by Kreisquadratur
+ * Implemented PING-PONG with Skype to detect if Connection to Skype API
+ was lost
+ * Launching of Skype by Miranda improved
diff --git a/protocols/SkypeClassic/contacts.cpp b/protocols/SkypeClassic/contacts.cpp
new file mode 100644
index 0000000000..8e25ae7c9d
--- /dev/null
+++ b/protocols/SkypeClassic/contacts.cpp
@@ -0,0 +1,419 @@
+/*
+ * Contactlist management functions
+ */
+
+#include "skype.h"
+#include "skypeapi.h"
+#include "debug.h"
+#include "pthread.h"
+#include "gchat.h"
+#include "voiceservice.h"
+
+#pragma warning (push)
+#pragma warning (disable: 4100) // unreferenced formal parameter
+#include <m_langpack.h>
+#pragma warning (pop)
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+// Imported Globals
+extern HINSTANCE hInst;
+extern BOOL bSkypeOut, bIsImoproxy;
+extern char protocol, g_szProtoName[];
+
+// Handles
+static HANDLE hMenuCallItem, hMenuCallHangup, hMenuSkypeOutCallItem, hMenuHoldCallItem, hMenuFileTransferItem, hMenuChatInitItem;
+
+// Check if alpha blending icons are supported
+// Seems to be not neccessary
+/*
+BOOL SupportAlphaIcons(void) {
+ HANDLE hMod;
+ DLLVERSIONINFO tDVI={0};
+ BOOL retval=FALSE;
+ FARPROC pDllGetVersion;
+
+ if (!(hMod=LoadLibrary("comctl32.dll"))) return FALSE;
+ if (pDllGetVersion=GetProcAddress(hMod, "DllGetVersion")) {
+ tDVI.cbSize=sizeof(tDVI);
+ if (!pDllGetVersion ((DLLVERSIONINFO *)&tDVI)) {
+ if (GetDeviceCaps(GetDC(NULL), BITSPIXEL)*GetDeviceCaps(GetDC(NULL), PLANES)>=32 &&
+ tDVI.dwMajorVersion>=6)
+ retval=TRUE;
+ }
+ }
+ FreeLibrary(hMod);
+ return retval;
+}
+*/
+
+CLISTMENUITEM CallItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_NOTOFFLINE|CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALL));
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.ptszName=LPGENT("Call (Skype)");
+ mi.pszService=SKYPE_CALL;
+
+ return mi;
+}
+
+CLISTMENUITEM SkypeOutCallItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_HIDDEN|CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALLSKYPEOUT));
+ mi.ptszName=LPGENT("Call using SkypeOut");
+ mi.pszService=SKYPEOUT_CALL;
+
+ return mi;
+}
+
+CLISTMENUITEM HupItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_NOTOFFLINE|CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_HANGUP));
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.ptszName=LPGENT("Hang up call (Skype)");
+ mi.pszService=SKYPE_CALLHANGUP;
+
+ return mi;
+}
+
+CLISTMENUITEM SkypeOutHupItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_HANGUP));
+ mi.ptszName=LPGENT("Hang up SkypeOut call");
+ mi.pszService=SKYPEOUT_CALL;
+ return mi;
+}
+
+CLISTMENUITEM HoldCallItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_HIDDEN|CMIF_NOTOFFLINE|CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_HOLD));
+ mi.ptszName=LPGENT("Hold call");
+ mi.pszService=SKYPE_HOLDCALL;
+ return mi;
+}
+
+CLISTMENUITEM ResumeCallItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_HIDDEN|CMIF_NOTOFFLINE|CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_RESUME));
+ mi.ptszName=LPGENT("Resume call");
+ mi.pszService=SKYPE_HOLDCALL;
+ return mi;
+}
+
+CLISTMENUITEM FileTransferItem(void) {
+ CLISTMENUITEM mi={0};
+
+ // Stolen from file.c of Miranda core
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000020000;
+ mi.flags=CMIF_HIDDEN|CMIF_NOTOFFLINE|CMIF_TCHAR;
+ mi.hIcon=LoadSkinnedIcon(SKINICON_EVENT_FILE);
+ mi.ptszName=LPGENT("&File");
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.pszService=SKYPE_SENDFILE;
+ return mi;
+}
+
+CLISTMENUITEM ChatInitItem(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000020000;
+ mi.flags=CMIF_HIDDEN|CMIF_NOTOFFLINE|CMIF_TCHAR;
+ mi.hIcon=LoadIcon( hInst, MAKEINTRESOURCE( IDI_INVITE ));
+ mi.ptszName=LPGENT("&Open groupchat");
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.pszService=SKYPE_CHATNEW;
+ return mi;
+}
+
+HANDLE add_contextmenu(HANDLE hContact) {
+ CLISTMENUITEM mi;
+
+ UNREFERENCED_PARAMETER(hContact);
+
+ if (!HasVoiceService()) {
+ mi=CallItem();
+ hMenuCallItem=Menu_AddContactMenuItem(&mi);
+ mi=HupItem();
+ hMenuCallHangup=Menu_AddContactMenuItem(&mi);
+ }
+
+ mi=SkypeOutCallItem();
+ hMenuSkypeOutCallItem=Menu_AddContactMenuItem(&mi);
+
+ if (!HasVoiceService()) {
+ mi=HoldCallItem();
+ hMenuHoldCallItem=Menu_AddContactMenuItem(&mi);
+ }
+
+ // We cannot use flag PF1_FILESEND for sending files, as Skype opens its own
+ // sendfile-Dialog.
+ mi=FileTransferItem();
+ hMenuFileTransferItem=Menu_AddContactMenuItem(&mi);
+
+ mi=ChatInitItem();
+ hMenuChatInitItem=Menu_AddContactMenuItem(&mi);
+
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_IMPORT));
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.ptszName=LPGENT("Import Skype history");
+ mi.pszService=SKYPE_IMPORTHISTORY;
+ return Menu_AddContactMenuItem(&mi);
+}
+
+HANDLE add_mainmenu(void) {
+ CLISTMENUITEM mi={0};
+
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=CMIF_TCHAR;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_ADD));
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.ptszName=LPGENT("Add Skype contact");
+ mi.pszService=SKYPE_ADDUSER;
+ return Menu_AddMainMenuItem(&mi);
+
+}
+
+int __cdecl PrebuildContactMenu(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ CLISTMENUITEM mi;
+ char *szProto;
+ BOOL callAvailable = FALSE;
+ BOOL hangupAvailable = FALSE;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!(szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0))) return 0;
+
+ if (!HasVoiceService()) {
+ // Clear hold-Item in case it exists
+ mi=HoldCallItem();
+ mi.flags|=CMIM_ALL;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuHoldCallItem,(LPARAM)&mi);
+ }
+
+ if (!strcmp(szProto, SKYPE_PROTONAME)) {
+ if (!HasVoiceService()) {
+ if (!db_get((HANDLE)wParam, SKYPE_PROTONAME, "CallId", &dbv)) {
+ if (db_get_b((HANDLE)wParam, SKYPE_PROTONAME, "OnHold", 0))
+ mi=ResumeCallItem(); else mi=HoldCallItem();
+ mi.flags=CMIM_ALL;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuHoldCallItem,(LPARAM)&mi);
+
+ callAvailable = FALSE;
+ hangupAvailable = TRUE;
+
+ db_free(&dbv);
+ } else { callAvailable = TRUE; hangupAvailable = FALSE; }
+
+ if (db_get_b((HANDLE)wParam, SKYPE_PROTONAME, "ChatRoom", 0)!=0) {
+ callAvailable = FALSE;
+ hangupAvailable = FALSE;
+ }
+
+ mi = CallItem();
+ mi.flags |= CMIM_ALL | (!callAvailable?CMIF_HIDDEN:0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuCallItem,(LPARAM)&mi);
+
+ mi = HupItem();
+ mi.flags |= CMIM_ALL | (!hangupAvailable?CMIF_HIDDEN:0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuCallHangup,(LPARAM)&mi);
+ }
+
+ // Clear SkypeOut menu in case it exists
+ mi=SkypeOutCallItem();
+ mi.flags|=CMIM_ALL;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuSkypeOutCallItem,(LPARAM)&mi);
+
+ // File sending and groupchat-creation works starting with protocol version 5
+ if (protocol>=5) {
+ mi=FileTransferItem();
+ if (db_get_b((HANDLE)wParam, SKYPE_PROTONAME, "ChatRoom", 0)==0)
+ mi.flags ^= CMIF_HIDDEN;
+ mi.flags |= CMIM_FLAGS;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuFileTransferItem,(LPARAM)&mi);
+ }
+
+ if (protocol>=5 || bIsImoproxy) {
+ mi=ChatInitItem();
+ if (db_get_b(NULL, SKYPE_PROTONAME, "UseGroupchat", 0) &&
+ db_get_b((HANDLE)wParam, SKYPE_PROTONAME, "ChatRoom", 0)==0)
+ mi.flags ^= CMIF_HIDDEN;
+ mi.flags |= CMIM_FLAGS;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuChatInitItem,(LPARAM)&mi);
+ }
+
+ } else if (bSkypeOut) {
+ if (!db_get((HANDLE)wParam, SKYPE_PROTONAME, "CallId", &dbv)) {
+ mi=SkypeOutHupItem();
+ db_free(&dbv);
+ } else {
+ mi=SkypeOutCallItem();
+ if(!db_get((HANDLE)wParam,"UserInfo","MyPhone0",&dbv)) {
+ db_free(&dbv);
+ mi.flags=0;
+ }
+ }
+ mi.flags|=CMIM_ALL;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HANDLE)hMenuSkypeOutCallItem,(LPARAM)&mi);
+ }
+
+ return 0;
+}
+
+/*
+int ClistDblClick(WPARAM wParam, LPARAM lParam) {
+ char *szProto;
+
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) &&
+ db_get_w((HANDLE)wParam, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE)==ID_STATUS_ONTHEPHONE) {
+ SkypeCall(wParam, 0);
+ }
+
+ return 0;
+}
+*/
+
+HANDLE find_contact(char *name) {
+ char *szProto;
+ int tCompareResult;
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ // already on list?
+ for (hContact=(HANDLE)db_find_first();hContact != NULL;hContact=db_find_next(hContact))
+ {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) && db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0)==0)
+ {
+ if (db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) continue;
+ tCompareResult = strcmp(dbv.pszVal, name);
+ db_free(&dbv);
+ if (tCompareResult) continue;
+ return hContact; // already there, return handle
+ }
+ }
+ return NULL;
+}
+HANDLE find_contactT(TCHAR *name) {
+ char *szProto;
+ int tCompareResult;
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ // already on list?
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact))
+ {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) && db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0)==0)
+ {
+ if (db_get_ts(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) continue;
+ tCompareResult = _tcscmp(dbv.ptszVal, name);
+ db_free(&dbv);
+ if (tCompareResult) continue;
+ return hContact; // already there, return handle
+ }
+ }
+ return NULL;
+}
+
+
+HANDLE add_contact(char *name, DWORD flags) {
+ HANDLE hContact;
+
+ // already on list?
+ if (hContact=find_contact(name)) {
+ if (!(flags & PALF_TEMPORARY) && db_get_b(hContact, "CList", "NotOnList", 1)) {
+ db_unset( hContact, "CList", "NotOnList" );
+ db_unset( hContact, "CList", "Hidden" );
+ }
+ LOG(("add_contact: Found %s", name));
+ return hContact; // already there, return handle
+ }
+ // no, so add
+
+ LOG(("add_contact: Adding %s", name));
+ hContact=(HANDLE)CallServiceSync(MS_DB_CONTACT_ADD, 0, 0);
+ if (hContact) {
+ if (CallServiceSync(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact,(LPARAM)SKYPE_PROTONAME)!=0) {
+ LOG(("add_contact: Ouch! MS_PROTO_ADDTOCONTACT failed for some reason"));
+ CallServiceSync(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ return NULL;
+ }
+ if (name[0]) db_set_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, name);
+
+ if (flags & PALF_TEMPORARY ) {
+ db_set_b(hContact, "CList", "NotOnList", 1);
+ db_set_b(hContact, "CList", "Hidden", 1);
+ }
+ if (name[0]) {
+ SkypeSend("GET USER %s DISPLAYNAME", name);
+ } else {LOG(("add_contact: Info: The contact added has no name."));}
+ } else {LOG(("add_contact: Ouch! MS_DB_CONTACT_ADD failed for some reason"));}
+ LOG(("add_contact succeeded"));
+ return hContact;
+}
+
+void logoff_contacts(BOOL bCleanup) {
+ HANDLE hContact;
+ char *szProto;
+ DBVARIANT dbv={0};
+
+ LOG(("logoff_contacts: Logging off contacts."));
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME))
+ {
+ if (db_get_w(hContact, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE)!=ID_STATUS_OFFLINE)
+ db_set_w(hContact, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE);
+
+ db_unset(hContact, SKYPE_PROTONAME, "CallId");
+ if (db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0)==1)
+ {
+ if (db_get_ts(hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv)) continue;
+ RemChat (dbv.ptszVal);
+ db_free(&dbv);
+ }
+ if (db_get_s(hContact, SKYPE_PROTONAME, "Typing_Stream", &dbv) == 0)
+ {
+ if (bCleanup) SkypeSend ("ALTER APPLICATION libpurple_typing DISCONNECT %s", dbv.pszVal);
+ db_free(&dbv);
+ db_unset(hContact, SKYPE_PROTONAME, "Typing_Stream");
+ }
+
+ }
+ }
+ if (bCleanup && (protocol>=5 || bIsImoproxy)) SkypeSend ("DELETE APPLICATION libpurple_typing");
+}
diff --git a/protocols/SkypeClassic/contacts.h b/protocols/SkypeClassic/contacts.h
new file mode 100644
index 0000000000..35a400c3e9
--- /dev/null
+++ b/protocols/SkypeClassic/contacts.h
@@ -0,0 +1,11 @@
+// Prototypes
+HANDLE add_contextmenu(HANDLE hContact);
+HANDLE find_contact(char *name);
+HANDLE find_contactT(TCHAR *name);
+HANDLE add_contact(char *name, DWORD flags);
+HANDLE add_mainmenu(void);
+CLISTMENUITEM HupItem(void);
+CLISTMENUITEM CallItem(void);
+void logoff_contacts(BOOL bCleanup);
+int PrebuildContactMenu(WPARAM, LPARAM);
+//int ClistDblClick(WPARAM, LPARAM); \ No newline at end of file
diff --git a/protocols/SkypeClassic/debug.cpp b/protocols/SkypeClassic/debug.cpp
new file mode 100644
index 0000000000..a5d7067e8e
--- /dev/null
+++ b/protocols/SkypeClassic/debug.cpp
@@ -0,0 +1,75 @@
+#ifndef _DEBUG
+#pragma warning (disable: 4206) // nonstandard extension used : translation unit is empty
+#else
+#include "debug.h"
+
+#define WIN32_LEAN_AND_MEAN
+//#include <windows.h>
+#include <stdio.h>
+//#include <time.h>
+#include "skype.h"
+#include <string.h>
+#include <stdlib.h>
+
+#define INITBUF 1024 /* Initial size of buffer */
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+extern char g_szProtoName[];
+
+static CRITICAL_SECTION m_WriteFileMutex;
+static FILE *m_fpLogFile = NULL;
+static char *m_szLogBuf = NULL;
+static DWORD m_iBufSize = 0;
+
+void init_debug(void) {
+ char *p;
+ char logfile[MAX_PATH];
+
+ ZeroMemory(logfile, sizeof(logfile));
+ p=logfile+GetModuleFileNameA(NULL, logfile, sizeof(logfile));
+ if (!(p=strrchr (logfile, '\\'))) p=logfile; else p++;
+ sprintf (p, "%s_log.txt", SKYPE_PROTONAME);
+ m_szLogBuf = calloc (1, (m_iBufSize = INITBUF));
+ m_fpLogFile = fopen(logfile, "a");
+ InitializeCriticalSection(&m_WriteFileMutex);
+}
+
+void end_debug (void) {
+ if (m_szLogBuf) free (m_szLogBuf);
+ if (m_fpLogFile) fclose (m_fpLogFile);
+ DeleteCriticalSection(&m_WriteFileMutex);
+}
+
+void do_log(const char *pszFormat, ...) {
+ char *ct, *pNewBuf;
+ va_list ap;
+ time_t lt;
+ int iLen;
+
+ if (!m_szLogBuf || !m_fpLogFile) return;
+ EnterCriticalSection(&m_WriteFileMutex);
+ time(&lt);
+ ct=ctime(&lt);
+ ct[strlen(ct)-1]=0;
+ do
+ {
+ va_start(ap, pszFormat);
+ iLen = _vsnprintf(m_szLogBuf, m_iBufSize, pszFormat, ap);
+ va_end(ap);
+ if (iLen == -1)
+ {
+ if (!(pNewBuf = (char*)realloc (m_szLogBuf, m_iBufSize*2)))
+ {
+ iLen = strlen (m_szLogBuf);
+ break;
+ }
+ m_szLogBuf = pNewBuf;
+ m_iBufSize*=2;
+ }
+ } while (iLen == -1);
+ fprintf (m_fpLogFile, sizeof(time_t) == sizeof(int) ? "%s (%ld) [%08X] %s\n" : "%s (%lld) [%08X] %s\n", ct, lt, GetCurrentThreadId(), m_szLogBuf);
+ fflush (m_fpLogFile);
+ LeaveCriticalSection(&m_WriteFileMutex);
+}
+#endif \ No newline at end of file
diff --git a/protocols/SkypeClassic/debug.h b/protocols/SkypeClassic/debug.h
new file mode 100644
index 0000000000..9582246251
--- /dev/null
+++ b/protocols/SkypeClassic/debug.h
@@ -0,0 +1,23 @@
+//#define DEBUG_RELEASE 1
+
+#ifdef DEBUG_RELEASE
+ #define _DEBUG 1
+#endif
+
+#ifdef _DEBUG
+ void init_debug(void);
+ void end_debug (void);
+ void do_log(const char *pszFormat, ...);
+ #define DEBUG_OUT(a) OUTPUT(a)
+ #define TRACE(a) OutputDebugString(a)
+ #define TRACEA(a) OutputDebugStringA(a)
+ #define TRACEW(a) OutputDebugStringW(a)
+ #define LOG(a) do_log a
+#else
+ #define DEBUG_OUT(a)
+ #define LOG(a)
+ #define TRACE(a)
+ #define TRACEA(a)
+ #define TRACEW(a)
+#endif
+
diff --git a/protocols/SkypeClassic/ezxml/ezxml.c b/protocols/SkypeClassic/ezxml/ezxml.c
new file mode 100644
index 0000000000..24c02fbd70
--- /dev/null
+++ b/protocols/SkypeClassic/ezxml/ezxml.c
@@ -0,0 +1,1033 @@
+/* ezxml.c
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if defined(WIN32) || defined(_WIN32)
+#include <io.h>
+#ifndef EZXML_NOMMAP
+#define EZXML_NOMMAP
+#endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#if !defined(WIN32) && !defined(_WIN32)
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#ifndef EZXML_NOMMAP
+#include <sys/mman.h>
+#endif // EZXML_NOMMAP
+#include <sys/stat.h>
+#include "ezxml.h"
+
+#if defined(WIN32) || defined(_WIN32)
+#define vsnprintf _vsnprintf
+#define snprintf _snprintf
+#define open _open
+#define read _read
+#define write _write
+#define close _close
+#endif
+
+#define EZXML_WS "\t\r\n " // whitespace
+#define EZXML_ERRL 128 // maximum error string length
+
+typedef struct ezxml_root *ezxml_root_t;
+struct ezxml_root { // additional data for the root tag
+ struct ezxml xml; // is a super-struct built on top of ezxml struct
+ ezxml_t cur; // current xml tree insertion point
+ char *m; // original xml string
+ size_t len; // length of allocated memory for mmap, -1 for malloc
+ char *u; // UTF-8 conversion of string if original was UTF-16
+ char *s; // start of work area
+ char *e; // end of work area
+ char **ent; // general entities (ampersand sequences)
+ char ***attr; // default attributes
+ char ***pi; // processing instructions
+ short standalone; // non-zero if <?xml standalone="yes"?>
+ char err[EZXML_ERRL]; // error string
+};
+
+char *EZXML_NIL[] = { NULL }; // empty, null terminated array of strings
+
+// returns the first child tag with the given name or NULL if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name)
+{
+ xml = (xml) ? xml->child : NULL;
+ while (xml && strcmp(name, xml->name)) xml = xml->sibling;
+ return xml;
+}
+
+// returns the Nth tag with the same name in the same subsection or NULL if not
+// found
+ezxml_t ezxml_idx(ezxml_t xml, int idx)
+{
+ for (; xml && idx; idx--) xml = xml->next;
+ return xml;
+}
+
+// returns the value of the requested tag attribute or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr)
+{
+ int i = 0, j = 1;
+ ezxml_root_t root = (ezxml_root_t)xml;
+
+ if (! xml || ! xml->attr) return NULL;
+ while (xml->attr[i] && strcmp(attr, xml->attr[i])) i += 2;
+ if (xml->attr[i]) return xml->attr[i + 1]; // found attribute
+
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+ for (i = 0; root->attr[i] && strcmp(xml->name, root->attr[i][0]); i++);
+ if (! root->attr[i]) return NULL; // no matching default attributes
+ while (root->attr[i][j] && strcmp(attr, root->attr[i][j])) j += 3;
+ return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; // found default
+}
+
+// same as ezxml_get but takes an already initialized va_list
+ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
+{
+ char *name = va_arg(ap, char *);
+ int idx = -1;
+
+ if (name && *name) {
+ idx = va_arg(ap, int);
+ xml = ezxml_child(xml, name);
+ }
+ return (idx < 0) ? xml : ezxml_vget(ezxml_idx(xml, idx), ap);
+}
+
+// Traverses the xml tree to retrieve a specific subtag. Takes a variable
+// length list of tag names and indexes. The argument list must be terminated
+// by either an index of -1 or an empty string tag name. Example:
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...)
+{
+ va_list ap;
+ ezxml_t r;
+
+ va_start(ap, xml);
+ r = ezxml_vget(xml, ap);
+ va_end(ap);
+ return r;
+}
+
+// returns a null terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target)
+{
+ ezxml_root_t root = (ezxml_root_t)xml;
+ int i = 0;
+
+ if (! root) return (const char **)EZXML_NIL;
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+ while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+ return (const char **)((root->pi[i]) ? root->pi[i] + 1 : EZXML_NIL);
+}
+
+// set an error string and return root
+ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err, ...)
+{
+ va_list ap;
+ int line = 1;
+ char *t, fmt[EZXML_ERRL];
+
+ for (t = root->s; t < s; t++) if (*t == '\n') line++;
+ snprintf(fmt, EZXML_ERRL, "[error near line %d]: %s", line, err);
+
+ va_start(ap, err);
+ vsnprintf(root->err, EZXML_ERRL, fmt, ap);
+ va_end(ap);
+
+ return &root->xml;
+}
+
+// Recursively decodes entity and character references and normalizes new lines
+// ent is a null terminated array of alternating entity names and values. set t
+// to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
+// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
+// attribute normalization. Returns s, or if the decoded string is longer than
+// s, returns a malloced string that must be freed.
+char *ezxml_decode(char *s, char **ent, char t)
+{
+ char *e, *r = s, *m = s;
+ long b, c, d, l;
+
+ for (; *s; s++) { // normalize line endings
+ while (*s == '\r') {
+ *(s++) = '\n';
+ if (*s == '\n') memmove(s, (s + 1), strlen(s));
+ }
+ }
+
+ for (s = r; ; ) {
+ while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace(*s)) s++;
+
+ if (! *s) break;
+ else if (t != 'c' && ! strncmp(s, "&#", 2)) { // character reference
+ if (s[2] == 'x') c = strtol(s + 3, &e, 16); // base 16
+ else c = strtol(s + 2, &e, 10); // base 10
+ if (! c || *e != ';') { s++; continue; } // not a character ref
+
+ if (c < 0x80) *(s++) = c; // US-ASCII subset
+ else { // multi-byte UTF-8 sequence
+ for (b = 0, d = c; d; d /= 2) b++; // number of bits in c
+ b = (b - 2) / 5; // number of bytes in payload
+ *(s++) = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+ while (b) *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+ }
+
+ memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
+ }
+ else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) ||
+ (*s == '%' && t == '%')) { // entity reference
+ for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b]));
+ b += 2); // find entity in entity list
+
+ if (ent[b++]) { // found a match
+ if ((c = strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
+ l = (d = (s - r)) + c + strlen(e); // new length
+ r = (r == m) ? strcpy(malloc(l), r) : realloc(r, l);
+ e = strchr((s = r + d), ';'); // fix up pointers
+ }
+
+ memmove(s + c, e + 1, strlen(e)); // shift rest of string
+ strncpy(s, ent[b], c); // copy in replacement text
+ }
+ else s++; // not a known entity
+ }
+ else if ((t == ' ' || t == '*') && isspace(*s)) *(s++) = ' ';
+ else s++; // no decoding needed
+ }
+
+ if (t == '*') { // normalize spaces for non-cdata attributes
+ for (s = r; *s; s++) {
+ if ((l = strspn(s, " "))) memmove(s, s + l, strlen(s + l) + 1);
+ while (*s && *s != ' ') s++;
+ }
+ if (--s >= r && *s == ' ') *s = '\0'; // trim any trailing space
+ }
+ return r;
+}
+
+// called when parser finds start of new tag
+void ezxml_open_tag(ezxml_root_t root, char *name, char **attr)
+{
+ ezxml_t xml = root->cur;
+
+ if (xml->name) xml = ezxml_add_child(xml, name, strlen(xml->txt));
+ else xml->name = name; // first open tag
+
+ xml->attr = attr;
+ root->cur = xml; // update tag insertion point
+}
+
+// called when parser finds character content between open and closing tag
+void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
+{
+ ezxml_t xml = root->cur;
+ char *m = s;
+ size_t l;
+
+ if (! xml || ! xml->name || ! len) return; // sanity check
+
+ s[len] = '\0'; // null terminate text (calling functions anticipate this)
+ len = strlen(s = ezxml_decode(s, root->ent, t)) + 1;
+
+ if (! *(xml->txt)) xml->txt = s; // initial character content
+ else { // allocate our own memory and make a copy
+ xml->txt = (xml->flags & EZXML_TXTM) // allocate some space
+ ? realloc(xml->txt, (l = strlen(xml->txt)) + len)
+ : strcpy(malloc((l = strlen(xml->txt)) + len), xml->txt);
+ strcpy(xml->txt + l, s); // add new char content
+ if (s != m) free(s); // free s if it was malloced by ezxml_decode()
+ }
+
+ if (xml->txt != m) ezxml_set_flag(xml, EZXML_TXTM);
+}
+
+// called when parser finds closing tag
+ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
+{
+ if (! root->cur || ! root->cur->name || strcmp(name, root->cur->name))
+ return ezxml_err(root, s, "unexpected closing tag </%s>", name);
+
+ root->cur = root->cur->parent;
+ return NULL;
+}
+
+// checks for circular entity references, returns non-zero if no circular
+// references are found, zero otherwise
+int ezxml_ent_ok(char *name, char *s, char **ent)
+{
+ int i;
+
+ for (; ; s++) {
+ while (*s && *s != '&') s++; // find next entity reference
+ if (! *s) return 1;
+ if (! strncmp(s + 1, name, strlen(name))) return 0; // circular ref.
+ for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
+ if (ent[i] && ! ezxml_ent_ok(name, ent[i + 1], ent)) return 0;
+ }
+}
+
+// called when the parser finds a processing instruction
+void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
+{
+ int i = 0, j = 1;
+ char *target = s;
+
+ s[len] = '\0'; // null terminate instruction
+ if (*(s += strcspn(s, EZXML_WS))) {
+ *s = '\0'; // null terminate target
+ s += strspn(s + 1, EZXML_WS) + 1; // skip whitespace after target
+ }
+
+ if (! strcmp(target, "xml")) { // <?xml ... ?>
+ if ((s = strstr(s, "standalone")) && ! strncmp(s + strspn(s + 10,
+ EZXML_WS "='\"") + 10, "yes", 3)) root->standalone = 1;
+ return;
+ }
+
+ if (! root->pi[0]) *(root->pi = malloc(sizeof(char **))) = NULL; //first pi
+
+ while (root->pi[i] && strcmp(target, root->pi[i][0])) i++; // find target
+ if (! root->pi[i]) { // new target
+ root->pi = realloc(root->pi, sizeof(char **) * (i + 2));
+ root->pi[i] = malloc(sizeof(char *) * 3);
+ root->pi[i][0] = target;
+ root->pi[i][1] = (char *)(root->pi[i + 1] = NULL); // terminate pi list
+ root->pi[i][2] = strdup(""); // empty document position list
+ }
+
+ while (root->pi[i][j]) j++; // find end of instruction list for this target
+ root->pi[i] = realloc(root->pi[i], sizeof(char *) * (j + 3));
+ root->pi[i][j + 2] = realloc(root->pi[i][j + 1], j + 1);
+ strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
+ root->pi[i][j + 1] = NULL; // null terminate pi list for this target
+ root->pi[i][j] = s; // set instruction
+}
+
+// called when the parser finds an internal doctype subset
+short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
+{
+ char q, *c, *t, *n = NULL, *v, **ent, **pe;
+ int i, j;
+
+ pe = memcpy(malloc(sizeof(EZXML_NIL)), EZXML_NIL, sizeof(EZXML_NIL));
+
+ for (s[len] = '\0'; s; ) {
+ while (*s && *s != '<' && *s != '%') s++; // find next declaration
+
+ if (! *s) break;
+ else if (! strncmp(s, "<!ENTITY", 8)) { // parse entity definitions
+ c = s += strspn(s + 8, EZXML_WS) + 8; // skip white space separator
+ n = s + strspn(s, EZXML_WS "%"); // find name
+ *(s = n + strcspn(n, EZXML_WS)) = ';'; // append ; to name
+
+ v = s + strspn(s + 1, EZXML_WS) + 1; // find value
+ if ((q = *(v++)) != '"' && q != '\'') { // skip externals
+ s = strchr(s, '>');
+ continue;
+ }
+
+ for (i = 0, ent = (*c == '%') ? pe : root->ent; ent[i]; i++);
+ ent = realloc(ent, (i + 3) * sizeof(char *)); // space for next ent
+ if (*c == '%') pe = ent;
+ else root->ent = ent;
+
+ *(++s) = '\0'; // null terminate name
+ if ((s = strchr(v, q))) *(s++) = '\0'; // null terminate value
+ ent[i + 1] = ezxml_decode(v, pe, '%'); // set value
+ ent[i + 2] = NULL; // null terminate entity list
+ if (! ezxml_ent_ok(n, ent[i + 1], ent)) { // circular reference
+ if (ent[i + 1] != v) free(ent[i + 1]);
+ ezxml_err(root, v, "circular entity declaration &%s", n);
+ break;
+ }
+ else ent[i] = n; // set entity name
+ }
+ else if (! strncmp(s, "<!ATTLIST", 9)) { // parse default attributes
+ t = s + strspn(s + 9, EZXML_WS) + 9; // skip whitespace separator
+ if (! *t) { ezxml_err(root, t, "unclosed <!ATTLIST"); break; }
+ if (*(s = t + strcspn(t, EZXML_WS ">")) == '>') continue;
+ else *s = '\0'; // null terminate tag name
+ for (i = 0; root->attr[i] && strcmp(n, root->attr[i][0]); i++);
+
+ while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
+ if (*(s = n + strcspn(n, EZXML_WS))) *s = '\0'; // attr name
+ else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ s += strspn(s + 1, EZXML_WS) + 1; // find next token
+ c = (strncmp(s, "CDATA", 5)) ? "*" : " "; // is it cdata?
+ if (! strncmp(s, "NOTATION", 8))
+ s += strspn(s + 8, EZXML_WS) + 8;
+ s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, EZXML_WS);
+ if (! s) { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ s += strspn(s, EZXML_WS ")"); // skip white space separator
+ if (! strncmp(s, "#FIXED", 6))
+ s += strspn(s + 6, EZXML_WS) + 6;
+ if (*s == '#') { // no default value
+ s += strcspn(s, EZXML_WS ">") - 1;
+ if (*c == ' ') continue; // cdata is default, nothing to do
+ v = NULL;
+ }
+ else if ((*s == '"' || *s == '\'') && // default value
+ (s = strchr(v = s + 1, *s))) *s = '\0';
+ else { ezxml_err(root, t, "malformed <!ATTLIST"); break; }
+
+ if (! root->attr[i]) { // new tag name
+ root->attr = (! i) ? malloc(2 * sizeof(char **))
+ : realloc(root->attr,
+ (i + 2) * sizeof(char **));
+ root->attr[i] = malloc(2 * sizeof(char *));
+ root->attr[i][0] = t; // set tag name
+ root->attr[i][1] = (char *)(root->attr[i + 1] = NULL);
+ }
+
+ for (j = 1; root->attr[i][j]; j += 3); // find end of list
+ root->attr[i] = realloc(root->attr[i],
+ (j + 4) * sizeof(char *));
+
+ root->attr[i][j + 3] = NULL; // null terminate list
+ root->attr[i][j + 2] = c; // is it cdata?
+ root->attr[i][j + 1] = (v) ? ezxml_decode(v, root->ent, *c)
+ : NULL;
+ root->attr[i][j] = n; // attribute name
+ }
+ }
+ else if (! strncmp(s, "<!--", 4)) s = strstr(s + 4, "-->"); // comments
+ else if (! strncmp(s, "<?", 2)) { // processing instructions
+ if ((s = strstr(c = s + 2, "?>")))
+ ezxml_proc_inst(root, c, s++ - c);
+ }
+ else if (*s == '<') s = strchr(s, '>'); // skip other declarations
+ else if (*(s++) == '%' && ! root->standalone) break;
+ }
+
+ free(pe);
+ return ! *root->err;
+}
+
+// Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
+// or NULL if no conversion was needed.
+char *ezxml_str2utf8(char **s, size_t *len)
+{
+ char *u;
+ size_t l = 0, sl, max = *len;
+ long c, d;
+ int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
+
+ if (be == -1) return NULL; // not UTF-16
+
+ u = malloc(max);
+ for (sl = 2; sl < *len - 1; sl += 2) {
+ c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) //UTF-16BE
+ : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); //UTF-16LE
+ if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { // high-half
+ d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
+ : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
+ c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
+ }
+
+ while (l + 6 > max) u = realloc(u, max += EZXML_BUFSIZE);
+ if (c < 0x80) u[l++] = c; // US-ASCII subset
+ else { // multi-byte UTF-8 sequence
+ for (b = 0, d = c; d; d /= 2) b++; // bits in c
+ b = (b - 2) / 5; // bytes in payload
+ u[l++] = (0xFF << (7 - b)) | (c >> (6 * b)); // head
+ while (b) u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F); // payload
+ }
+ }
+ return *s = realloc(u, *len = l);
+}
+
+// frees a tag attribute list
+void ezxml_free_attr(char **attr) {
+ int i = 0;
+ char *m;
+
+ if (! attr || attr == EZXML_NIL) return; // nothing to free
+ while (attr[i]) i += 2; // find end of attribute list
+ m = attr[i + 1]; // list of which names and values are malloced
+ for (i = 0; m[i]; i++) {
+ if (m[i] & EZXML_NAMEM) free(attr[i * 2]);
+ if (m[i] & EZXML_TXTM) free(attr[(i * 2) + 1]);
+ }
+ free(m);
+ free(attr);
+}
+
+// parse the given xml string and return an ezxml structure
+ezxml_t ezxml_parse_str(char *s, size_t len)
+{
+ ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
+ char q, e, *d, **attr, **a = NULL; // initialize a to avoid compile warning
+ int l, i, j;
+
+ root->m = s;
+ if (! len) return ezxml_err(root, NULL, "root tag missing");
+ root->u = ezxml_str2utf8(&s, &len); // convert utf-16 to utf-8
+ root->e = (root->s = s) + len; // record start and end of work area
+
+ e = s[len - 1]; // save end char
+ s[len - 1] = '\0'; // turn end char into null terminator
+
+ while (*s && *s != '<') s++; // find first tag
+ if (! *s) return ezxml_err(root, s, "root tag missing");
+
+ for (; ; ) {
+ attr = (char **)EZXML_NIL;
+ d = ++s;
+
+ if (isalpha(*s) || *s == '_' || *s == ':' || *s < '\0') { // new tag
+ if (! root->cur)
+ return ezxml_err(root, d, "markup outside of root element");
+
+ s += strcspn(s, EZXML_WS "/>");
+ while (isspace(*s)) *(s++) = '\0'; // null terminate tag name
+
+ if (*s && *s != '/' && *s != '>') // find tag in default attr list
+ for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
+
+ for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { // new attrib
+ attr = (l) ? realloc(attr, (l + 4) * sizeof(char *))
+ : malloc(4 * sizeof(char *)); // allocate space
+ attr[l + 3] = (l) ? realloc(attr[l + 1], (l / 2) + 2)
+ : malloc(2); // mem for list of maloced vals
+ strcpy(attr[l + 3] + (l / 2), " "); // value is not malloced
+ attr[l + 2] = NULL; // null terminate list
+ attr[l + 1] = ""; // temporary attribute value
+ attr[l] = s; // set attribute name
+
+ s += strcspn(s, EZXML_WS "=/>");
+ if (*s == '=' || isspace(*s)) {
+ *(s++) = '\0'; // null terminate tag attribute name
+ q = *(s += strspn(s, EZXML_WS "="));
+ if (q == '"' || q == '\'') { // attribute value
+ attr[l + 1] = ++s;
+ while (*s && *s != q) s++;
+ if (*s) *(s++) = '\0'; // null terminate attribute val
+ else {
+ ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing %c", q);
+ }
+
+ for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j +=3);
+ attr[l + 1] = ezxml_decode(attr[l + 1], root->ent, (a
+ && a[j]) ? *a[j + 2] : ' ');
+ if (attr[l + 1] < d || attr[l + 1] > s)
+ attr[l + 3][l / 2] = EZXML_TXTM; // value malloced
+ }
+ }
+ while (isspace(*s)) s++;
+ }
+
+ if (*s == '/') { // self closing tag
+ *(s++) = '\0';
+ if ((*s && *s != '>') || (! *s && e != '>')) {
+ if (l) ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing >");
+ }
+ ezxml_open_tag(root, d, attr);
+ ezxml_close_tag(root, d, s);
+ }
+ else if ((q = *s) == '>' || (! *s && e == '>')) { // open tag
+ *s = '\0'; // temporarily null terminate tag name
+ ezxml_open_tag(root, d, attr);
+ *s = q;
+ }
+ else {
+ if (l) ezxml_free_attr(attr);
+ return ezxml_err(root, d, "missing >");
+ }
+ }
+ else if (*s == '/') { // close tag
+ s += strcspn(d = s + 1, EZXML_WS ">") + 1;
+ if (! (q = *s) && e != '>') return ezxml_err(root, d, "missing >");
+ *s = '\0'; // temporarily null terminate tag name
+ if (ezxml_close_tag(root, d, s)) return &root->xml;
+ if (isspace(*s = q)) s += strspn(s, EZXML_WS);
+ }
+ else if (! strncmp(s, "!--", 3)) { // xml comment
+ if (! (s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) ||
+ (! *s && e != '>')) return ezxml_err(root, d, "unclosed <!--");
+ }
+ else if (! strncmp(s, "![CDATA[", 8)) { // cdata
+ if ((s = strstr(s, "]]>")))
+ ezxml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
+ else return ezxml_err(root, d, "unclosed <![CDATA[");
+ }
+ else if (! strncmp(s, "!DOCTYPE", 8)) { // dtd
+ for (l = 0; *s && ((! l && *s != '>') || (l && (*s != ']' ||
+ *(s + strspn(s + 1, EZXML_WS) + 1) != '>')));
+ l = (*s == '[') ? 1 : l) s += strcspn(s + 1, "[]>") + 1;
+ if (! *s && e != '>')
+ return ezxml_err(root, d, "unclosed <!DOCTYPE");
+ d = (l) ? strchr(d, '[') + 1 : d;
+ if (l && ! ezxml_internal_dtd(root, d, s++ - d)) return &root->xml;
+ }
+ else if (*s == '?') { // <?...?> processing instructions
+ do { s = strchr(s, '?'); } while (s && *(++s) && *s != '>');
+ if (! s || (! *s && e != '>'))
+ return ezxml_err(root, d, "unclosed <?");
+ else ezxml_proc_inst(root, d + 1, s - d - 2);
+ }
+ else return ezxml_err(root, d, "unexpected <");
+
+ if (! s || ! *s) break;
+ *s = '\0';
+ d = ++s;
+ if (*s && *s != '<') { // tag character content
+ while (*s && *s != '<') s++;
+ if (*s) ezxml_char_content(root, d, s - d, '&');
+ else break;
+ }
+ else if (! *s) break;
+ }
+
+ if (! root->cur) return &root->xml;
+ else if (! root->cur->name) return ezxml_err(root, d, "root tag missing");
+ else return ezxml_err(root, d, "unclosed tag <%s>", root->cur->name);
+}
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp)
+{
+ ezxml_root_t root;
+ size_t l, len = 0;
+ char *s;
+
+ if (! (s = malloc(EZXML_BUFSIZE))) return NULL;
+ do {
+ len += (l = fread((s + len), 1, EZXML_BUFSIZE, fp));
+ if (l == EZXML_BUFSIZE) s = realloc(s, len + EZXML_BUFSIZE);
+ } while (s && l == EZXML_BUFSIZE);
+
+ if (! s) return NULL;
+ root = (ezxml_root_t)ezxml_parse_str(s, len);
+ root->len = -1; // so we know to free s in ezxml_free()
+ return &root->xml;
+}
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd)
+{
+ ezxml_root_t root;
+ struct stat st;
+ size_t l;
+ void *m;
+
+ if (fd < 0) return NULL;
+ fstat(fd, &st);
+
+#ifndef EZXML_NOMMAP
+ l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) -1);
+ if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) !=
+ MAP_FAILED) {
+ madvise(m, l, MADV_SEQUENTIAL); // optimize for sequential access
+ root = (ezxml_root_t)ezxml_parse_str(m, st.st_size);
+ madvise(m, root->len = l, MADV_NORMAL); // put it back to normal
+ }
+ else { // mmap failed, read file into memory
+#endif // EZXML_NOMMAP
+ l = read(fd, m = malloc(st.st_size), st.st_size);
+ root = (ezxml_root_t)ezxml_parse_str(m, l);
+ root->len = -1; // so we know to free s in ezxml_free()
+#ifndef EZXML_NOMMAP
+ }
+#endif // EZXML_NOMMAP
+ return &root->xml;
+}
+
+// a wrapper for ezxml_parse_fd that accepts a file name
+ezxml_t ezxml_parse_file(const char *file)
+{
+ int fd = open(file, O_RDONLY, 0);
+ ezxml_t xml = ezxml_parse_fd(fd);
+
+ if (fd >= 0) close(fd);
+ return xml;
+}
+
+// Encodes ampersand sequences appending the results to *dst, reallocating *dst
+// if length excedes max. a is non-zero for attribute encoding. Returns *dst
+char *ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen,
+ size_t *max, short a)
+{
+ const char *e;
+
+ for (e = s + len; s != e; s++) {
+ while (*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE);
+
+ switch (*s) {
+ case '\0': return *dst;
+ case '&': *dlen += sprintf(*dst + *dlen, "&amp;"); break;
+ case '<': *dlen += sprintf(*dst + *dlen, "&lt;"); break;
+ case '>': *dlen += sprintf(*dst + *dlen, "&gt;"); break;
+ case '"': *dlen += sprintf(*dst + *dlen, (a) ? "&quot;" : "\""); break;
+ case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "&#xA;" : "\n"); break;
+ case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "&#x9;" : "\t"); break;
+ case '\r': *dlen += sprintf(*dst + *dlen, "&#xD;"); break;
+ default: (*dst)[(*dlen)++] = *s;
+ }
+ }
+ return *dst;
+}
+
+// Recursively converts each tag to xml appending it to *s. Reallocates *s if
+// its length excedes max. start is the location of the previous tag in the
+// parent tag's character content. Returns *s.
+char *ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max,
+ size_t start, char ***attr)
+{
+ int i, j;
+ char *txt = (xml->parent) ? xml->parent->txt : "";
+ size_t off = 0;
+
+ // parent character content up to this tag
+ *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0);
+
+ while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, "<%s", xml->name); // open tag
+ for (i = 0; xml->attr[i]; i += 2) { // tag attributes
+ if (ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue;
+ while (*len + strlen(xml->attr[i]) + 7 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
+ ezxml_ampencode(xml->attr[i + 1], -1, s, len, max, 1);
+ *len += sprintf(*s + *len, "\"");
+ }
+
+ for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
+ for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
+ if (! attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
+ continue; // skip duplicates and non-values
+ while (*len + strlen(attr[i][j]) + 7 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
+ ezxml_ampencode(attr[i][j + 1], -1, s, len, max, 1);
+ *len += sprintf(*s + *len, "\"");
+ }
+ *len += sprintf(*s + *len, ">");
+
+ *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) //child
+ : ezxml_ampencode(xml->txt, -1, s, len, max, 0); //data
+
+ while (*len + strlen(xml->name) + 4 > *max) // reallocate s
+ *s = realloc(*s, *max += EZXML_BUFSIZE);
+
+ *len += sprintf(*s + *len, "</%s>", xml->name); // close tag
+
+ while (txt[off] && off < xml->off) off++; // make sure off is within bounds
+ return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr)
+ : ezxml_ampencode(txt + off, -1, s, len, max, 0);
+}
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml)
+{
+ ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL;
+ ezxml_root_t root = (ezxml_root_t)xml;
+ size_t len = 0, max = EZXML_BUFSIZE;
+ char *s = strcpy(malloc(max), ""), *t, *n;
+ int i, j, k;
+
+ if (! xml || ! xml->name) return realloc(s, len + 1);
+ while (root->xml.parent) root = (ezxml_root_t)root->xml.parent; // root tag
+
+ for (i = 0; ! p && root->pi[i]; i++) { // pre-root processing instructions
+ for (k = 2; root->pi[i][k - 1]; k++);
+ for (j = 1; (n = root->pi[i][j]); j++) {
+ if (root->pi[i][k][j - 1] == '>') continue; // not pre-root
+ while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+ s = realloc(s, max += EZXML_BUFSIZE);
+ len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n);
+ }
+ }
+
+ xml->parent = xml->ordered = NULL;
+ s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr);
+ xml->parent = p;
+ xml->ordered = o;
+
+ for (i = 0; ! p && root->pi[i]; i++) { // post-root processing instructions
+ for (k = 2; root->pi[i][k - 1]; k++);
+ for (j = 1; (n = root->pi[i][j]); j++) {
+ if (root->pi[i][k][j - 1] == '<') continue; // not post-root
+ while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max)
+ s = realloc(s, max += EZXML_BUFSIZE);
+ len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n);
+ }
+ }
+ return realloc(s, len + 1);
+}
+
+// free the memory allocated for the ezxml structure
+void ezxml_free(ezxml_t xml)
+{
+ ezxml_root_t root = (ezxml_root_t)xml;
+ int i, j;
+ char **a, *s;
+
+ if (! xml) return;
+ ezxml_free(xml->child);
+ ezxml_free(xml->ordered);
+
+ if (! xml->parent) { // free root tag allocations
+ for (i = 10; root->ent[i]; i += 2) // 0 - 9 are default entites (<>&"')
+ if ((s = root->ent[i + 1]) < root->s || s > root->e) free(s);
+ free(root->ent); // free list of general entities
+
+ for (i = 0; (a = root->attr[i]); i++) {
+ for (j = 1; a[j++]; j += 2) // free malloced attribute values
+ if (a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]);
+ free(a);
+ }
+ if (root->attr[0]) free(root->attr); // free default attribute list
+
+ for (i = 0; root->pi[i]; i++) {
+ for (j = 1; root->pi[i][j]; j++);
+ free(root->pi[i][j + 1]);
+ free(root->pi[i]);
+ }
+ if (root->pi[0]) free(root->pi); // free processing instructions
+
+ if (root->len == -1) free(root->m); // malloced xml data
+#ifndef EZXML_NOMMAP
+ else if (root->len) munmap(root->m, root->len); // mem mapped xml data
+#endif // EZXML_NOMMAP
+ if (root->u) free(root->u); // utf8 conversion
+ }
+
+ ezxml_free_attr(xml->attr); // tag attributes
+ if ((xml->flags & EZXML_TXTM)) free(xml->txt); // character content
+ if ((xml->flags & EZXML_NAMEM)) free(xml->name); // tag name
+ free(xml);
+}
+
+// return parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml)
+{
+ while (xml && xml->parent) xml = xml->parent; // find root tag
+ return (xml) ? ((ezxml_root_t)xml)->err : "";
+}
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name)
+{
+ static char *ent[] = { "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
+ "apos;", "&#39;", "amp;", "&#38;", NULL };
+ ezxml_root_t root = (ezxml_root_t)memset(malloc(sizeof(struct ezxml_root)),
+ '\0', sizeof(struct ezxml_root));
+ root->xml.name = (char *)name;
+ root->cur = &root->xml;
+ strcpy(root->err, root->xml.txt = "");
+ root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent));
+ root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL);
+ return &root->xml;
+}
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
+{
+ ezxml_t cur, prev, head;
+
+ xml->next = xml->sibling = xml->ordered = NULL;
+ xml->off = off;
+ xml->parent = dest;
+
+ if ((head = dest->child)) { // already have sub tags
+ if (head->off <= off) { // not first subtag
+ for (cur = head; cur->ordered && cur->ordered->off <= off;
+ cur = cur->ordered);
+ xml->ordered = cur->ordered;
+ cur->ordered = xml;
+ }
+ else { // first subtag
+ xml->ordered = head;
+ dest->child = xml;
+ }
+
+ for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name);
+ prev = cur, cur = cur->sibling); // find tag type
+ if (cur && cur->off <= off) { // not first of type
+ while (cur->next && cur->next->off <= off) cur = cur->next;
+ xml->next = cur->next;
+ cur->next = xml;
+ }
+ else { // first tag of this type
+ if (prev && cur) prev->sibling = cur->sibling; // remove old first
+ xml->next = cur; // old first tag is now next
+ for (cur = head, prev = NULL; cur && cur->off <= off;
+ prev = cur, cur = cur->sibling); // new sibling insert point
+ xml->sibling = cur;
+ if (prev) prev->sibling = xml;
+ }
+ }
+ else dest->child = xml; // only sub tag
+
+ return xml;
+}
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off)
+{
+ ezxml_t child;
+
+ if (! xml) return NULL;
+ child = (ezxml_t)memset(malloc(sizeof(struct ezxml)), '\0',
+ sizeof(struct ezxml));
+ child->name = (char *)name;
+ child->attr = EZXML_NIL;
+ child->txt = "";
+
+ return ezxml_insert(child, xml, off);
+}
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt)
+{
+ if (! xml) return NULL;
+ if (xml->flags & EZXML_TXTM) free(xml->txt); // existing txt was malloced
+ xml->flags &= ~EZXML_TXTM;
+ xml->txt = (char *)txt;
+ return xml;
+}
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value)
+{
+ int l = 0, c;
+
+ if (! xml) return NULL;
+ while (xml->attr[l] && strcmp(xml->attr[l], name)) l += 2;
+ if (! xml->attr[l]) { // not found, add as new attribute
+ if (! value) return xml; // nothing to do
+ if (xml->attr == EZXML_NIL) { // first attribute
+ xml->attr = malloc(4 * sizeof(char *));
+ xml->attr[1] = strdup(""); // empty list of malloced names/vals
+ }
+ else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *));
+
+ xml->attr[l] = (char *)name; // set attribute name
+ xml->attr[l + 2] = NULL; // null terminate attribute list
+ xml->attr[l + 3] = realloc(xml->attr[l + 1],
+ (c = strlen(xml->attr[l + 1])) + 2);
+ strcpy(xml->attr[l + 3] + c, " "); // set name/value as not malloced
+ if (xml->flags & EZXML_DUP) xml->attr[l + 3][c] = EZXML_NAMEM;
+ }
+ else if (xml->flags & EZXML_DUP) free((char *)name); // name was strduped
+
+ for (c = l; xml->attr[c]; c += 2); // find end of attribute list
+ if (xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); //old val
+ if (xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM;
+ else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM;
+
+ if (value) xml->attr[l + 1] = (char *)value; // set attribute value
+ else { // remove attribute
+ if (xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]);
+ memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
+ xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *));
+ memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1,
+ (c / 2) - (l / 2)); // fix list of which name/vals are malloced
+ }
+ xml->flags &= ~EZXML_DUP; // clear strdup() flag
+ return xml;
+}
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
+{
+ if (xml) xml->flags |= flag;
+ return xml;
+}
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml)
+{
+ ezxml_t cur;
+
+ if (! xml) return NULL; // nothing to do
+ if (xml->next) xml->next->sibling = xml->sibling; // patch sibling list
+
+ if (xml->parent) { // not root tag
+ cur = xml->parent->child; // find head of subtag list
+ if (cur == xml) xml->parent->child = xml->ordered; // first subtag
+ else { // not first subtag
+ while (cur->ordered != xml) cur = cur->ordered;
+ cur->ordered = cur->ordered->ordered; // patch ordered list
+
+ cur = xml->parent->child; // go back to head of subtag list
+ if (strcmp(cur->name, xml->name)) { // not in first sibling list
+ while (strcmp(cur->sibling->name, xml->name))
+ cur = cur->sibling;
+ if (cur->sibling == xml) { // first of a sibling list
+ cur->sibling = (xml->next) ? xml->next
+ : cur->sibling->sibling;
+ }
+ else cur = cur->sibling; // not first of a sibling list
+ }
+
+ while (cur->next && cur->next != xml) cur = cur->next;
+ if (cur->next) cur->next = cur->next->next; // patch next list
+ }
+ }
+ xml->ordered = xml->sibling = xml->next = NULL;
+ return xml;
+}
+
+#ifdef EZXML_TEST // test harness
+int main(int argc, char **argv)
+{
+ ezxml_t xml;
+ char *s;
+ int i;
+
+ if (argc != 2) return fprintf(stderr, "usage: %s xmlfile\n", argv[0]);
+
+ xml = ezxml_parse_file(argv[1]);
+ printf("%s\n", (s = ezxml_toxml(xml)));
+ free(s);
+ i = fprintf(stderr, "%s", ezxml_error(xml));
+ ezxml_free(xml);
+ return (i) ? 1 : 0;
+}
+#endif // EZXML_TEST
diff --git a/protocols/SkypeClassic/ezxml/ezxml.h b/protocols/SkypeClassic/ezxml/ezxml.h
new file mode 100644
index 0000000000..3e020788b4
--- /dev/null
+++ b/protocols/SkypeClassic/ezxml/ezxml.h
@@ -0,0 +1,167 @@
+/* ezxml.h
+ *
+ * Copyright 2004-2006 Aaron Voisine <aaron@voisine.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EZXML_H
+#define _EZXML_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EZXML_BUFSIZE 1024 // size of internal memory buffers
+#define EZXML_NAMEM 0x80 // name is malloced
+#define EZXML_TXTM 0x40 // txt is malloced
+#define EZXML_DUP 0x20 // attribute name and value are strduped
+
+typedef struct ezxml *ezxml_t;
+struct ezxml {
+ char *name; // tag name
+ char **attr; // tag attributes { name, value, name, value, ... NULL }
+ char *txt; // tag character content, empty string if none
+ size_t off; // tag offset from start of parent tag character content
+ ezxml_t next; // next tag with same name in this section at this depth
+ ezxml_t sibling; // next tag with different name in same section and depth
+ ezxml_t ordered; // next tag, same section and depth, in original order
+ ezxml_t child; // head of sub tag list, NULL if none
+ ezxml_t parent; // parent tag, NULL if current tag is root tag
+ short flags; // additional information
+};
+
+// Given a string of xml data and its length, parses it and creates an ezxml
+// structure. For efficiency, modifies the data by adding null terminators
+// and decoding ampersand sequences. If you don't want this, copy the data and
+// pass in the copy. Returns NULL on failure.
+ezxml_t ezxml_parse_str(char *s, size_t len);
+
+// A wrapper for ezxml_parse_str() that accepts a file descriptor. First
+// attempts to mem map the file. Failing that, reads the file into memory.
+// Returns NULL on failure.
+ezxml_t ezxml_parse_fd(int fd);
+
+// a wrapper for ezxml_parse_fd() that accepts a file name
+ezxml_t ezxml_parse_file(const char *file);
+
+// Wrapper for ezxml_parse_str() that accepts a file stream. Reads the entire
+// stream into memory and then parses it. For xml files, use ezxml_parse_file()
+// or ezxml_parse_fd()
+ezxml_t ezxml_parse_fp(FILE *fp);
+
+// returns the first child tag (one level deeper) with the given name or NULL
+// if not found
+ezxml_t ezxml_child(ezxml_t xml, const char *name);
+
+// returns the next tag of the same name in the same section and depth or NULL
+// if not found
+#define ezxml_next(xml) ((xml) ? xml->next : NULL)
+
+// Returns the Nth tag with the same name in the same section at the same depth
+// or NULL if not found. An index of 0 returns the tag given.
+ezxml_t ezxml_idx(ezxml_t xml, int idx);
+
+// returns the name of the given tag
+#define ezxml_name(xml) ((xml) ? xml->name : NULL)
+
+// returns the given tag's character content or empty string if none
+#define ezxml_txt(xml) ((xml) ? xml->txt : "")
+
+// returns the value of the requested tag attribute, or NULL if not found
+const char *ezxml_attr(ezxml_t xml, const char *attr);
+
+// Traverses the ezxml sturcture to retrieve a specific subtag. Takes a
+// variable length list of tag names and indexes. The argument list must be
+// terminated by either an index of -1 or an empty string tag name. Example:
+// title = ezxml_get(library, "shelf", 0, "book", 2, "title", -1);
+// This retrieves the title of the 3rd book on the 1st shelf of library.
+// Returns NULL if not found.
+ezxml_t ezxml_get(ezxml_t xml, ...);
+
+// Converts an ezxml structure back to xml. Returns a string of xml data that
+// must be freed.
+char *ezxml_toxml(ezxml_t xml);
+
+// returns a NULL terminated array of processing instructions for the given
+// target
+const char **ezxml_pi(ezxml_t xml, const char *target);
+
+// frees the memory allocated for an ezxml structure
+void ezxml_free(ezxml_t xml);
+
+// returns parser error message or empty string if none
+const char *ezxml_error(ezxml_t xml);
+
+// returns a new empty ezxml structure with the given root tag name
+ezxml_t ezxml_new(const char *name);
+
+// wrapper for ezxml_new() that strdup()s name
+#define ezxml_new_d(name) ezxml_set_flag(ezxml_new(strdup(name)), EZXML_NAMEM)
+
+// Adds a child tag. off is the offset of the child tag relative to the start
+// of the parent tag's character content. Returns the child tag.
+ezxml_t ezxml_add_child(ezxml_t xml, const char *name, size_t off);
+
+// wrapper for ezxml_add_child() that strdup()s name
+#define ezxml_add_child_d(xml, name, off) \
+ ezxml_set_flag(ezxml_add_child(xml, strdup(name), off), EZXML_NAMEM)
+
+// sets the character content for the given tag and returns the tag
+ezxml_t ezxml_set_txt(ezxml_t xml, const char *txt);
+
+// wrapper for ezxml_set_txt() that strdup()s txt
+#define ezxml_set_txt_d(xml, txt) \
+ ezxml_set_flag(ezxml_set_txt(xml, strdup(txt)), EZXML_TXTM)
+
+// Sets the given tag attribute or adds a new attribute if not found. A value
+// of NULL will remove the specified attribute. Returns the tag given.
+ezxml_t ezxml_set_attr(ezxml_t xml, const char *name, const char *value);
+
+// Wrapper for ezxml_set_attr() that strdup()s name/value. Value cannot be NULL
+#define ezxml_set_attr_d(xml, name, value) \
+ ezxml_set_attr(ezxml_set_flag(xml, EZXML_DUP), strdup(name), strdup(value))
+
+// sets a flag for the given tag and returns the tag
+ezxml_t ezxml_set_flag(ezxml_t xml, short flag);
+
+// removes a tag along with its subtags without freeing its memory
+ezxml_t ezxml_cut(ezxml_t xml);
+
+// inserts an existing tag into an ezxml structure
+ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off);
+
+// Moves an existing tag to become a subtag of dest at the given offset from
+// the start of dest's character content. Returns the moved tag.
+#define ezxml_move(xml, dest, off) ezxml_insert(ezxml_cut(xml), dest, off)
+
+// removes a tag along with all its subtags
+#define ezxml_remove(xml) ezxml_free(ezxml_cut(xml))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _EZXML_H
diff --git a/protocols/SkypeClassic/gchat.cpp b/protocols/SkypeClassic/gchat.cpp
new file mode 100644
index 0000000000..6964bf8c09
--- /dev/null
+++ b/protocols/SkypeClassic/gchat.cpp
@@ -0,0 +1,910 @@
+#include "skype.h"
+#include "skypeapi.h"
+#include "gchat.h"
+#include "contacts.h"
+#include "debug.h"
+#include "utf8.h"
+#include "pthread.h"
+
+#pragma warning (push)
+#pragma warning (disable: 4100) // unreferenced formal parameter
+#include <m_langpack.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_contacts.h>
+#pragma warning (pop)
+
+#ifndef DWLP_USER
+#define DWLP_USER DWL_USER
+#endif
+
+#ifdef _UNICODE
+#define STR "%S"
+#else
+#define STR "%s"
+#endif
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+extern HANDLE hInitChat;
+extern HINSTANCE hInst;
+extern char protocol, g_szProtoName[];
+extern DWORD mirandaVersion;
+
+static gchat_contacts *chats=NULL;
+static int chatcount=0;
+static CRITICAL_SECTION m_GCMutex;
+
+// TODO: Disable groupchat for Protocol verisons <5
+
+/****************************************************************************/
+/* Chat management helper functions */
+/****************************************************************************/
+
+/* Get the gchat_contacts entry for the chat with the id szChatId
+ If the chat doesn't already exist in the list, it is added.
+
+ Parameters: szChatId - String with the chat ID of the chat to be found
+ Returns: Pointer to the gchat_contacts entry for the given id.
+ NULL on failure (not enough memory)
+*/
+gchat_contacts *GetChat(TCHAR *szChatId) {
+ int i;
+
+ for (i=0;i<chatcount;i++)
+ if (!_tcscmp(chats[i].szChatName, szChatId)) return &chats[i];
+ if (chats = (gchat_contacts *)realloc(chats, sizeof(gchat_contacts)*(++chatcount))) {
+ memset(&chats[chatcount-1], 0, sizeof(gchat_contacts));
+ chats[chatcount-1].szChatName=_tcsdup(szChatId);
+ return &chats[chatcount-1];
+ }
+ return NULL;
+}
+
+/* Removes the gchat_contacts entry for the chat with the id szChatId,
+ if it exists.
+
+ Parameters: szChatId - String with the chat ID to be removed from list
+ */
+void RemChat(TCHAR *szChatId) {
+ int i;
+
+ for (i=0;i<chatcount;i++)
+ if (!_tcscmp(chats[i].szChatName, szChatId)) {
+ if (chats[i].szChatName) free(chats[i].szChatName);
+ if (chats[i].mJoinedContacts) free(chats[i].mJoinedContacts);
+ if (i<--chatcount) memmove(&chats[i], &chats[i+1], (chatcount-i)*sizeof(gchat_contacts));
+ chats = (gchat_contacts *)realloc(chats, sizeof(gchat_contacts)*chatcount);
+ return;
+ }
+}
+
+/* Checks, if the contact with the handle hContact exists in the groupchat
+ given in gc
+
+ Parameters: gc - gchat_contacts entry for the chat session to be searched
+ who - Name of member
+ Returns: -1 = Not found
+ >=0 = Number of found item
+ */
+static int ExistsChatContact(gchat_contacts *gc, const TCHAR *who) {
+ int i;
+
+ for (i=0;i<gc->mJoinedCount;i++)
+ if (_tcscmp(gc->mJoinedContacts[i].who, who)==0) return i;
+ return -1;
+}
+
+gchat_contact *GetChatContact(gchat_contacts *gc, const TCHAR *who) {
+ int i = ExistsChatContact (gc, who);
+
+ if (i==-1) return NULL;
+ return &gc->mJoinedContacts[i];
+}
+
+/* Adds contact with the name who to the groupchat given in gc
+
+ Parameters: gc -
+ Returns: -1 = Contact not found
+ -2 = On failure
+ >=0 = Number of added item
+ */
+static int AddChatContact(gchat_contacts *gc, char *who, TCHAR *pszRole) {
+ int i = -2;
+ HANDLE hContact;
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ CONTACTINFO ci = {0};
+ TCHAR *twho;
+
+ LOG (("AddChatContact %s", who));
+ if (!(twho = make_nonutf_tchar_string((const unsigned char*)who)))
+ return -2;
+ if ((i=ExistsChatContact(gc, twho))>=0) return i;
+ hContact=find_contact(who);
+
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = gc->szChatName;
+ gcd.iType = GC_EVENT_JOIN;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.ptszStatus = pszRole?pszRole:_T("USER");
+ gce.time = (DWORD)time(NULL);
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ ci.hContact = hContact;
+
+ if (hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=twho;
+
+ gce.ptszUID=twho;
+ if (!CallService(MS_GC_EVENT, 0, (LPARAM)&gce)) {
+ if ((gc->mJoinedContacts=(gchat_contact*)realloc(gc->mJoinedContacts, (gc->mJoinedCount+1)*sizeof(gchat_contact))))
+ {
+ gc->mJoinedContacts[i=gc->mJoinedCount].hContact=hContact;
+ _tcscpy (gc->mJoinedContacts[i].szRole, gce.ptszStatus);
+ _tcscpy (gc->mJoinedContacts[i].who, twho);
+ gc->mJoinedCount++;
+ }
+ }
+ if (ci.pszVal) mir_free (ci.pszVal);
+ free_nonutf_tchar_string (twho);
+ return i;
+}
+
+void RemChatContact(gchat_contacts *gc, const TCHAR *who) {
+ int i;
+
+ if (!gc) return;
+ for (i=0;i<gc->mJoinedCount;i++)
+ if (_tcscmp(gc->mJoinedContacts[i].who, who)==0) {
+ if (i<--gc->mJoinedCount)
+ memmove(&gc->mJoinedContacts[i], &gc->mJoinedContacts[i+1], (gc->mJoinedCount-i)*sizeof(gchat_contact));
+ if (gc->mJoinedCount) gc->mJoinedContacts = (gchat_contact*)realloc(gc->mJoinedContacts, sizeof(gchat_contact)*gc->mJoinedCount);
+ else {free (gc->mJoinedContacts); gc->mJoinedContacts = NULL; }
+ return;
+ }
+}
+
+HANDLE find_chat(TCHAR *chatname) {
+ char *szProto;
+ int tCompareResult;
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) &&
+ db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0)==1)
+ {
+ if (db_get_ts(hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv)) continue;
+ tCompareResult = _tcscmp(dbv.ptszVal, chatname);
+ db_free(&dbv);
+ if (tCompareResult) continue;
+ return hContact; // already there, return handle
+ }
+ }
+ return NULL;
+}
+
+#ifdef _UNICODE
+HANDLE find_chatA(char *chatname) {
+ char *szProto;
+ int tCompareResult;
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) &&
+ db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0)==1)
+ {
+ if (db_get_s(hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv)) continue;
+ tCompareResult = strcmp(dbv.pszVal, chatname);
+ db_free(&dbv);
+ if (tCompareResult) continue;
+ return hContact; // already there, return handle
+ }
+ }
+ return NULL;
+}
+#endif
+
+
+
+int __cdecl AddMembers(char *szSkypeMsg) {
+ BYTE *contactmask=NULL;
+ DBVARIANT dbv2;
+ CONTACTINFO ci={0};
+ char *ptr, *who, *nextoken;
+ TCHAR *szChatId;
+ int i, iRet = 0;
+ gchat_contacts *gc;
+
+ LOG(("AddMembers STARTED"));
+ if (!(ptr=strstr(szSkypeMsg, " MEMBERS"))) return -1;
+ EnterCriticalSection(&m_GCMutex);
+ ptr[0]=0;
+ szChatId = make_nonutf_tchar_string((const unsigned char*)szSkypeMsg+5);
+ ptr+=9;
+ if (find_chat(szChatId) && (gc=GetChat(szChatId)) &&
+ !db_get_s(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv2))
+ {
+ char *pszMemObjs, *token;
+
+ if (protocol>=7 && (pszMemObjs = SkypeGet ("CHAT", szSkypeMsg+5, "MEMBEROBJECTS"))) {
+ // Add new contacts (protocol 7+ with memberobjects, supports roles)
+ for (token=strtok_r(pszMemObjs, ", ", &nextoken); token; token=strtok_r(NULL, ", ", &nextoken)) {
+ if (!(who = SkypeGet ("CHATMEMBER", token, "IDENTITY"))) continue;
+ if (strcmp(who, dbv2.pszVal)) {
+ char *pszRole;
+ TCHAR *ptszRole = NULL;
+
+ if (pszRole = SkypeGet ("CHATMEMBER", token, "ROLE"))
+ ptszRole = make_nonutf_tchar_string((const unsigned char*)pszRole);
+
+ i=AddChatContact(gc, who, ptszRole);
+ free_nonutf_tchar_string (ptszRole);
+ if (pszRole) free (pszRole);
+ if (i>=0 && !contactmask && !(contactmask = (unsigned char*)calloc(gc->mJoinedCount, 1))) i=-2;
+ if (!(contactmask= (unsigned char *) realloc(contactmask, gc->mJoinedCount))) {
+ iRet = -1;
+ free (who);
+ break;
+ }
+ contactmask[i]=TRUE;
+ }
+ free (who);
+ }
+ free (pszMemObjs);
+ }
+ else
+ {
+ // Add new contacts (normal)
+ for (who=strtok_r(ptr, " ", &nextoken); who; who=strtok_r(NULL, " ", &nextoken)) {
+ if (strcmp(who, dbv2.pszVal)) {
+ i=AddChatContact(gc, who, NULL);
+ if (i>=0 && !contactmask && !(contactmask = (unsigned char*)calloc(gc->mJoinedCount, 1))) i=-2;
+ if (i<0 || !(contactmask= (unsigned char *) realloc(contactmask, gc->mJoinedCount))) {
+ iRet = -1;
+ break;
+ }
+ contactmask[i]=TRUE;
+ }
+ }
+ }
+ // Quit contacts which are no longer there
+ if (iRet == 0 && contactmask) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = szChatId;
+ gcd.iType = GC_EVENT_QUIT;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.time = (DWORD)time(NULL);
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY;
+
+ for (i=0;i<gc->mJoinedCount;i++)
+ if (!contactmask[i])
+ {
+ ci.hContact = gc->mJoinedContacts[i].hContact;
+ ci.dwFlag = CNF_TCHAR;
+ if (ci.hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=gc->mJoinedContacts[i].who;
+ RemChatContact(gc, gc->mJoinedContacts[i].who);
+ gce.ptszUID = gc->mJoinedContacts[i].who;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ if (ci.pszVal) {
+ mir_free (ci.pszVal);
+ ci.pszVal=NULL;
+ }
+ }
+ // We don't do this, because the dialog group-chat may have been started intentionally
+ /*
+ if (gc->mJoinedCount == 1) {
+ // switch back to normal session
+ KillChatSession(&gcd);
+ }
+ */
+ }
+ if (contactmask) free(contactmask);
+ db_free(&dbv2);
+ } else iRet = -1;
+ free_nonutf_tchar_string (szChatId);
+ LeaveCriticalSection(&m_GCMutex);
+ LOG(("AddMembers DONE"));
+ return iRet;
+}
+
+void AddMembersThread(char *szSkypeMsg)
+{
+ AddMembers (szSkypeMsg);
+ free (szSkypeMsg);
+}
+
+/****************************************************************************/
+/* Window procedures */
+/****************************************************************************/
+INT_PTR CALLBACK InputBoxDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLong (hwndDlg, DWLP_USER, lParam);
+ SetDlgItemText (hwndDlg, IDC_TEXT, (TCHAR*)lParam);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ {
+ GetDlgItemText(hwndDlg, IDC_TEXT, (TCHAR*)GetWindowLong(hwndDlg, DWLP_USER), MAX_BUF-1*sizeof(TCHAR));
+ EndDialog(hwndDlg, 1);
+ break;
+ }
+ case IDCANCEL:
+ EndDialog(hwndDlg, 0);
+ break;
+ } }
+ return FALSE;
+}
+
+/****************************************************************************/
+/* Core Chat management functions */
+/****************************************************************************/
+
+/* We have a new Groupchat
+
+ This hook is called when a new chat is initialised.
+ Parameters: wParam = (char *)Name of new chat session [Has to be ASCIIZ/UTF8]
+ lParam = 1 - Create groupchat, but don't open it
+ 0 - Default - open groupchat after init
+*/
+int __cdecl ChatInit(WPARAM wParam, LPARAM lParam) {
+ GCSESSION gcw = {0};
+ GCEVENT gce = {0};
+ GCDEST gcd = {0};
+ DBVARIANT dbv, dbv2;
+ char *szChatName;
+ int iRet = -1;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!wParam) return -1;
+
+ gcw.cbSize = sizeof(GCSESSION);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = SKYPE_PROTONAME;
+ gcw.dwFlags = GC_TCHAR;
+
+ if (!(szChatName = SkypeGet ("CHAT", (char *)wParam, "FRIENDLYNAME")) || !*szChatName)
+ gcw.ptszName=TranslateT("Unknown"); else {
+#ifdef _UNICODE
+ gcw.ptszName=make_unicode_string((const unsigned char*)szChatName);
+ free (szChatName);
+ szChatName = (char*)gcw.ptszName;
+#else
+ gcw.ptszName=szChatName;
+#endif
+ }
+ gcw.ptszID = make_nonutf_tchar_string((const unsigned char*)wParam);
+ gcw.pszStatusbarText = NULL;
+ EnterCriticalSection(&m_GCMutex);
+ if (!CallService(MS_GC_NEWSESSION, 0, (LPARAM)&gcw)) {
+ char *szChatRole;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = (TCHAR*)gcw.ptszID;
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.pDest = &gcd;
+ gce.ptszStatus = _T("CREATOR");
+ gce.dwFlags = GC_TCHAR;
+ // BUG: Groupchat returns nonzero on success here in earlier versions, so we don't check
+ // it here
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ gce.ptszStatus = _T("MASTER");
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ gce.ptszStatus = _T("HELPER");
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ gce.ptszStatus = _T("USER");
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ gce.ptszStatus = _T("LISTENER");
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ gce.ptszStatus = _T("APPLICANT");
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_JOIN;
+ gce.ptszStatus = NULL;
+ if (protocol >=7 && (szChatRole = SkypeGet ("CHAT", (char *)wParam, "MYROLE"))) {
+ if (strncmp(szChatRole, "ERROR", 5))
+ {
+#ifdef _UNICODE
+ gce.ptszStatus = make_unicode_string((const unsigned char*)szChatRole);
+ free (szChatRole);
+#else
+ gce.ptszStatus = szChatRole;
+#endif
+ }
+ }
+ if (!gce.ptszStatus) gce.ptszStatus=_tcsdup(_T("CREATOR"));
+
+ if (!db_get_ts(NULL, SKYPE_PROTONAME, "Nick", &dbv)) {
+ if (!db_get_ts(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv2)) {
+ gce.ptszNick = dbv.ptszVal;
+ gce.ptszUID = dbv2.ptszVal;
+ gce.time = 0;
+ gce.bIsMe = TRUE;
+ gce.dwFlags |= GCEF_ADDTOLOG;
+ if (!CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce)) {
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.iType = GC_EVENT_CONTROL;
+ gce.pDest = &gcd;
+ if (!lParam) CallService(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
+ CallService(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+ CallService(MS_GC_EVENT, lParam?WINDOW_HIDDEN:WINDOW_VISIBLE, (LPARAM)&gce);
+ SkypeSend ("GET CHAT %s MEMBERS", (char *)wParam);
+ iRet = 0;
+ } else {LOG (("ChatInit: Joining 'me' failed."));}
+ }
+ db_free(&dbv2);
+ }
+ free ((void*)gce.ptszStatus);
+ db_free(&dbv);
+ }
+ free (szChatName);
+ free_nonutf_tchar_string ((void*)gcw.ptszID);
+ LeaveCriticalSection(&m_GCMutex);
+ return iRet;
+}
+
+/* Open new Groupchat
+
+ Parameters: szChatId = (char *)Name of new chat session
+*/
+int __cdecl ChatStart(char *szChatId, BOOL bJustCreate) {
+ LOG(("ChatStart: New groupchat started"));
+ if (!szChatId || NotifyEventHooks(hInitChat, (WPARAM)szChatId, bJustCreate)) return -1;
+ return 0;
+}
+
+
+void KillChatSession(GCDEST *gcd) {
+ GCEVENT gce = {0};
+
+ EnterCriticalSection(&m_GCMutex);
+ LOG(("KillChatSession: Groupchatsession terminated."));
+ gce.cbSize = sizeof(GCEVENT);
+ gce.dwFlags = GC_TCHAR;
+ gce.pDest = gcd;
+ gcd->iType = GC_EVENT_CONTROL;
+ if (SkypeSend ("ALTER CHAT "STR" LEAVE", gcd->ptszID) == 0)
+ {
+ CallService(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce);
+ CallService(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce);
+ }
+ LeaveCriticalSection(&m_GCMutex);
+}
+
+void InviteUser(TCHAR *szChatId) {
+ HMENU tMenu = CreatePopupMenu();
+ HANDLE hContact = db_find_first(), hInvitedUser;
+ DBVARIANT dbv;
+ HWND tWindow;
+ POINT pt;
+ gchat_contacts *gc;
+ int j;
+
+ if (!szChatId || !(gc=GetChat(szChatId))) return;
+
+ // add the heading
+ AppendMenu(tMenu, MF_STRING|MF_GRAYED|MF_DISABLED, (UINT_PTR)0, TranslateT("&Invite user..."));
+ AppendMenu(tMenu, MF_SEPARATOR, (UINT_PTR)1, NULL);
+
+ // generate a list of contact
+ while (hContact) {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact,0 );
+ if (szProto && !strcmp(SKYPE_PROTONAME, szProto) &&
+ !db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) &&
+ db_get_w(hContact, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE)!=ID_STATUS_OFFLINE)
+ {
+ BOOL alreadyInSession = FALSE;
+ for (j=0; j<gc->mJoinedCount; j++) {
+ if (gc->mJoinedContacts[j].hContact==hContact) {
+ alreadyInSession = TRUE;
+ break;
+ }
+ }
+ if (!alreadyInSession)
+ AppendMenu(tMenu, MF_STRING, (UINT_PTR)hContact,
+ (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+ }
+ hContact = db_find_next(hContact);
+ }
+
+ tWindow = CreateWindow(_T("EDIT"),_T(""),0,1,1,1,1,NULL,NULL,hInst,NULL);
+
+ GetCursorPos (&pt);
+ hInvitedUser = (HANDLE)TrackPopupMenu(tMenu, TPM_NONOTIFY | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, tWindow, NULL);
+ DestroyMenu(tMenu);
+ DestroyWindow(tWindow);
+
+ if (!hInvitedUser || db_get_s(hInvitedUser, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return;
+ SkypeSend ("ALTER CHAT "STR" ADDMEMBERS %s", szChatId, dbv.pszVal);
+ db_free(&dbv);
+
+}
+
+static void KickUser (HANDLE hContact, GCHOOK *gch)
+{
+ char *ptr;
+
+ EnterCriticalSection(&m_GCMutex);
+ if (SkypeSend ("ALTER CHAT "STR" KICK "STR, gch->pDest->ptszID, gch->ptszUID)!=-1) {
+ if (ptr=SkypeRcv("ALTER CHAT KICK", 2000)) {
+ if (strncmp(ptr, "ERROR", 5)) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ CONTACTINFO ci = {0};
+ DBVARIANT dbv;
+
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = (TCHAR*)gch->pDest->ptszID;
+ gcd.iType = GC_EVENT_KICK;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.time = (DWORD)time(NULL);
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.ptszUID= gch->ptszUID;
+
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ ci.hContact = hContact;
+ if (hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=gce.ptszUID;
+
+ if (!db_get_ts(NULL, SKYPE_PROTONAME, "Nick", &dbv)) {
+ gce.ptszStatus = dbv.ptszVal;
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ RemChatContact (GetChat(gcd.ptszID), gch->ptszUID);
+ db_free(&dbv);
+ }
+ if (ci.pszVal) mir_free (ci.pszVal);
+ }
+ free (ptr);
+ }
+ }
+ LeaveCriticalSection(&m_GCMutex);
+}
+
+void SetChatTopic (TCHAR *szChatId, TCHAR *szTopic, BOOL bSet)
+{
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ HANDLE hContact = find_chat (szChatId);
+ char *szUTFTopic;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = szChatId;
+ gcd.iType = GC_EVENT_TOPIC;
+ gce.pDest = &gcd;
+ gce.ptszText = szTopic;
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.time = (DWORD)time (NULL);
+ gce.dwFlags = GC_TCHAR;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ gcd.iType = GC_EVENT_SETSBTEXT;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+
+ if (bSet) {
+#ifdef _UNICODE
+ szUTFTopic=(char*)make_utf8_string(szTopic);
+#else
+ if (utf8_encode(szTopic, &szUTFTopic)==-1) szUTFTopic = NULL;
+#endif
+ if (szUTFTopic) {
+ SkypeSend ("ALTER CHAT "STR" SETTOPIC %s", szChatId, szUTFTopic);
+ free (szUTFTopic);
+ }
+ testfor ("ALTER CHAT SETTOPIC", INFINITE);
+ }
+
+ if (hContact)
+ db_set_ts(hContact, SKYPE_PROTONAME, "Nick", szTopic);
+}
+
+
+int GCEventHook(WPARAM wParam,LPARAM lParam) {
+ GCHOOK *gch = (GCHOOK*) lParam;
+ gchat_contacts *gc = GetChat(gch->pDest->ptszID);
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ if(gch) {
+ if (!_stricmp(gch->pDest->pszModule, SKYPE_PROTONAME)) {
+
+ switch (gch->pDest->iType) {
+ case GC_SESSION_TERMINATE: {
+ HANDLE hContact;
+
+ if (gc->mJoinedCount == 1) {
+ // switch back to normal session
+ // I don't know if this behaviour isn't a bit annoying, therefore, we
+ // don't do this now, until a user requests this feature :)
+
+ // open up srmm dialog when quit while 1 person left
+// CallService(MS_MSG_SENDMESSAGE, (WPARAM)gc->mJoinedContacts[0].hContact, 0);
+
+ RemChatContact(gc, gc->mJoinedContacts[0].who);
+ }
+ // Delete Chatroom from Contact list, as we don't need it anymore...?
+ if (hContact = find_chat(gc->szChatName))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ RemChat(gc->szChatName);
+
+ break;
+ }
+ case GC_USER_MESSAGE:
+ if(gch && gch->ptszText && _tcslen(gch->ptszText) > 0) {
+ DBVARIANT dbv, dbv2;
+ CCSDATA ccs = {0};
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ TCHAR *pEnd;
+
+ // remove the ending linebreak
+ for (pEnd = &gch->ptszText[_tcslen(gch->ptszText) - 1];
+ *pEnd==_T('\r') || *pEnd==_T('\n'); pEnd--) *pEnd=0;
+ // Send message to the chat-contact
+ if (ccs.hContact = find_chat(gch->pDest->ptszID)) {
+#ifdef _UNICODE
+ // If PREF_UTF is supported, just convert it to UTF8 and pass the buffer to PSS_MESSAGE
+ if (mirandaVersion >= 0x070000) {
+ ccs.lParam = (LPARAM)make_utf8_string(gch->ptszText);
+ ccs.wParam = PREF_UTF;
+ CallProtoService (SKYPE_PROTONAME, PSS_MESSAGE, 0, (LPARAM)&ccs);
+ free ((void*)ccs.lParam);
+ } else {
+ // Otherwise create this strange dual miranda-format
+ ccs.lParam = (LPARAM)calloc(3, _tcslen(gch->ptszText)+1);
+ wcstombs ((char*)ccs.lParam, gch->ptszText, _tcslen(gch->ptszText)+1);
+ _tcscpy ((TCHAR*)((char*)ccs.lParam+strlen((char*)ccs.lParam)+1), gch->ptszText);
+ ccs.wParam = PREF_UNICODE;
+ CallProtoService (SKYPE_PROTONAME, PSS_MESSAGE, 0, (LPARAM)&ccs);
+ free ((void*)ccs.lParam);
+ }
+#else
+ ccs.lParam = (LPARAM)gch->ptszText;
+ ccs.wParam = PREF_TCHAR;
+ CallProtoService (SKYPE_PROTONAME, PSS_MESSAGE, 0, (LPARAM)&ccs);
+#endif
+ }
+
+ // Add our line to the chatlog
+ gcd.pszModule = gch->pDest->pszModule;
+ gcd.ptszID = gch->pDest->ptszID;
+ if ( _tcsncmp(gch->ptszText, _T("/me "), 4)==0 && _tcslen(gch->ptszText)>4) {
+ gce.ptszText = gch->ptszText+4;
+ gcd.iType = GC_EVENT_ACTION;
+ }
+ else {
+ gce.ptszText = gch->ptszText;
+ gcd.iType = GC_EVENT_MESSAGE;
+ }
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ if (db_get_ts(NULL, SKYPE_PROTONAME, "Nick", &dbv)) gce.ptszNick=TranslateT("Me");
+ else gce.ptszNick = dbv.ptszVal;
+ db_get_ts(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv2);
+ gce.ptszUID = dbv2.ptszVal;
+ gce.time = (DWORD)time(NULL);
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.bIsMe = TRUE;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ if (dbv.pszVal) db_free(&dbv);
+ if (dbv2.pszVal) db_free(&dbv2);
+ }
+ break;
+ case GC_USER_CHANMGR:
+ InviteUser(gch->pDest->ptszID);
+ break;
+ case GC_USER_PRIVMESS: {
+ HANDLE hContact = find_contactT(gch->ptszUID);
+ if (hContact) CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0);
+ break;
+
+ }
+ case GC_USER_LOGMENU:
+ switch(gch->dwData) {
+ case 10: InviteUser(gch->pDest->ptszID); break;
+ case 20: KillChatSession(gch->pDest); break;
+ case 30:
+ {
+ TCHAR *ptr, buf[MAX_BUF];
+
+ ptr = SkypeGetT ("CHAT", gch->pDest->ptszID, "TOPIC");
+ _tcscpy(buf, ptr);
+ free(ptr);
+ if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_INPUTBOX), NULL, InputBoxDlgProc, (LPARAM)&buf))
+ SetChatTopic (gch->pDest->ptszID, buf, TRUE);
+ break;
+ }
+ }
+ break;
+ case GC_USER_NICKLISTMENU: {
+ HANDLE hContact = find_contactT(gch->ptszUID);
+
+ switch(gch->dwData) {
+ case 10:CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); break;
+ case 20:CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)hContact, 0); break;
+ case 30: KickUser(hContact, gch); break;
+ case 110: KillChatSession(gch->pDest); break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ }
+ return 0;
+}
+
+int __cdecl GCMenuHook(WPARAM wParam,LPARAM lParam) {
+ GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam;
+ DBVARIANT dbv;
+ TCHAR* szInvite = TranslateT("&Invite user...");
+ TCHAR* szLeave = TranslateT("&Leave chat session");
+ TCHAR* szTopic = TranslateT("Set &Topic...");
+ TCHAR* szDetails = TranslateT("User &details");
+ TCHAR* szHistory = TranslateT("User &history");
+ TCHAR* szKick = TranslateT("&Kick user");
+
+ static struct gc_item Item_log[] = {
+ {NULL, 10, MENU_ITEM, FALSE},
+ {NULL, 30, MENU_ITEM, FALSE},
+ {NULL, 20, MENU_ITEM, FALSE}
+ };
+ static struct gc_item Item_nicklist_me[] = {
+ {NULL, 20, MENU_ITEM, FALSE},
+ {_T(""), 100, MENU_SEPARATOR, FALSE},
+ {NULL, 110, MENU_ITEM, FALSE}
+ };
+ static struct gc_item Item_nicklist[] = {
+ {NULL, 10, MENU_ITEM, FALSE},
+ {NULL, 20, MENU_ITEM, FALSE},
+ {NULL, 30, MENU_ITEM, FALSE}
+ };
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ Item_log[0].pszDesc = szInvite;
+ Item_log[1].pszDesc = szTopic;
+ Item_log[2].pszDesc = szLeave;
+ Item_nicklist_me[0].pszDesc = szHistory;
+ Item_nicklist_me[2].pszDesc = szLeave;
+ Item_nicklist[0].pszDesc = szDetails;
+ Item_nicklist[1].pszDesc = szHistory;
+ Item_nicklist[2].pszDesc = szKick;
+
+ LOG (("GCMenuHook started."));
+ if(gcmi) {
+ if (!_stricmp(gcmi->pszModule, SKYPE_PROTONAME)) {
+ switch (gcmi->Type)
+ {
+ case MENU_ON_LOG:
+ gcmi->nItems = sizeof(Item_log)/sizeof(Item_log[0]);
+ gcmi->Item = &Item_log[0];
+ LOG (("GCMenuHook: Items in log window: %d", gcmi->nItems));
+ break;
+ case MENU_ON_NICKLIST:
+ if (db_get_ts(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) return -1;
+ if (!lstrcmp(dbv.ptszVal, gcmi->pszUID)) {
+ gcmi->nItems = sizeof(Item_nicklist_me)/sizeof(Item_nicklist_me[0]);
+ gcmi->Item = &Item_nicklist_me[0];
+ } else {
+ gchat_contacts *gcs = GetChat(gcmi->pszID);
+ gchat_contact *gc = gcs?GetChatContact(gcs, gcmi->pszUID):NULL;
+ gcmi->nItems = sizeof(Item_nicklist)/sizeof(Item_nicklist[0]);
+
+ Item_nicklist[2].bDisabled = FALSE;
+ if (gc && !gc->hContact)
+ {
+ gcmi->nItems -= 2;
+ gcmi->Item = &Item_nicklist[2];
+ }
+ else
+ gcmi->Item = &Item_nicklist[0];
+ /*
+ if (protocol<7) Item_nicklist[2].bDisabled = TRUE;
+ else {
+ TCHAR *szChatRole;
+ if (szChatRole = SkypeGetT ("CHAT", gcmi->pszID, "MYROLE")) {
+ if (_tcscmp(szChatRole, _T("MASTER")) && _tcscmp(szChatRole, _T("CREATOR")))
+ Item_nicklist[2].bDisabled = TRUE;
+ free (szChatRole);
+ }
+ }*/
+
+ }
+ db_free(&dbv);
+ break;
+ }
+ } else {LOG (("GCMenuHook: ERROR: Not our protocol."));}
+ } else {LOG (("GCMenuHook: ERROR: No gcmi"));}
+ LOG (("GCMenuHook: terminated."));
+ return 0;
+}
+
+INT_PTR GCOnLeaveChat(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ DBVARIANT dbv;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (db_get_ts(hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv) == 0)
+ {
+ GCDEST gcd = {0};
+
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.iType = GC_EVENT_CONTROL;
+ gcd.ptszID = dbv.ptszVal;
+ KillChatSession(&gcd);
+ db_free(&dbv);
+ }
+ return 0;
+}
+
+INT_PTR GCOnJoinChat(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ DBVARIANT dbv;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (db_get_s(hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv) == 0)
+ {
+ ChatStart (dbv.pszVal, FALSE);
+ db_free(&dbv);
+ }
+ return 0;
+}
+
+void GCInit(void)
+{
+ InitializeCriticalSection (&m_GCMutex);
+}
+
+void GCExit(void)
+{
+ int i;
+
+ DeleteCriticalSection (&m_GCMutex);
+ for (i=0;i<chatcount;i++) {
+ if (chats[i].szChatName) free(chats[i].szChatName);
+ if (chats[i].mJoinedContacts) free(chats[i].mJoinedContacts);
+ }
+ if (chats) free (chats);
+ chats = NULL;
+ chatcount = 0;
+} \ No newline at end of file
diff --git a/protocols/SkypeClassic/gchat.h b/protocols/SkypeClassic/gchat.h
new file mode 100644
index 0000000000..f9bd283320
--- /dev/null
+++ b/protocols/SkypeClassic/gchat.h
@@ -0,0 +1,47 @@
+// m_chat users these BaseTSD types, so if we are compiling with an old PSDK, these typedefs
+// are not there, so better define them, just in case...
+#ifndef LongToPtr
+#define DWORD_PTR DWORD
+#endif
+
+#pragma warning (push)
+#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
+#include <m_chat.h>
+#pragma warning (pop)
+
+#define MAX_BUF 256 // Buffer for topic-string
+
+typedef struct {
+ HANDLE hContact;
+ TCHAR who[33];
+ TCHAR szRole[12];
+} gchat_contact;
+
+typedef struct {
+ TCHAR* szChatName; // name of chat session
+ gchat_contact* mJoinedContacts; // contacts
+ int mJoinedCount; // contacts count
+} gchat_contacts;
+
+int ChatInit(WPARAM, LPARAM);
+int __cdecl ChatStart(char *szChatId, BOOL bJustCreate);
+gchat_contacts *GetChat(TCHAR *szChatId);
+HANDLE find_chat(TCHAR *chatname);
+#ifdef _UNICODE
+HANDLE find_chatA(char *chatname);
+#else
+#define find_chatA find_chat
+#endif
+void RemChatContact(gchat_contacts*, const TCHAR*);
+gchat_contact *GetChatContact(gchat_contacts *gc, const TCHAR *who);
+int AddMembers(char*);
+void AddMembersThread(char *szSkypeMsg);
+void RemChat(TCHAR *szChatId);
+int GCEventHook (WPARAM, LPARAM);
+int GCMenuHook (WPARAM, LPARAM);
+void KillChatSession(GCDEST*);
+INT_PTR GCOnLeaveChat(WPARAM wParam,LPARAM lParam);
+INT_PTR GCOnJoinChat(WPARAM wParam,LPARAM lParam);
+void GCInit(void);
+void GCExit(void);
+void SetChatTopic (TCHAR *szChatId, TCHAR *szTopic, BOOL bSet);
diff --git a/protocols/SkypeClassic/memlist.cpp b/protocols/SkypeClassic/memlist.cpp
new file mode 100644
index 0000000000..b14133ef57
--- /dev/null
+++ b/protocols/SkypeClassic/memlist.cpp
@@ -0,0 +1,248 @@
+// The omnipresent memory list, WIN32 implementation, thread safe
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "memlist.h"
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+struct _tagLIST
+{
+ unsigned int uiCount;
+ unsigned int uiCapacity;
+ void **apStorage;
+ HANDLE hHeap;
+ CRITICAL_SECTION cs;
+};
+
+
+TYP_LIST *List_Init(unsigned int uiCapacity)
+{
+ HANDLE hHeap = GetProcessHeap();
+ TYP_LIST *pstHandle;
+
+ pstHandle = (TYP_LIST *)HeapAlloc(hHeap, 0, sizeof(TYP_LIST));
+ if (!pstHandle) return NULL;
+ pstHandle->uiCount = 0;
+ pstHandle->uiCapacity = uiCapacity;
+ if (uiCapacity == 0)
+ pstHandle->apStorage = NULL;
+ else
+ {
+ pstHandle->apStorage = (void **)HeapAlloc(hHeap, 0, sizeof(void *)*uiCapacity);
+ if (!pstHandle->apStorage)
+ {
+ HeapFree (hHeap, 0, pstHandle);
+ return NULL;
+ }
+ }
+ pstHandle->hHeap = hHeap;
+ InitializeCriticalSection (&pstHandle->cs);
+ return pstHandle;
+}
+
+void List_Exit(TYP_LIST *pstHandle)
+{
+ if (pstHandle->apStorage)
+ HeapFree (pstHandle->hHeap, 0, pstHandle->apStorage);
+ DeleteCriticalSection (&pstHandle->cs);
+ HeapFree (pstHandle->hHeap, 0, pstHandle);
+}
+
+BOOL List_Push(TYP_LIST *pstHandle, void *pItem)
+{
+ return List_InsertElementAt(pstHandle, pItem,pstHandle->uiCount);
+}
+
+void *List_Pop (TYP_LIST *pstHandle)
+{
+ if (pstHandle->uiCount)
+ return List_RemoveElementAt(pstHandle ,pstHandle->uiCount-1);
+ else return NULL;
+}
+
+BOOL List_InsertElementAt(TYP_LIST *pstHandle, void *pItem, unsigned int uiPos)
+{
+ unsigned int uiStep;
+ void **apNewStorage;
+
+ EnterCriticalSection (&pstHandle->cs);
+ if (uiPos > pstHandle->uiCount)
+ uiPos = pstHandle->uiCount;
+
+ if (pstHandle->uiCount >= pstHandle->uiCapacity)
+ {
+ uiStep = pstHandle->uiCount*2;
+ if (uiStep < 8) uiStep = 8;
+
+ if (!pstHandle->apStorage)
+ apNewStorage = (void **)HeapAlloc(pstHandle->hHeap, 0, sizeof(void *)*uiStep);
+ else
+ apNewStorage = (void **)HeapReAlloc (pstHandle->hHeap, 0, pstHandle->apStorage, sizeof(void *)*uiStep);
+ if (!apNewStorage)
+ {
+ LeaveCriticalSection (&pstHandle->cs);
+ return FALSE;
+ }
+ pstHandle->apStorage = apNewStorage;
+ pstHandle->uiCapacity = uiStep;
+ }
+
+ if (uiPos<pstHandle->uiCount)
+ MoveMemory (&pstHandle->apStorage[uiPos+1], &pstHandle->apStorage[uiPos], (pstHandle->uiCount-uiPos)*sizeof(void*));
+ pstHandle->apStorage[uiPos] = pItem;
+ pstHandle->uiCount++;
+ LeaveCriticalSection (&pstHandle->cs);
+ return TRUE;
+}
+
+void *List_RemoveElementAt(TYP_LIST *pstHandle, unsigned int uiPos)
+{
+ void *pRet;
+
+ EnterCriticalSection (&pstHandle->cs);
+ pRet = pstHandle->apStorage[uiPos];
+ if (uiPos<pstHandle->uiCount)
+ MoveMemory (&pstHandle->apStorage[uiPos], &pstHandle->apStorage[uiPos+1], (pstHandle->uiCount-uiPos)*sizeof(void*));
+ pstHandle->uiCount--;
+ LeaveCriticalSection (&pstHandle->cs);
+ return pRet;
+}
+
+unsigned int List_Count(TYP_LIST *pstHandle)
+{
+ return pstHandle->uiCount;
+}
+
+void *List_ElementAt(TYP_LIST *pstHandle,unsigned int uiPos)
+{
+ void *pRet = NULL;
+
+ EnterCriticalSection (&pstHandle->cs);
+ if (uiPos < pstHandle->uiCount)
+ pRet = pstHandle->apStorage[uiPos];
+ LeaveCriticalSection (&pstHandle->cs);
+ return pRet;
+}
+
+void *List_Top(TYP_LIST *pstHandle)
+{
+ if (pstHandle->uiCount)
+ return List_ElementAt (pstHandle, pstHandle->uiCount-1);
+ else return NULL;
+}
+
+#ifdef _INC_STDLIB
+void List_Sort(TYP_LIST *pstHandle, int (*pFunc)(const void*,const void*))
+{
+ EnterCriticalSection (&pstHandle->cs);
+ qsort(pstHandle->apStorage,pstHandle->uiCount,sizeof(void *),pFunc);
+ LeaveCriticalSection (&pstHandle->cs);
+}
+#endif
+
+
+void List_FreeElements(TYP_LIST *pstHandle)
+{
+ void *pEntry;
+ HANDLE hHeap = GetProcessHeap();
+
+ while (pEntry = List_Pop(pstHandle))
+ HeapFree (hHeap, 0, pEntry);
+}
+
+BOOL List_BinarySearch(TYP_LIST *hPList,
+ int (*pPFunc)(const void *pstPElement,const void *pstPToFind),
+ const void *pstPToFind,int *piPToInsert)
+{
+ unsigned int
+ iStart,
+ iEnd,
+ iInd;
+ int iRetCompare;
+
+ if (hPList == NULL)
+ {
+ *piPToInsert = 0;
+ return FALSE;
+ }
+
+ iStart = 0;
+ if (hPList->uiCount == 0)
+ {
+ *piPToInsert = 0;
+ return FALSE;
+ }
+ EnterCriticalSection (&hPList->cs);
+ iEnd = hPList->uiCount-1;
+
+ iRetCompare = (*pPFunc)(hPList->apStorage[0],pstPToFind);
+ if (iRetCompare >= 0)
+ {
+ *piPToInsert = 0;
+ LeaveCriticalSection (&hPList->cs);
+ return iRetCompare == 0;
+ }
+
+ iRetCompare = (*pPFunc)(hPList->apStorage[iEnd],pstPToFind);
+ if (iRetCompare < 0)
+ {
+ *piPToInsert = hPList->uiCount;
+ LeaveCriticalSection (&hPList->cs);
+ return FALSE;
+ }
+ else if (iRetCompare == 0)
+ {
+ *piPToInsert = hPList->uiCount-1;
+ LeaveCriticalSection (&hPList->cs);
+ return TRUE;
+ }
+
+ // Otherwise C4702: unreachable code below
+ #pragma warning (suppress: 4127) // conditional expression is constant
+ while(1)
+ {
+ switch (iEnd-iStart)
+ {
+ case 0:
+ *piPToInsert = iStart;
+ LeaveCriticalSection (&hPList->cs);
+ return FALSE;
+ case 1:
+ *piPToInsert = iStart+1;
+ LeaveCriticalSection (&hPList->cs);
+ return FALSE;
+ default:
+ iInd = iStart + (iEnd-iStart)/2;
+ iRetCompare = (*pPFunc)(hPList->apStorage[iInd],pstPToFind);
+ if (iRetCompare == 0)
+ {
+ *piPToInsert = iInd;
+ LeaveCriticalSection (&hPList->cs);
+ return TRUE;
+ }
+ if (iRetCompare < 0)
+ iStart = iInd;
+ else
+ iEnd = iInd;
+ break;
+ }
+ }
+
+ LeaveCriticalSection (&hPList->cs);
+ return FALSE;
+}
+
+BOOL List_InsertSort(TYP_LIST *hPList,
+ int (*pPFunc)(const void *pstPElement,const void *pstPToFind),
+ void *pItem)
+{
+ int iListInd;
+
+ if (!List_BinarySearch(hPList,pPFunc,(void *)pItem,&iListInd))
+ {
+ return List_InsertElementAt (hPList, pItem, iListInd);
+ }
+ return FALSE;
+}
+
+
diff --git a/protocols/SkypeClassic/memlist.h b/protocols/SkypeClassic/memlist.h
new file mode 100644
index 0000000000..7c147d37eb
--- /dev/null
+++ b/protocols/SkypeClassic/memlist.h
@@ -0,0 +1,43 @@
+#ifndef __MEMLIST_H__
+#define __MEMLIST_H__
+
+// Optional for programs linked against CRT:
+// Remove this if you want a proper plain WIN32-App
+//#include <stdlib.h>
+
+struct _tagLIST;
+typedef struct _tagLIST TYP_LIST;
+
+TYP_LIST *List_Init(unsigned int uiCapacity);
+void List_Exit(TYP_LIST *pstHandle);
+BOOL List_Push(TYP_LIST *pstHandle, void *pItem);
+void *List_Pop (TYP_LIST *pstHandle);
+BOOL List_InsertElementAt(TYP_LIST *pstHandle, void *pItem, unsigned int uiPos);
+void *List_RemoveElementAt(TYP_LIST *pstHandle, unsigned int uiPos);
+unsigned int List_Count(TYP_LIST *pstHandle);
+void *List_ElementAt(TYP_LIST *pstHandle,unsigned int uiPos);
+void *List_Top(TYP_LIST *pstHandle);
+void List_FreeElements(TYP_LIST *pstHandle);
+BOOL List_BinarySearch(TYP_LIST *hPList,
+ int (*pPFunc)(const void *pstPElement,const void *pstPToFind),
+ const void *pstPToFind,int *piPToInsert);
+BOOL List_InsertSort(TYP_LIST *hPList,
+ int (*pPFunc)(const void *pstPElement,const void *pstPToFind),
+ void *pItem);
+
+//#ifdef _INC_STDLIB
+void List_Sort(TYP_LIST *pstHandle, int (*pFunc)(const void*,const void*));
+/*#else
+#undef RtlMoveMemory
+NTSYSAPI
+VOID
+NTAPI
+RtlMoveMemory (
+ VOID UNALIGNED *Destination,
+ CONST VOID UNALIGNED *Source,
+ SIZE_T Length
+ );
+
+#endif*/
+
+#endif \ No newline at end of file
diff --git a/protocols/SkypeClassic/msglist.cpp b/protocols/SkypeClassic/msglist.cpp
new file mode 100644
index 0000000000..aedb4d1257
--- /dev/null
+++ b/protocols/SkypeClassic/msglist.cpp
@@ -0,0 +1,86 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "memlist.h"
+#include "debug.h"
+#include "msglist.h"
+
+#define MSGLIST_TIMEOUT 1800 // Chatmessage references will be kept for 30 minutes
+
+static TYP_LIST *m_hMsgList = NULL;
+
+static int CmpProc(const void *pstPElement,const void *pstPToFind)
+{
+ return (DWORD)pstPToFind - ((TYP_MSGLENTRY*)pstPElement)->uMsgNum;
+}
+
+void MsgList_Init(void)
+{
+ m_hMsgList = List_Init(128);
+}
+
+void MsgList_Exit(void)
+{
+ if (!m_hMsgList) return;
+ List_FreeElements (m_hMsgList);
+ List_Exit(m_hMsgList);
+ m_hMsgList = NULL;
+}
+
+TYP_MSGLENTRY *MsgList_Add(DWORD uMsgNum, HANDLE hEvent)
+{
+ TYP_MSGLENTRY *pEntry;
+ int iListInd;
+ BOOL bFound;
+
+ LOG (("MsgList_Add (%d, %08X)", uMsgNum, hEvent));
+ if (!m_hMsgList || !hEvent) return FALSE;
+ bFound = List_BinarySearch(m_hMsgList,CmpProc,(void *)uMsgNum,&iListInd);
+ if (!bFound) pEntry = (TYP_MSGLENTRY*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TYP_MSGLENTRY));
+ else pEntry = (TYP_MSGLENTRY*)List_ElementAt (m_hMsgList, iListInd);
+ if (!pEntry) return NULL;
+ pEntry->uMsgNum = uMsgNum;
+ pEntry->hEvent = hEvent;
+ pEntry->tEdited = 0;
+ time(&pEntry->t);
+ if (!bFound) return List_InsertElementAt (m_hMsgList, pEntry, iListInd)?pEntry:NULL;
+ return pEntry;
+}
+
+
+TYP_MSGLENTRY *MsgList_FindMessage(DWORD uMsgNum)
+{
+ TYP_MSGLENTRY *pEntry;
+ int iPos;
+
+ LOG (("MsgList_FindEvent (%d)", uMsgNum));
+ if (m_hMsgList && List_BinarySearch(m_hMsgList, CmpProc, (void*)uMsgNum, &iPos))
+ {
+ pEntry = (TYP_MSGLENTRY*)List_ElementAt (m_hMsgList, iPos);
+ time(&pEntry->t); // Touch it, so that it doesn't get thrown away too soon
+ LOG (("MsgList_FindEvent(%d): %08X", uMsgNum, pEntry->hEvent));
+ return pEntry;
+ }
+ return NULL;
+}
+
+void MsgList_CollectGarbage(void)
+{
+ unsigned int i;
+ TYP_MSGLENTRY *pEntry;
+ time_t t;
+
+ if (!m_hMsgList) return;
+ time(&t);
+ t-=MSGLIST_TIMEOUT;
+ for (i=0; i<List_Count(m_hMsgList); i++)
+ {
+ pEntry = (TYP_MSGLENTRY*)List_ElementAt (m_hMsgList, i);
+ if (pEntry->t < t)
+ {
+ LOG (("MsgList_CollectGarbage throwing out msg %d", pEntry->uMsgNum));
+ HeapFree (GetProcessHeap(), 0, List_RemoveElementAt (m_hMsgList, i));
+ i--;
+ }
+ }
+}
+
diff --git a/protocols/SkypeClassic/msglist.h b/protocols/SkypeClassic/msglist.h
new file mode 100644
index 0000000000..66a271ef18
--- /dev/null
+++ b/protocols/SkypeClassic/msglist.h
@@ -0,0 +1,15 @@
+#include <time.h>
+
+typedef struct {
+ DWORD uMsgNum;
+ HANDLE hEvent;
+ HANDLE hMetaEvent;
+ time_t t;
+ time_t tEdited;
+} TYP_MSGLENTRY;
+
+void MsgList_Init(void);
+void MsgList_Exit(void);
+TYP_MSGLENTRY *MsgList_Add(DWORD uMsgNum, HANDLE hEvent);
+TYP_MSGLENTRY *MsgList_FindMessage(DWORD uMsgNum);
+void MsgList_CollectGarbage(void);
diff --git a/protocols/SkypeClassic/msgq.cpp b/protocols/SkypeClassic/msgq.cpp
new file mode 100644
index 0000000000..e1ab0d1998
--- /dev/null
+++ b/protocols/SkypeClassic/msgq.cpp
@@ -0,0 +1,90 @@
+/*
+ * Implements a simple message queue for send and receive queue.
+ * We could use memlist.c, but it's not efficient
+ * enough for this purpose (would always memmove on removing first
+ * element), therefore it's implemented as tail queue.
+ */
+
+#include "skype.h"
+#include "msgq.h"
+#include "debug.h"
+
+
+void MsgQ_Init(TYP_MSGQ *q)
+{
+ TAILQ_INIT(&q->l);
+ InitializeCriticalSection (&q->cs);
+}
+
+void MsgQ_Exit(TYP_MSGQ *q)
+{
+ struct MsgQueue *ptr;
+
+ EnterCriticalSection(&q->cs);
+ while ((ptr=q->l.tqh_first) != NULL)
+ free(MsgQ_RemoveMsg(q, ptr));
+ LeaveCriticalSection(&q->cs);
+ DeleteCriticalSection (&q->cs);
+}
+
+BOOL MsgQ_Add(TYP_MSGQ *q, char *msg)
+{
+ struct MsgQueue *ptr;
+
+ if ((ptr=(struct MsgQueue*)malloc(sizeof(struct MsgQueue))) == NULL)
+ return FALSE;
+ ptr->message = _strdup(msg); // Don't forget to free!
+ ptr->tAdded = SkypeTime(NULL);
+ SkypeTime(&ptr->tReceived);
+ EnterCriticalSection(&q->cs);
+ TAILQ_INSERT_TAIL(&q->l, ptr, l);
+ //LOG (("MsgQ_Add (%s) @%lu/%ld", msg, ptr->tReceived, ptr->tAdded));
+ LeaveCriticalSection(&q->cs);
+ return TRUE;
+}
+
+char *MsgQ_RemoveMsg(TYP_MSGQ *q, struct MsgQueue *ptr)
+{
+ char *msg;
+
+ if (!ptr) return NULL;
+ EnterCriticalSection(&q->cs);
+ TAILQ_REMOVE(&q->l, ptr, l);
+ LeaveCriticalSection(&q->cs);
+ msg=ptr->message;
+ free(ptr);
+ return msg;
+}
+
+char *MsgQ_Get(TYP_MSGQ *q)
+{
+ char *msg;
+
+ msg=MsgQ_RemoveMsg(q, q->l.tqh_first);
+ return msg;
+}
+
+int MsgQ_CollectGarbage(TYP_MSGQ *q, time_t age)
+{
+ struct MsgQueue *ptr;
+ int i=0;
+
+ EnterCriticalSection(&q->cs);
+ ptr=q->l.tqh_first;
+ while (ptr)
+ {
+ if (ptr->tAdded && SkypeTime(NULL)-ptr->tAdded>age)
+ {
+ struct MsgQueue *ptr_;
+ LOG(("GarbageCollector throwing out message: %s", ptr->message));
+ ptr_=ptr;
+ ptr=ptr->l.tqe_next;
+ free(MsgQ_RemoveMsg(q, ptr_));
+ i++;
+ continue;
+ }
+ ptr=ptr->l.tqe_next;
+ }
+ LeaveCriticalSection(&q->cs);
+ return i;
+}
diff --git a/protocols/SkypeClassic/msgq.h b/protocols/SkypeClassic/msgq.h
new file mode 100644
index 0000000000..4eb666944b
--- /dev/null
+++ b/protocols/SkypeClassic/msgq.h
@@ -0,0 +1,64 @@
+#include <time.h>
+
+// ----------------------------------------------------------------------
+// Stolen from *nix sys/queue.h
+// ----------------------------------------------------------------------
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+}
+
+#define TAILQ_INSERT_TAIL(head, elm, field) { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+}
+
+#define TAILQ_REMOVE(head, elm, field) { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+}
+// ----------------------------------------------------------------------
+
+struct MsgQueue {
+ TAILQ_ENTRY(MsgQueue) l;
+ char *message;
+ time_t tAdded;
+ time_t tReceived;
+};
+typedef struct
+{
+ TAILQ_HEAD(tag_msgq, MsgQueue) l;
+ CRITICAL_SECTION cs;
+} TYP_MSGQ;
+
+void MsgQ_Init(TYP_MSGQ *q);
+void MsgQ_Exit(TYP_MSGQ *q);
+BOOL MsgQ_Add(TYP_MSGQ *q, char *msg);
+char *MsgQ_RemoveMsg(TYP_MSGQ *q, struct MsgQueue *ptr);
+char *MsgQ_Get(TYP_MSGQ *q);
+int MsgQ_CollectGarbage(TYP_MSGQ *q, time_t age);
diff --git a/protocols/SkypeClassic/pthread.cpp b/protocols/SkypeClassic/pthread.cpp
new file mode 100644
index 0000000000..12da5a7a4f
--- /dev/null
+++ b/protocols/SkypeClassic/pthread.cpp
@@ -0,0 +1,70 @@
+/*
+ * $Id: pthread.c,v 1.4 2003/12/19 12:53:36 gena01 Exp $
+ *
+ * Skype Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * Code borrowed for Skype plugin. Fixed to compile on Mingw by G.Feldman
+ * Original Copyright (c) 2003 Robert Rainwater
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+
+#include "skype.h"
+
+/* Gena01 - added some defined to fix compilation with mingw gcc */
+/* __try/__finally taken from abiword patch found on the web */
+#if 0
+ #include <crtdbg.h>
+#else
+#define __try
+#define __except(x) if (0) /* don't execute handler */
+#define __finally
+
+#define _try __try
+#define _except __except
+#define _finally __finally
+#endif
+
+#include <excpt.h>
+
+struct pthread_arg
+{
+ HANDLE hEvent;
+ void (*threadcode) (void *);
+ void *arg;
+};
+
+void pthread_r(struct pthread_arg *fa)
+{
+ void (*callercode) (void *) = fa->threadcode;
+ void *arg = fa->arg;
+ Thread_Push(0, 0);
+ SetEvent(fa->hEvent);
+ __try {
+ callercode(arg);
+ }
+ __finally {
+ Thread_Pop();
+ }
+}
+
+unsigned long pthread_create(pThreadFunc parFunc, void *arg)
+{
+ unsigned long rc;
+ struct pthread_arg fa;
+ fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ fa.threadcode = parFunc;
+ fa.arg = arg;
+ rc = _beginthread((pThreadFunc) pthread_r, 0, &fa);
+ if ((unsigned long) -1L != rc) {
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ }
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
diff --git a/protocols/SkypeClassic/pthread.h b/protocols/SkypeClassic/pthread.h
new file mode 100644
index 0000000000..1c9f3e3924
--- /dev/null
+++ b/protocols/SkypeClassic/pthread.h
@@ -0,0 +1,26 @@
+/*
+ * $Id: pthread.h,v 1.3 2003/10/05 04:03:05 gena01 Exp $
+ *
+ * Skype Miranda Plugin
+ *
+ * Authors: Gennady Feldman (aka Gena01)
+ * Laurent Marechal (aka Peorth)
+ *
+ * Code borrowed for Skype plugin. Fixed to compile on Mingw by G.Feldman
+ * Original Copyright (c) 2003 Robert Rainwater
+ *
+ * This code is under GPL and is based on AIM, MSN and Miranda source code.
+ * I want to thank Robert Rainwater and George Hazan for their code and support
+ * and for answering some of my questions during development of this plugin.
+ */
+#ifndef PTHREAD_H
+#define PTHREAD_H
+
+unsigned long pthread_create(void (*threadcode) (void *), void *arg);
+typedef CRITICAL_SECTION pthread_mutex_t;
+#define pthread_mutex_init(pmutex) InitializeCriticalSection(pmutex)
+#define pthread_mutex_destroy(pmutex) DeleteCriticalSection(pmutex)
+#define pthread_mutex_lock(pmutex) EnterCriticalSection(pmutex)
+#define pthread_mutex_unlock(pmutex) LeaveCriticalSection(pmutex)
+
+#endif
diff --git a/protocols/SkypeClassic/readme.txt b/protocols/SkypeClassic/readme.txt
new file mode 100644
index 0000000000..333f92d90a
--- /dev/null
+++ b/protocols/SkypeClassic/readme.txt
@@ -0,0 +1,47 @@
+Skype Protocol - Maybe we can call it beta now? ;)
+
+As so many people requested it, here is now a implementation of the Skype
+protocol for Miranda IM.
+Note, that this is just a wrapper for the Skype-API, which means that Skype
+has to be running while you use this plugin.
+The plugin should be able to launch Skype, if it is not running on startup.
+Please note, that I never coded a protocol-plugin for Miranda before, so
+expect it to be buggy and unstable, I hope I have some time to correct the
+severest bugs and to add more features soon.
+No warranty, whatsoever! I suggest that you back up your existing Miranda
+Database before using this plugin, just to be sure you have a backup if
+it runs amok ;-) Feel free to improve the ugly sourcecode.
+Please give me feedback, if it works for you, it would be interesting.
+
+NOTES - READ THEM CAREFULLY!
+----------------------------
+
+ * You need Skype 1.0.0.97 or above in order to have access to the Skype API
+ * You have to manually disable popup of messages in SKYPE, as there is
+ currently no function in the API to do this
+ Got to File/Options/Short messages and disable the checkboxes there
+ Otherwise you would get all Skype-Messages twice (in Skype AND Miranda)
+ * If you always get "Unknown event" when a call is incoming and you are using
+ the NewEventNotify-plugin or Tabsrmm then go to the plugin's options
+ (Sessions / Event Notifications / Announce events of type) and disable
+ "other events" there.
+ * Importing history for a contact can be launched by clickting "import History"
+ in the context menu of a contact. The importing takes place in the background.
+ AS soon, as it's finished, you will be notified by a messagebox.
+ This feature is still buggy and quite a bit unpredictable.
+ * There is a nice Iconset with the original Skype-Icons created by X-Byte
+ Thanks for that. Grab it at http://dose.0wnz.at/Skype/Skype_icons.zip
+ * Skype API bug: When you set Skype offline via API, the contacts stay online
+ I made a Miranda-sie workaround for this now, but it's a Skype-API bug,
+ not a plugin-bug
+ * Skype API bug: when you rename Skypeout-contacts in Skype, their new nicks
+ aren't sent correctly via the API, instead, the previous nick is sent and
+ therefore the Miranda-name is not up-to-date after nick change.
+ This is not a plugin bug either.
+BUGS
+----
+
+ * To track bugs, you have to make a Debug-Build out from the source.
+ The plugin then will log the Skype-API communication to a logfile
+ called skype_log.txt so that we may se what caused the crash.
+
diff --git a/protocols/SkypeClassic/res/8060.ico b/protocols/SkypeClassic/res/8060.ico
new file mode 100644
index 0000000000..0769ddb8b2
--- /dev/null
+++ b/protocols/SkypeClassic/res/8060.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/Copy of online.ico b/protocols/SkypeClassic/res/Copy of online.ico
new file mode 100644
index 0000000000..c9376943cb
--- /dev/null
+++ b/protocols/SkypeClassic/res/Copy of online.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/DND.ico b/protocols/SkypeClassic/res/DND.ico
new file mode 100644
index 0000000000..ace441c3ad
--- /dev/null
+++ b/protocols/SkypeClassic/res/DND.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/Invite.ico b/protocols/SkypeClassic/res/Invite.ico
new file mode 100644
index 0000000000..12af3b8ab8
--- /dev/null
+++ b/protocols/SkypeClassic/res/Invite.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/NA.ico b/protocols/SkypeClassic/res/NA.ico
new file mode 100644
index 0000000000..5bb7dba823
--- /dev/null
+++ b/protocols/SkypeClassic/res/NA.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/add.ico b/protocols/SkypeClassic/res/add.ico
new file mode 100644
index 0000000000..b0e9903bbe
--- /dev/null
+++ b/protocols/SkypeClassic/res/add.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/add2.ico b/protocols/SkypeClassic/res/add2.ico
new file mode 100644
index 0000000000..e7593bb787
--- /dev/null
+++ b/protocols/SkypeClassic/res/add2.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/auth.ico b/protocols/SkypeClassic/res/auth.ico
new file mode 100644
index 0000000000..9bf01c59a4
--- /dev/null
+++ b/protocols/SkypeClassic/res/auth.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/away.ico b/protocols/SkypeClassic/res/away.ico
new file mode 100644
index 0000000000..7993291dcc
--- /dev/null
+++ b/protocols/SkypeClassic/res/away.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/call.bmp b/protocols/SkypeClassic/res/call.bmp
new file mode 100644
index 0000000000..7da6ac53cf
--- /dev/null
+++ b/protocols/SkypeClassic/res/call.bmp
Binary files differ
diff --git a/protocols/SkypeClassic/res/call.ico b/protocols/SkypeClassic/res/call.ico
new file mode 100644
index 0000000000..43516a3c0f
--- /dev/null
+++ b/protocols/SkypeClassic/res/call.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/chat.ico b/protocols/SkypeClassic/res/chat.ico
new file mode 100644
index 0000000000..cf6e01e93d
--- /dev/null
+++ b/protocols/SkypeClassic/res/chat.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/conference.ico b/protocols/SkypeClassic/res/conference.ico
new file mode 100644
index 0000000000..bd6b1518fb
--- /dev/null
+++ b/protocols/SkypeClassic/res/conference.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/error.ico b/protocols/SkypeClassic/res/error.ico
new file mode 100644
index 0000000000..e191cbf754
--- /dev/null
+++ b/protocols/SkypeClassic/res/error.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/hang_up.ico b/protocols/SkypeClassic/res/hang_up.ico
new file mode 100644
index 0000000000..dacfcd4935
--- /dev/null
+++ b/protocols/SkypeClassic/res/hang_up.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/history.ico b/protocols/SkypeClassic/res/history.ico
new file mode 100644
index 0000000000..c406120433
--- /dev/null
+++ b/protocols/SkypeClassic/res/history.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/hold.ico b/protocols/SkypeClassic/res/hold.ico
new file mode 100644
index 0000000000..3ad69006a7
--- /dev/null
+++ b/protocols/SkypeClassic/res/hold.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/import.ico b/protocols/SkypeClassic/res/import.ico
new file mode 100644
index 0000000000..863d45cd6b
--- /dev/null
+++ b/protocols/SkypeClassic/res/import.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/invisible.ico b/protocols/SkypeClassic/res/invisible.ico
new file mode 100644
index 0000000000..b734f6a495
--- /dev/null
+++ b/protocols/SkypeClassic/res/invisible.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/message.ico b/protocols/SkypeClassic/res/message.ico
new file mode 100644
index 0000000000..c4ca27be54
--- /dev/null
+++ b/protocols/SkypeClassic/res/message.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/occupied.ico b/protocols/SkypeClassic/res/occupied.ico
new file mode 100644
index 0000000000..a0baafec21
--- /dev/null
+++ b/protocols/SkypeClassic/res/occupied.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/offline.ico b/protocols/SkypeClassic/res/offline.ico
new file mode 100644
index 0000000000..e26af6fdec
--- /dev/null
+++ b/protocols/SkypeClassic/res/offline.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/online.ico b/protocols/SkypeClassic/res/online.ico
new file mode 100644
index 0000000000..ae1a3df64f
--- /dev/null
+++ b/protocols/SkypeClassic/res/online.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/pause.ico b/protocols/SkypeClassic/res/pause.ico
new file mode 100644
index 0000000000..de366073da
--- /dev/null
+++ b/protocols/SkypeClassic/res/pause.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/phone.ico b/protocols/SkypeClassic/res/phone.ico
new file mode 100644
index 0000000000..1a13073ce6
--- /dev/null
+++ b/protocols/SkypeClassic/res/phone.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/resume.ico b/protocols/SkypeClassic/res/resume.ico
new file mode 100644
index 0000000000..294bad488e
--- /dev/null
+++ b/protocols/SkypeClassic/res/resume.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/search.ico b/protocols/SkypeClassic/res/search.ico
new file mode 100644
index 0000000000..e28bef60e1
--- /dev/null
+++ b/protocols/SkypeClassic/res/search.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/skype.ico b/protocols/SkypeClassic/res/skype.ico
new file mode 100644
index 0000000000..b267bbb5fc
--- /dev/null
+++ b/protocols/SkypeClassic/res/skype.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/skypeout.ico b/protocols/SkypeClassic/res/skypeout.ico
new file mode 100644
index 0000000000..6d135bae96
--- /dev/null
+++ b/protocols/SkypeClassic/res/skypeout.ico
Binary files differ
diff --git a/protocols/SkypeClassic/res/skyping.ico b/protocols/SkypeClassic/res/skyping.ico
new file mode 100644
index 0000000000..59fdb4482d
--- /dev/null
+++ b/protocols/SkypeClassic/res/skyping.ico
Binary files differ
diff --git a/protocols/SkypeClassic/resource.h b/protocols/SkypeClassic/resource.h
new file mode 100644
index 0000000000..5f57feb9a3
--- /dev/null
+++ b/protocols/SkypeClassic/resource.h
@@ -0,0 +1,124 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Skript1.rc
+//
+#define IDI_SKYPE 102
+#define IDI_ONLINE 104
+#define IDI_OFFLINE 105
+#define IDI_AWAY 128
+#define IDI_CHAT 129
+#define IDI_INVISIBLE 130
+#define IDI_NA 131
+#define IDI_DND 158
+#define IDI_OCCUPIED 159
+#define IDI_ADD 160
+#define IDI_IMPORT 161
+#define IDI_ERRORS 162
+#define IDI_MESSAGE 163
+#define IDI_CALL 164
+#define IDI_CALLSKYPEOUT 165
+#define IDI_HOLD 166
+#define IDI_RESUME 167
+#define IDI_HANGUP 168
+#define IDI_AVATAR 169
+#define IDD_OPTIONS 170
+#define IDI_INVITE 170
+#define IDD_DIAL 171
+#define IDB_CALL 172
+#define IDD_INPUTBOX 172
+#define IDD_CALLSTAT 173
+#define IDD_SETAVATAR 174
+#define IDD_OPT_DEFAULT 175
+#define IDD_OPT_PROXY 176
+#define IDD_SETDETAILS 177
+#define IDD_OPT_ADVANCED 178
+#define IDD_OPT_POPUP 179
+#define IDI_PHONE 1002
+#define IDC_SHUTDOWN 1004
+#define IDC_ENABLEMENU 1005
+#define IDC_UNLOADOFFLINE 1006
+#define IDC_USES2S 1007
+#define IDC_HOST 1008
+#define IDC_PORT 1009
+#define IDC_REQPASS 1010
+#define IDC_PASSWORD 1011
+#define IDC_USEPOPUP 1012
+#define IDC_GROUPCHAT 1014
+#define IDC_NOERRORS 1015
+#define IDC_CONNATTEMPTS 1016
+#define IDC_GROUPCHATREAD 1016
+#define IDC_SKYPEOUTSTAT 1018
+#define IDC_NUMBER 1019
+#define IDDIAL 1020
+#define IDC_KEEPSTATE 1021
+#define IDC_CLEANUP 1022
+#define IDC_JOIN 1023
+#define IDC_TIMEZONE 1023
+#define IDC_HOLD 1024
+#define IDC_SHOWDEFAULTAVATAR 1024
+#define IDC_HANGUP 1025
+#define IDC_IGNTZ 1025
+#define IDC_AVATAR 1026
+#define IDC_NOSKYPE3STATS 1026
+#define IDC_SETAVATAR 1027
+#define IDC_SHOWFULLNAME 1027
+#define IDC_DELETEAVATAR 1028
+#define IDC_STARTSKYPE 1029
+#define IDC_NOTRAY 1030
+#define IDC_NOSPLASH 1031
+#define IDC_MINIMIZED 1032
+#define IDC_TEXT 1033
+#define IDC_CUSTOMCOMMAND 1033
+#define IDC_OPTIONSTAB 1034
+#define IDC_REMOVEABLE 1034
+#define IDC_FULLNAME 1035
+#define IDC_DATAPATHO 1035
+#define IDC_BIRTHDAY 1036
+#define IDC_SECONDARY 1036
+#define IDC_SEX 1037
+#define IDC_CITY 1038
+#define IDC_COUNTRY 1039
+#define IDC_PROVINCE 1040
+#define IDC_HOMEPHONE 1041
+#define IDC_OFFICEPHONE 1042
+#define IDC_HOMEPAGE 1043
+#define IDC_SAVEDETAILS 1044
+#define IDC_COMMANDLINE 1045
+#define IDC_DATAPATH 1046
+#define IDC_POPUPINCOMING 1049
+#define IDC_PREVIEW 1050
+#define IDC_POPUPTEXTCOLOR 1051
+#define IDC_POPUPTIME 1052
+#define IDC_POPUPBACKCOLOR 1053
+#define IDC_USEWINCOLORS 1054
+#define IDC_POPUPERROR 1055
+#define IDC_USERNAME 1055
+#define IDC_PREVIEWERR 1056
+#define IDC_EDIT2 1056
+#define IDC_POPUPTIMEERR 1057
+#define IDC_POPUPBACKCOLORERR 1058
+#define IDC_POPUPTEXTCOLORERR 1059
+#define IDC_USEWINCOLORSERR 1060
+#define IDC_SUPPRESSCALLSUMMARYMESSAGE 1061
+#define IDC_AUTODETECTION 1062
+#define IDC_STATIC_HOST 1063
+#define IDC_STATIC_PORT 1064
+#define IDC_BROWSEDP 1065
+#define IDC_BROWSECMDL 1066
+#define IDC_STATIC_POPUPBACKCOLOR 1066
+#define IDC_STATIC_POPUPTEXTCOLOR 1067
+#define IDC_STATIC_POPUPTEXTCOLORERR 1068
+#define IDC_STATIC_POPUPBACKCOLORERR 1069
+#define IDC_STATIC_PATHINFO 1070
+#define IDC_STATIC_RESTART 1071
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 181
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1072
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/SkypeClassic/skype.cpp b/protocols/SkypeClassic/skype.cpp
new file mode 100644
index 0000000000..495ff50da2
--- /dev/null
+++ b/protocols/SkypeClassic/skype.cpp
@@ -0,0 +1,3381 @@
+/*
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+*/
+
+#include "skype.h"
+#include "debug.h"
+#include "skypeapi.h"
+#include "skypesvc.h"
+#include "contacts.h"
+#include "utf8.h"
+#include "pthread.h"
+#include "gchat.h"
+#include "m_toptoolbar.h"
+#include "voiceservice.h"
+#include "msglist.h"
+#include "memlist.h"
+#include <sys/timeb.h>
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
+#endif
+#ifdef _WIN64
+ #if (_MSC_VER < 1500)
+ #pragma comment (lib, "bufferoverflowU.lib")
+ #endif
+#endif
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+POPUPDATAT MessagePopup;
+
+// Exported Globals
+HWND hSkypeWnd=NULL, g_hWnd=NULL, hSkypeWndSecondary=NULL, hForbiddenSkypeWnd = NULL;
+HANDLE SkypeReady, SkypeMsgReceived, hInitChat=NULL, httbButton=NULL, FetchMessageEvent=NULL;
+BOOL SkypeInitialized=FALSE, MirandaShuttingDown=FALSE, PopupServiceExists=FALSE;
+BOOL UseSockets=FALSE, bSkypeOut=FALSE, bProtocolSet=FALSE, bIsImoproxy=FALSE;
+char skype_path[MAX_PATH], protocol=2, *pszProxyCallout=NULL, g_szProtoName[_MAX_FNAME]="SkypeClassic";
+int SkypeStatus=ID_STATUS_OFFLINE, hSearchThread=-1, receivers=1;
+long sendwatchers = 0, rcvwatchers = 0;
+UINT ControlAPIAttach, ControlAPIDiscover;
+LONG AttachStatus=-1;
+HINSTANCE hInst;
+HANDLE hProtocolAvatarsFolder;
+char DefaultAvatarsFolder[MAX_PATH+1];
+DWORD mirandaVersion;
+int hLangpack = 0;
+
+CRITICAL_SECTION RingAndEndcallMutex, QueryThreadMutex, TimeMutex;
+
+// Module Internal Globals
+HANDLE MessagePumpReady;
+HANDLE hChatEvent=NULL, hChatMenu=NULL;
+HANDLE hEvInitChat=NULL, hBuddyAdded=NULL;
+HANDLE hMenuAddSkypeContact=NULL;
+
+DWORD msgPumpThreadId = 0;
+#ifdef SKYPEBUG_OFFLN
+HANDLE GotUserstatus;
+#endif
+
+BOOL bModulesLoaded=FALSE;
+char *RequestedStatus=NULL; // To fix Skype-API Statusmode-bug
+char cmdMessage[12]="MESSAGE", cmdPartner[8]="PARTNER"; // Compatibility commands
+
+
+
+// Direct assignment of user properties to a DB-Setting
+static const settings_map m_settings[]= {
+ {"LANGUAGE", "Language1"},
+ {"PROVINCE", "State"},
+ {"CITY", "City"},
+ {"PHONE_HOME", "Phone"},
+ {"PHONE_OFFICE", "CompanyPhone"},
+ {"PHONE_MOBILE", "Cellular"},
+ {"HOMEPAGE", "Homepage"},
+ {"ABOUT", "About"}
+ };
+
+// Imported Globals
+extern status_map status_codes[];
+
+BOOL (WINAPI *MyEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
+
+HMODULE hUxTheme = 0;
+
+// function pointers, use typedefs for casting to shut up the compiler when using GetProcAddress()
+
+typedef BOOL (WINAPI *PITA)();
+typedef HANDLE (WINAPI *POTD)(HWND, LPCWSTR);
+typedef UINT (WINAPI *PDTB)(HANDLE, HDC, int, int, RECT *, RECT *);
+typedef UINT (WINAPI *PCTD)(HANDLE);
+typedef UINT (WINAPI *PDTT)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, DWORD, RECT *);
+
+PITA pfnIsThemeActive = 0;
+POTD pfnOpenThemeData = 0;
+PDTB pfnDrawThemeBackground = 0;
+PCTD pfnCloseThemeData = 0;
+PDTT pfnDrawThemeText = 0;
+
+#define FIXED_TAB_SIZE 100 // default value for fixed width tabs
+
+typedef struct {
+ char msgnum[16];
+ BOOL getstatus;
+ BOOL bIsRead;
+ BOOL bDontMarkSeen;
+ BOOL QueryMsgDirection;
+ TYP_MSGLENTRY *pMsgEntry;
+} fetchmsg_arg;
+
+typedef struct {
+ HANDLE hContact;
+ char szId[16];
+} msgsendwt_arg;
+
+/*
+ * visual styles support (XP+)
+ * returns 0 on failure
+ */
+
+int InitVSApi()
+{
+ if((hUxTheme = LoadLibraryA("uxtheme.dll")) == 0)
+ return 0;
+
+ pfnIsThemeActive = (PITA)GetProcAddress(hUxTheme, "IsThemeActive");
+ pfnOpenThemeData = (POTD)GetProcAddress(hUxTheme, "OpenThemeData");
+ pfnDrawThemeBackground = (PDTB)GetProcAddress(hUxTheme, "DrawThemeBackground");
+ pfnCloseThemeData = (PCTD)GetProcAddress(hUxTheme, "CloseThemeData");
+ pfnDrawThemeText = (PDTT)GetProcAddress(hUxTheme, "DrawThemeText");
+
+ MyEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+ if(pfnIsThemeActive != 0 && pfnOpenThemeData != 0 && pfnDrawThemeBackground != 0 && pfnCloseThemeData != 0 && pfnDrawThemeText != 0) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * unload uxtheme.dll
+ */
+
+int FreeVSApi()
+{
+ if(hUxTheme != 0)
+ FreeLibrary(hUxTheme);
+ return 0;
+}
+
+// Plugin Info
+PLUGININFOEX pluginInfo = {
+ sizeof(PLUGININFOEX),
+ "Skype Protocol",
+ PLUGIN_MAKE_VERSION(0,0,0,54),
+ "Support for Skype network",
+ "leecher - tweety - jls17",
+ "leecher@dose.0wnz.at - tweety@user.berlios.de",
+ "© 2004-2012 leecher - tweety",
+ "http://developer.berlios.de/projects/mgoodies/",
+ UNICODE_AWARE,
+ { 0xa71f8335, 0x7b87, 0x4432, { 0xb8, 0xa3, 0x81, 0x47, 0x94, 0x31, 0xc6, 0xf5 } } // {A71F8335-7B87-4432-B8A3-81479431C6F5}
+};
+
+#define MAPDND 1 // Map Occupied to DND status and say that you support it
+//#define MAPNA 1 // Map NA status to Away and say that you support it
+
+/* P R O G R A M */
+
+void RegisterToDbeditorpp(void)
+{
+ // known modules list
+ if (ServiceExists("DBEditorpp/RegisterSingleModule"))
+ CallService("DBEditorpp/RegisterSingleModule", (WPARAM)SKYPE_PROTONAME, 0);
+}
+
+/*
+ * ShowMessage
+ *
+ * Shows a popup, if the popup plugin is enabled.
+ * mustShow: 1 -> If Popup-Plugin is not available/disabled, show Message
+ * in a Messagewindow
+ * If the Popup-Plugin is enabled, let the message stay on
+ * screen until someone clicks it away.
+ * 0 -> If Popup-Plugin is not available/disabled, skip message
+ * Returns 0 on success, -1 on failure
+ *
+ */
+int ShowMessage(int iconID, TCHAR *lpzText, int mustShow) {
+
+
+
+ if (db_get_b(NULL, SKYPE_PROTONAME, "SuppressErrors", 0)) return -1;
+ lpzText=TranslateTS(lpzText);
+
+ if (bModulesLoaded && PopupServiceExists && ServiceExists(MS_POPUP_ADDPOPUPT) && db_get_b(NULL, SKYPE_PROTONAME, "UsePopup", 0) && !MirandaShuttingDown) {
+ BOOL showPopup, popupWindowColor;
+ unsigned int popupBackColor, popupTextColor;
+ int popupTimeSec;
+
+ popupTimeSec = db_get_dw(NULL, SKYPE_PROTONAME, "popupTimeSecErr", 4);
+ popupTextColor = db_get_dw(NULL, SKYPE_PROTONAME, "popupTextColorErr", GetSysColor(COLOR_WINDOWTEXT));
+ popupBackColor = db_get_dw(NULL, SKYPE_PROTONAME, "popupBackColorErr", GetSysColor(COLOR_BTNFACE));
+ popupWindowColor = ( 0 != db_get_b(NULL, SKYPE_PROTONAME, "popupWindowColorErr", TRUE));
+ showPopup = ( 0 != db_get_b(NULL, SKYPE_PROTONAME, "showPopupErr", TRUE));
+
+ MessagePopup.lchContact = NULL;
+ MessagePopup.lchIcon = LoadIcon(hInst,MAKEINTRESOURCE(iconID));
+ MessagePopup.colorBack = ! popupWindowColor ? popupBackColor : GetSysColor(COLOR_BTNFACE);
+ MessagePopup.colorText = ! popupWindowColor ? popupTextColor : GetSysColor(COLOR_WINDOWTEXT);
+ MessagePopup.iSeconds = popupTimeSec;
+ MessagePopup.PluginData = (void *)1;
+
+ lstrcpy(MessagePopup.lptzText, lpzText);
+
+#ifdef _UNICODE
+ mbstowcs (MessagePopup.lptzContactName, SKYPE_PROTONAME, strlen(SKYPE_PROTONAME)+1);
+#else
+ lstrcpy(MessagePopup.lptzContactName, SKYPE_PROTONAME);
+#endif
+
+ if(showPopup)
+ CallService(MS_POPUP_ADDPOPUPT,(WPARAM)&MessagePopup,0);
+
+ return 0;
+ }
+ else {
+
+ if (mustShow==1) MessageBox(NULL,lpzText,_T("Skype Protocol"), MB_OK | MB_ICONWARNING);
+ return 0;
+ }
+}
+#ifdef _UNICODE
+int ShowMessageA(int iconID, char *lpzText, int mustShow) {
+ WCHAR *lpwText;
+ int iRet;
+ size_t len = mbstowcs (NULL, lpzText, strlen(lpzText));
+ if (len == -1 || !(lpwText = (WCHAR*)calloc(len+1,sizeof(WCHAR)))) return -1;
+ mbstowcs (lpwText, lpzText, strlen(lpzText));
+ iRet = ShowMessage(iconID, lpwText, mustShow);
+ free (lpwText);
+ return iRet;
+}
+#endif
+
+// processing Hooks
+
+int HookContactAdded(WPARAM wParam, LPARAM lParam) {
+ char *szProto;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME))
+ add_contextmenu((HANDLE)wParam);
+ return 0;
+}
+
+int HookContactDeleted(WPARAM wParam, LPARAM lParam) {
+ char *szProto;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME)) {
+ DBVARIANT dbv;
+ int retval;
+
+ if (db_get_s((HANDLE)wParam, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) return 1;
+ retval=SkypeSend("SET USER %s BUDDYSTATUS 1", dbv.pszVal);
+ db_free(&dbv);
+ if (retval) return 1;
+ }
+ return 0;
+}
+
+void GetInfoThread(HANDLE hContact) {
+ DBVARIANT dbv;
+ int i;
+ char *ptr;
+ BOOL bSetNick = FALSE;
+ // All properties are already handled in the WndProc, so we just consume the
+ // messages here to do proper ERROR handling
+ // If you add something here, be sure to handle it in WndProc, but let it
+ // fall through there so that message gets added to the queue in order to be
+ // consumed by SkypeGet
+ char *pszProps[] = {
+ "BIRTHDAY", "COUNTRY", "SEX", "MOOD_TEXT", "TIMEZONE", "IS_VIDEO_CAPABLE"};
+
+
+ LOG (("GetInfoThread started."));
+ EnterCriticalSection (&QueryThreadMutex);
+ if (db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ {
+ LOG (("GetInfoThread terminated, cannot find Skype Name for contact %08X.", hContact));
+ LeaveCriticalSection (&QueryThreadMutex);
+ return;
+ }
+
+ if (ptr=SkypeGet ("USER", dbv.pszVal, "DISPLAYNAME")) {
+ // WndProc sets Nick accordingly
+ if (*ptr) bSetNick = TRUE;
+ free (ptr);
+ }
+
+ if (ptr=SkypeGet ("USER", dbv.pszVal, "FULLNAME")) {
+ if (*ptr && !bSetNick && db_get_b(NULL, SKYPE_PROTONAME, "ShowFullname", 1)) {
+ // No Displayname and FULLNAME requested
+ db_set_utf(hContact, SKYPE_PROTONAME, "Nick", ptr);
+ bSetNick = TRUE;
+ }
+ free (ptr);
+ }
+
+ if (!bSetNick) {
+ // Still no nick set, so use SKYPE Nickname
+ db_set_s(hContact, SKYPE_PROTONAME, "Nick", dbv.pszVal);
+ }
+
+
+ if (!bIsImoproxy)
+ {
+ for (i=0; i<sizeof(pszProps)/sizeof(pszProps[0]); i++)
+ if (ptr=SkypeGet ("USER", dbv.pszVal, pszProps[i])) free (ptr);
+ } else {
+ if (ptr=SkypeGet ("USER", dbv.pszVal, "MOOD_TEXT")) free (ptr);
+ }
+
+ if (protocol >= 7 || bIsImoproxy) {
+ // Notify about the possibility of an avatar
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = SKYPE_PROTONAME;
+ ack.hContact = hContact;
+ ack.type = ACKTYPE_AVATAR;
+ ack.result = ACKRESULT_STATUS;
+
+ CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+ //if (ptr=SkypeGet ("USER", dbv.pszVal, "RICH_MOOD_TEXT")) free (ptr);
+ }
+
+ if (!bIsImoproxy)
+ {
+ for (i=0; i<sizeof(m_settings)/sizeof(m_settings[0]); i++)
+ if (ptr=SkypeGet ("USER", dbv.pszVal, m_settings[i].SkypeSetting)) free (ptr);
+ }
+
+ ProtoBroadcastAck(SKYPE_PROTONAME, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ LeaveCriticalSection(&QueryThreadMutex);
+ db_free(&dbv);
+ LOG (("GetInfoThread terminated gracefully."));
+}
+
+time_t SkypeTime(time_t *timer) {
+ struct _timeb tb;
+
+ EnterCriticalSection (&TimeMutex);
+ _ftime(&tb);
+ if (timer) *timer=tb.time;
+ LeaveCriticalSection (&TimeMutex);
+ return tb.time;
+}
+
+
+void BasicSearchThread(char *nick) {
+ PROTOSEARCHRESULT psr={0};
+ char *cmd=NULL, *token=NULL, *ptr=NULL, *nextoken;
+ time_t st;
+
+ LOG (("BasicSearchThread started."));
+ EnterCriticalSection (&QueryThreadMutex);
+ SkypeTime(&st);
+ if (SkypeSend("SEARCH USERS %s", nick)==0 && (cmd=SkypeRcvTime("USERS", st, INFINITE))) {
+ if (strncmp(cmd, "ERROR", 5)) {
+ psr.cbSize=sizeof(psr);
+ for (token=strtok_r(cmd+5, ", ", &nextoken); token; token=strtok_r(NULL, ", ", &nextoken)) {
+ psr.nick=psr.id=_A2T(token);
+ psr.lastName=NULL;
+ psr.firstName=NULL;
+ psr.email=NULL;
+ if (ptr=SkypeGet("USER", token, "FULLNAME")) {
+ // We cannot use strtok() to seperate first & last name here,
+ // because we already use it for parsing the user list
+ // So we use our own function
+ if (psr.lastName=_A2T(strchr(ptr, ' '))) {
+ *psr.lastName=0;
+ psr.lastName++;
+ LOG(("BasicSearchThread: lastName=%s", psr.lastName));
+ }
+ psr.firstName=_A2T(ptr);
+ LOG(("BasicSearchThread: firstName=%s", psr.firstName));
+ }
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)hSearchThread, (LPARAM)(PROTOSEARCHRESULT*)&psr);
+ if (ptr) free(ptr);
+ }
+ } else {
+ OUT(cmd);
+ }
+ free(cmd);
+ }
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)hSearchThread, 0);
+ free(nick);
+ LeaveCriticalSection(&QueryThreadMutex);
+ LOG (("BasicSearchThread terminated gracefully."));
+ return;
+}
+
+// added by TioDuke
+void GetDisplaynameThread(char *dummy) {
+ DBVARIANT dbv;
+ char *ptr;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ LOG(("GetDisplaynameThread started."));
+ if (db_get_s(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) {
+ LOG(("GetDisplaynameThread terminated."));
+ return;
+ }
+ EnterCriticalSection(&QueryThreadMutex);
+ if ((ptr=SkypeGet("USER", dbv.pszVal, "FULLNAME"))) {
+ if (*ptr) db_set_utf(NULL, SKYPE_PROTONAME, "Nick", ptr);
+ free(ptr);
+ }
+ db_free(&dbv);
+ LeaveCriticalSection(&QueryThreadMutex);
+ LOG(("GetDisplaynameThread terminated gracefully."));
+}
+
+
+// Starts importing history from Skype
+INT_PTR ImportHistory(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (db_get_b((HANDLE)wParam, SKYPE_PROTONAME, "ChatRoom", 0)) {
+ if (db_get_s((HANDLE)wParam, SKYPE_PROTONAME, "ChatRoomID", &dbv)) return 0;
+ SkypeSend ("GET CHAT %s CHATMESSAGES", dbv.pszVal);
+ } else {
+ if (db_get_s((HANDLE)wParam, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) return 0;
+ SkypeSend("SEARCH %sS %s", cmdMessage, dbv.pszVal);
+ }
+ db_free(&dbv);
+ return 0;
+}
+
+int SearchFriends(void) {
+ char *ptr, *token, *pStat, *nextoken;
+ int iRet = 0;
+ time_t st;
+
+ SkypeTime(&st);
+ if (SkypeSend("SEARCH FRIENDS")!=-1 && (ptr=SkypeRcvTime("USERS", st, INFINITE)))
+ {
+ if (strncmp(ptr, "ERROR", 5)) {
+ if (ptr+5) {
+ for (token=strtok_r(ptr+5, ", ", &nextoken); token; token=strtok_r(NULL, ", ", &nextoken)) {
+ if (!(pStat = SkypeGet("USER", token, "ONLINESTATUS")))
+ {
+ iRet = -1;
+ break;
+ }
+ free (pStat);
+ }
+ }
+ } else iRet=-1;
+ free(ptr);
+ } else iRet=-1;
+ return iRet;
+}
+
+void __cdecl SearchUsersWaitingMyAuthorization(void *dummy) {
+ char *cmd, *token, *nextoken;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ if (SkypeSend("#UWA SEARCH USERSWAITINGMYAUTHORIZATION")) return;
+ if (!(cmd=SkypeRcv("#UWA USERS", INFINITE))) return;
+ if (!strncmp(cmd, "ERROR", 5)) {
+ free(cmd);
+ return;
+ }
+
+ token=strtok_r(cmd+10, ", ", &nextoken);
+ while (token) {
+ CCSDATA ccs={0};
+ PROTORECVEVENT pre={0};
+ HANDLE hContact;
+ char *firstname=NULL, *lastname=NULL, *pCurBlob;
+
+ LOG(("Awaiting auth: %s", token));
+ ccs.szProtoService=PSR_AUTH;
+ ccs.hContact=hContact=add_contact(token, PALF_TEMPORARY);
+ ccs.wParam=0;
+ ccs.lParam=(LPARAM)&pre;
+ pre.flags=0;
+ pre.timestamp=(DWORD)SkypeTime(NULL);
+
+ /* blob is: */
+ //DWORD protocolSpecific HANDLE hContact
+ //ASCIIZ nick, firstName, lastName, e-mail, requestReason
+ if (firstname=SkypeGet("USER", token, "FULLNAME"))
+ if (lastname=strchr(firstname, ' ')) {
+ *lastname=0;
+ lastname++;
+ }
+
+ pre.lParam=sizeof(DWORD)+sizeof(HANDLE)+strlen(token)+5;
+ if (firstname) pre.lParam+=strlen(firstname);
+ if (lastname) pre.lParam+=strlen(lastname);
+ if (pre.szMessage = pCurBlob = (char *)calloc(1, pre.lParam)) {
+ pCurBlob+=sizeof(DWORD); // Not used
+ memcpy(pCurBlob,&hContact,sizeof(HANDLE)); pCurBlob+=sizeof(HANDLE);
+ strcpy((char *)pCurBlob,token); pCurBlob+=strlen((char *)pCurBlob)+1;
+ if (firstname) {
+ strcpy((char *)pCurBlob,firstname);
+ if (lastname) {
+ pCurBlob+=strlen((char *)pCurBlob)+1;
+ strcpy((char *)pCurBlob,lastname);
+ }
+ }
+ CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);
+ free(pre.szMessage);
+ }
+ if (firstname) free(firstname);
+ token=strtok_r(NULL, ", ", &nextoken);
+ }
+ free(cmd);
+ return;
+}
+
+void SearchFriendsThread(char *dummy) {
+ UNREFERENCED_PARAMETER(dummy);
+
+ if (!SkypeInitialized) return;
+ LOG(("SearchFriendsThread started."));
+ EnterCriticalSection(&QueryThreadMutex);
+ SkypeInitialized=FALSE;
+ SearchFriends();
+ SkypeInitialized=TRUE;
+ LeaveCriticalSection(&QueryThreadMutex);
+ LOG(("SearchFriendsThread terminated gracefully."));
+}
+
+void __cdecl SearchRecentChats(void *dummy) {
+ char *cmd, *token, *nextoken;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ if (SkypeSend("#RCH SEARCH RECENTCHATS")) return;
+ if (!(cmd=SkypeRcv("#RCH CHATS", INFINITE))) return;
+ if (!strncmp(cmd, "ERROR", 5)) {
+ free(cmd);
+ return;
+ }
+
+ for (token=strtok_r(cmd+10, ", ", &nextoken); token; token=strtok_r(NULL, ", ", &nextoken)) {
+ char *pszStatus = SkypeGet ("CHAT", token, "STATUS");
+
+ if (pszStatus) {
+ if (!strcmp(pszStatus, "MULTI_SUBSCRIBED")) {
+ // Add chatrooms for active multisubscribed chats
+ /*if (!find_chatA(token)) */{
+ char *pszTopic;
+
+ EnterCriticalSection (&QueryThreadMutex);
+ ChatStart(token, TRUE);
+ if (pszTopic = SkypeGet ("CHAT", token, "TOPIC")) {
+ TCHAR *psztChatName, *psztTopic;
+
+ if (!*pszTopic) {
+ free (pszTopic);
+ pszTopic = SkypeGet ("CHAT", token, "FRIENDLYNAME");
+ }
+ psztChatName = make_nonutf_tchar_string((const unsigned char*)token);
+ psztTopic = make_tchar_string((const unsigned char*)pszTopic);
+ SetChatTopic (psztChatName, psztTopic, FALSE);
+ free_nonutf_tchar_string(psztChatName);
+ free (psztTopic);
+ free (pszTopic);
+ }
+ LeaveCriticalSection (&QueryThreadMutex);
+ }
+ }
+ free (pszStatus);
+ }
+ }
+ free(cmd);
+ return;
+}
+
+
+void __cdecl SkypeSystemInit(char *dummy) {
+ static BOOL Initializing=FALSE;
+ DBVARIANT dbv={0};
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ LOG (("SkypeSystemInit thread started."));
+ if (SkypeInitialized || Initializing)
+ {
+ LOG (("SkypeSystemInit terminated, nothing to do."));
+ return;
+ }
+ Initializing=TRUE;
+// Do initial Skype-Tasks
+ logoff_contacts(FALSE);
+// Add friends
+
+ // Clear currentuserhandle entries from queue
+ while (testfor ("CURRENTUSERHANDLE", 0));
+ if (SkypeSend(SKYPE_PROTO)==-1 || !testfor("PROTOCOL", INFINITE) ||
+ SkypeSend("GET CURRENTUSERHANDLE")==-1 ||
+ SkypeSend("GET PRIVILEGE SKYPEOUT")==-1) {
+ Initializing=FALSE;
+ LOG (("SkypeSystemInit thread stopped with failure."));
+ return;
+ }
+
+ if(db_get_s(NULL,SKYPE_PROTONAME,"LoginUserName",&dbv) == 0)
+ {
+ if (*dbv.pszVal)
+ {
+ char *pszUser;
+
+ // Username is set in Plugin, therefore we need to match it
+ // against CURRENTUSERHANDLE
+ if (pszUser = SkypeRcv ("CURRENTUSERHANDLE", INFINITE))
+ {
+ memmove (pszUser, pszUser+18, strlen(pszUser+17));
+ if (_stricmp(dbv.pszVal, pszUser))
+ {
+ char szError[256];
+
+ // Doesn't match, maybe we have a second Skype instance we have to take
+ // care of? If in doubt, let's wait a while for it to report its hWnd to us.
+ LOG (("Userhandle %s doesn't match username %s from settings", pszUser, dbv.pszVal));
+ if (!hSkypeWndSecondary) Sleep(3000);
+ if (hSkypeWndSecondary)
+ {
+ hSkypeWnd = hSkypeWndSecondary;
+ hSkypeWndSecondary = NULL;
+ Initializing=FALSE;
+ while (testfor ("CURRENTUSERHANDLE", 0));
+ LOG (("Trying to init secondary Skype instance"));
+ SkypeSystemInit(dummy);
+ }
+ else
+ {
+ hForbiddenSkypeWnd = hSkypeWnd;
+
+ // If we need to start Skype as secondary instance, we should do it now
+ if (db_get_b(NULL, SKYPE_PROTONAME, "StartSkype", 1) &&
+ db_get_b(NULL, SKYPE_PROTONAME, "secondary", 0))
+ {
+ int oldstatus;
+
+ hSkypeWnd = NULL;
+ AttachStatus=-1;
+ if (g_hWnd) KillTimer (g_hWnd, 1);
+ oldstatus = SkypeStatus;
+ InterlockedExchange((long *)&SkypeStatus, ID_STATUS_CONNECTING);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ ConnectToSkypeAPI(skype_path, 1);
+ }
+ if (hForbiddenSkypeWnd == hSkypeWnd && !hSkypeWndSecondary)
+ {
+ int oldstatus;
+
+ sprintf (szError, "Username '%s' provided by Skype API doesn't match username '%s' in "
+ "your settings. Please either remove username setting in you configuration or correct "
+ "it. Will not connect!", pszUser, dbv.pszVal);
+ OUTPUTA (szError);
+ Initializing=FALSE;
+ AttachStatus=-1;
+ logoff_contacts(FALSE);
+ if (g_hWnd) KillTimer (g_hWnd, 1);
+ hSkypeWnd = NULL;
+ oldstatus = SkypeStatus;
+ InterlockedExchange((long *)&SkypeStatus, ID_STATUS_OFFLINE);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ }
+ }
+ }
+ free (pszUser);
+ }
+ }
+ db_free(&dbv);
+ if (!Initializing) return;
+ }
+
+#ifdef SKYPEBUG_OFFLN
+ if (!ResetEvent(GotUserstatus) || SkypeSend("GET USERSTATUS")==-1 ||
+ WaitForSingleObject(GotUserstatus, INFINITE)==WAIT_FAILED)
+ {
+ LOG (("SkypeSystemInit thread stopped with failure."));
+ Initializing=FALSE;
+ return;
+ }
+ if (SkypeStatus!=ID_STATUS_OFFLINE)
+#endif
+ if (SearchFriends()==-1) {
+ LOG (("SkypeSystemInit thread stopped with failure."));
+ Initializing=FALSE;
+ return;
+ }
+ if (protocol>=5 || bIsImoproxy) {
+ SkypeSend ("CREATE APPLICATION libpurple_typing");
+ testfor ("CREATE APPLICATION libpurple_typing", 2000);
+ }
+ if (protocol>=5 || bIsImoproxy) {
+ SearchUsersWaitingMyAuthorization(NULL);
+ if (db_get_b(NULL, SKYPE_PROTONAME, "UseGroupchat", 0))
+ SearchRecentChats(NULL);
+ }
+ SkypeSend("SEARCH MISSED%sS", cmdMessage);
+
+
+#ifndef SKYPEBUG_OFFLN
+ if (SkypeSend("GET USERSTATUS")==-1)
+ {
+ LOG (("SkypeSystemInit thread stopped with failure."));
+ Initializing=FALSE;
+ return;
+ }
+#endif
+ SetTimer (g_hWnd, 1, PING_INTERVAL, NULL);
+ SkypeInitialized=TRUE;
+ Initializing=FALSE;
+ LOG (("SkypeSystemInit thread terminated gracefully."));
+ return;
+}
+
+void FirstLaunch(char *dummy) {
+ int counter=0;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ LOG (("FirstLaunch thread started."));
+ if (!db_get_b(NULL, SKYPE_PROTONAME, "StartSkype", 1) || ConnectToSkypeAPI(skype_path, FALSE)==-1)
+ {
+ int oldstatus=SkypeStatus;
+
+ LOG(("OnModulesLoaded starting offline.."));
+ InterlockedExchange((long *)&SkypeStatus, ID_STATUS_OFFLINE);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ }
+ if (AttachStatus==-1 || AttachStatus==SKYPECONTROLAPI_ATTACH_REFUSED || AttachStatus==SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE) {
+ LOG (("FirstLaunch thread stopped because of invalid Attachstatus."));
+ return;
+ }
+
+ // When you launch Skype and Attach is Successfull, it still takes some time
+ // until it becomes available for receiving messages.
+ // Let's probe this with PINGing
+ LOG(("CheckIfApiIsResponding Entering test loop"));
+ for ( ;; ) {
+ LOG(("Test #%d", counter));
+ if (SkypeSend("PING")==-1) counter ++; else break;
+ if (counter>=20) {
+ OUTPUT(_T("Cannot reach Skype API, plugin disfunct."));
+ LOG (("FirstLaunch thread stopped: cannot reach Skype API."));
+ return;
+ }
+ Sleep(500);
+ }
+ LOG(("CheckIfApiIsResponding: Testing for PONG"));
+ testfor("PONG", 2000); // Flush PONG from MsgQueue
+
+ pthread_create(( pThreadFunc )SkypeSystemInit, NULL);
+ LOG (("FirstLaunch thread terminated gracefully."));
+}
+
+int CreateTopToolbarButton(WPARAM wParam, LPARAM lParam) {
+ TTBButton ttb={0};
+
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ ttb.cbSize = sizeof(ttb);
+ ttb.dwFlags = TTBBF_VISIBLE|TTBBF_SHOWTOOLTIP;
+ ttb.hIconHandleDn = ttb.hIconHandleUp = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALL));
+ ttb.pszService = SKYPEOUT_CALL;
+ ttb.name=Translate("Do a SkypeOut-call");
+ if ((int)(TopToolbar_AddButton(&ttb))==-1) httbButton=0;
+ return 0;
+}
+
+
+int OnModulesLoaded(WPARAM wParam, LPARAM lParam) {
+ bModulesLoaded=TRUE;
+
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ PopupServiceExists = ServiceExists(MS_POPUP_ADDPOPUP);
+
+ logoff_contacts(FALSE);
+
+ HookEventsLoaded();
+ RegisterToDbeditorpp();
+ VoiceServiceModulesLoaded();
+ GCInit();
+
+ add_contextmenu(NULL);
+ if ( ServiceExists( MS_GC_REGISTER ))
+ {
+ GCREGISTER gcr = {0};
+ static COLORREF crCols[1] = {0};
+ char szEvent[MAXMODULELABELLENGTH];
+
+ gcr.cbSize = sizeof( GCREGISTER );
+ gcr.dwFlags = GC_CHANMGR | GC_TCHAR; // |GC_ACKMSG; // TODO: Not implemented yet
+ gcr.ptszModuleDispName = _T("Skype protocol");
+ gcr.pszModule = SKYPE_PROTONAME;
+ if (CallService(MS_GC_REGISTER, 0, (LPARAM)&gcr))
+ {
+ OUTPUT(_T("Unable to register with Groupchat module!"));
+ }
+ _snprintf (szEvent, sizeof(szEvent), "%s\\ChatInit", SKYPE_PROTONAME);
+ hInitChat = CreateHookableEvent(szEvent);
+ hEvInitChat = HookEvent(szEvent, ChatInit);
+
+ hChatEvent = HookEvent(ME_GC_EVENT, GCEventHook);
+ hChatMenu = HookEvent(ME_GC_BUILDMENU, GCMenuHook);
+ CreateServiceFunction (SKYPE_CHATNEW, SkypeChatCreate);
+ CreateProtoService (PS_LEAVECHAT, GCOnLeaveChat);
+ CreateProtoService (PS_JOINCHAT, GCOnJoinChat);
+ }
+ // Try folder service first
+ hProtocolAvatarsFolder = NULL;
+ if (ServiceExists(MS_FOLDERS_REGISTER_PATH))
+ {
+ char *tmpPath;
+
+ if (!ServiceExists (MS_UTILS_REPLACEVARS) || !(tmpPath = Utils_ReplaceVars("%miranda_avatarcache%")))
+ tmpPath = PROFILE_PATH;
+ mir_snprintf(DefaultAvatarsFolder, sizeof(DefaultAvatarsFolder), "%s\\%s", tmpPath, SKYPE_PROTONAME);
+ hProtocolAvatarsFolder = (HANDLE) FoldersRegisterCustomPath(SKYPE_PROTONAME, "Avatars Cache", DefaultAvatarsFolder);
+ }
+
+ if (hProtocolAvatarsFolder == NULL)
+ {
+ // Use defaults
+ CallService(MS_DB_GETPROFILEPATH, (WPARAM) MAX_PATH, (LPARAM) DefaultAvatarsFolder);
+ mir_snprintf(DefaultAvatarsFolder, sizeof(DefaultAvatarsFolder), "%s\\%s", DefaultAvatarsFolder, SKYPE_PROTONAME);
+ CreateDirectoryA(DefaultAvatarsFolder, NULL);
+ }
+
+ pthread_create(( pThreadFunc )FirstLaunch, NULL);
+ return 0;
+}
+
+void FetchMessageThread(fetchmsg_arg *pargs) {
+ char *who=NULL, *type=NULL, *chat=NULL, *users=NULL, *msg=NULL, *status=NULL;
+ char *ptr, *msgptr, szPartnerHandle[32], szBuf[128];
+ int direction=0, msglen = 0;
+ DWORD timestamp = 0, lwr=0;
+ CCSDATA ccs={0};
+ PROTORECVEVENT pre={0};
+ HANDLE hContact = NULL, hDbEvent, hChat = NULL;
+ DBEVENTINFO dbei={0};
+ DBVARIANT dbv={0};
+ fetchmsg_arg args;
+ BOOL bEmoted=FALSE, isGroupChat=FALSE, bHasPartList=FALSE;
+ BOOL bUseGroupChat = db_get_b(NULL, SKYPE_PROTONAME, "UseGroupchat", 0);
+
+ if (!pargs) return;
+ args = *pargs;
+ free (pargs);
+
+ sprintf (szPartnerHandle, "%s_HANDLE", cmdPartner);
+ pre.lParam = strtoul(args.msgnum, NULL, 10);
+ if (args.bIsRead) pre.flags |= PREF_CREATEREAD;
+ //pEvent = MsgList_FindMessage(pre.lParam);
+
+ // Get Timestamp
+ if (!args.pMsgEntry || !args.pMsgEntry->tEdited) {
+ if (!(ptr=SkypeGet (cmdMessage, args.msgnum, "TIMESTAMP"))) return;
+ if (strncmp(ptr, "ERROR", 5)) timestamp=atol(ptr);
+ else timestamp=(DWORD)SkypeTime(NULL);
+ free(ptr);
+ } else timestamp=(DWORD)(args.pMsgEntry->tEdited);
+
+ __try {
+ // Get Chatname (also to determine if we need to relay this to a groupchat)
+ if (!(chat=SkypeGetErr (cmdMessage, args.msgnum, "CHATNAME"))) __leave;
+ if (hChat = find_chatA(chat)) isGroupChat=TRUE;
+
+ // Get chat status
+ if ((status=SkypeGetErr ("CHAT", chat, "STATUS")) &&
+ !strcmp(status, "MULTI_SUBSCRIBED")) isGroupChat=TRUE;
+
+ // Get chat type
+ if (!(type=SkypeGetErr (cmdMessage, args.msgnum, "TYPE"))) __leave;
+ bEmoted = strcmp(type, "EMOTED")==0;
+ if (strcmp(type, "MULTI_SUBSCRIBED")==0) isGroupChat=TRUE;
+
+ // Group chat handling
+ if (isGroupChat && strcmp(type, "TEXT") && strcmp(type, "SAID") && strcmp(type, "UNKNOWN") && !bEmoted) {
+ if (bUseGroupChat) {
+ BOOL bAddedMembers = FALSE;
+
+ if (!strcmp(type,"SAWMEMBERS") || !strcmp(type, "CREATEDCHATWITH"))
+ {
+ // We have a new Groupchat
+ LOG(("FetchMessageThread CHAT SAWMEMBERS"));
+ if (!hChat) ChatStart(chat, FALSE);
+ __leave;
+ }
+ if (!strcmp(type,"KICKED"))
+ {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ CONTACTINFO ci = {0};
+
+ if (!hChat) __leave;
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = make_nonutf_tchar_string((const unsigned char*)chat);
+ gcd.iType = GC_EVENT_KICK;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.time = timestamp;
+
+ if (users=SkypeGetErr (cmdMessage, args.msgnum, "USERS")) {
+ ci.hContact = find_contact(users);
+ gce.ptszUID= make_nonutf_tchar_string((const unsigned char*)users);
+ if (who=SkypeGetErr (cmdMessage, args.msgnum, szPartnerHandle)) {
+ gce.ptszStatus= make_nonutf_tchar_string((const unsigned char*)who);
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ if (ci.hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=gce.ptszUID;
+
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ RemChatContact (GetChat(gcd.ptszID), gce.ptszUID);
+ free_nonutf_tchar_string((void*)gce.ptszStatus);
+ if (ci.pszVal) mir_free (ci.pszVal);
+ }
+ free_nonutf_tchar_string((void*)gce.ptszUID);
+ }
+ free_nonutf_tchar_string((void*)gcd.ptszID);
+ __leave;
+ }
+ if (!strcmp(type,"SETROLE"))
+ {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ CONTACTINFO ci = {0};
+ gchat_contact *gcContact;
+ char *pszRole;
+
+ // FROM_HANDLE - Wer hats gesetzt
+ // USERS - Wessen Rolle wurde gesetzt
+ // ROLE - Die neue Rolle
+ if (!hChat) __leave;
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = make_nonutf_tchar_string((const unsigned char*)chat);
+ gcd.iType = GC_EVENT_REMOVESTATUS;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.time = timestamp;
+
+ if (users=SkypeGetErr (cmdMessage, args.msgnum, "USERS")) {
+ gce.ptszUID= make_nonutf_tchar_string((const unsigned char*)users);
+ if (who=SkypeGetErr (cmdMessage, args.msgnum, szPartnerHandle)) {
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ ci.hContact = find_contact(who);
+ if (ci.hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ gce.ptszText=_tcsdup(ci.pszVal);
+ mir_free (ci.pszVal);
+ ci.pszVal = NULL;
+ }
+ else gce.ptszText=make_tchar_string((const unsigned char*)who);
+
+ ci.hContact = find_contact(users);
+ if (ci.hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=gce.ptszUID;
+
+ if (gcContact = GetChatContact(GetChat(gcd.ptszID), gce.ptszUID))
+ {
+ gce.ptszStatus = gcContact->szRole;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ }
+ if (pszRole=SkypeGetErr (cmdMessage, args.msgnum, "ROLE")) {
+ gce.ptszStatus = make_nonutf_tchar_string((const unsigned char*)pszRole);
+ gcd.iType = GC_EVENT_ADDSTATUS;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ free_nonutf_tchar_string((void*)gce.ptszStatus);
+ free (pszRole);
+ }
+ free((void*)gce.ptszText);
+ if (ci.pszVal) mir_free (ci.pszVal);
+ }
+ free_nonutf_tchar_string((void*)gce.ptszUID);
+ }
+ free_nonutf_tchar_string((void*)gcd.ptszID);
+ __leave;
+ }
+ if (!strcmp(type,"SETTOPIC"))
+ {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ CONTACTINFO ci = {0};
+
+ LOG(("FetchMessageThread CHAT SETTOPIC"));
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = make_nonutf_tchar_string((const unsigned char*)chat);
+ gcd.iType = GC_EVENT_TOPIC;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.time = timestamp;
+ if (who=SkypeGetErr (cmdMessage, args.msgnum, szPartnerHandle)) {
+ ci.hContact = find_contact(who);
+ gce.ptszUID = make_nonutf_tchar_string((const unsigned char*)who);
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ if (ci.hContact && !CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=gce.ptszUID;
+
+ if (ptr=SkypeGetErr (cmdMessage, args.msgnum, "BODY")) {
+ gce.ptszText = make_tchar_string((const unsigned char*)ptr);
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ free ((void*)gce.ptszText);
+ free (ptr);
+ }
+ free_nonutf_tchar_string ((void*)gce.ptszUID);
+ if (ci.pszVal) mir_free (ci.pszVal);
+ }
+ free_nonutf_tchar_string((void*)gcd.ptszID);
+ if (!args.bDontMarkSeen)
+ {
+ MsgList_Add (pre.lParam, INVALID_HANDLE_VALUE);
+ SkypeSend("SET %s %s SEEN", cmdMessage, args.msgnum);
+ }
+ __leave;
+ }
+ if (!strcmp(type,"LEFT") || (bAddedMembers = strcmp(type,"ADDEDMEMBERS")==0))
+ {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ CONTACTINFO ci = {0};
+ char *pszInvited = Translate("invited ");
+
+ LOG(("FetchMessageThread CHAT LEFT or ADDEDMEMBERS"));
+ if (bAddedMembers) {
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = make_nonutf_tchar_string((const unsigned char*)chat);
+ gcd.iType = GC_EVENT_ACTION;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ gce.time = timestamp;
+ if (users=SkypeGetErr (cmdMessage, args.msgnum, "USERS")) {
+ // We assume that users buffer has enough room for "invited" string
+ memmove (users+strlen(pszInvited), users, strlen(users)+1);
+ memcpy (users, pszInvited, strlen(pszInvited));
+ gce.ptszText= make_tchar_string((const unsigned char*)users);
+ if (who=SkypeGetErr (cmdMessage, args.msgnum, szPartnerHandle)) {
+ DBVARIANT dbv;
+
+ if (db_get_s(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv)==0) {
+ gce.bIsMe = strcmp(who, dbv.pszVal)==0;
+ db_free(&dbv);
+ }
+ if (!gce.bIsMe) ci.hContact = find_contact(who);
+ gce.ptszUID= make_nonutf_tchar_string((const unsigned char*)who);
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ else gce.ptszNick=gce.ptszUID;
+
+ CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce);
+ free_nonutf_tchar_string((void*)gce.ptszUID);
+ if (ci.pszVal) mir_free (ci.pszVal);
+ }
+ if (gce.ptszText) free ((void*)gce.ptszText);
+ }
+ free_nonutf_tchar_string ((void*)gcd.ptszID);
+ }
+ if (!args.QueryMsgDirection) SkypeSend ("GET CHAT %s MEMBERS", chat);
+ __leave;
+ }
+ }
+ __leave;
+ }
+
+ // Need to get the status?
+ if (args.getstatus) {
+ char *status;
+
+ if (protocol<4) InterlockedIncrement (&rcvwatchers);
+ status=SkypeGetID(cmdMessage, args.msgnum, "STATUS");
+ if (protocol<4) InterlockedDecrement (&rcvwatchers);
+ if (!status) __leave;
+ if (!strcmp(status, "SENT")) direction=DBEF_SENT;
+ free(status);
+ }
+
+ // Who sent it?
+ if (!(who=SkypeGetErr (cmdMessage, args.msgnum, szPartnerHandle))) __leave;
+
+ // Get contact handle
+ LOG(("FetchMessageThread Finding contact handle"));
+ db_get_s(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv);
+ if (dbv.pszVal && !strcmp (who, dbv.pszVal))
+ {
+ char *pTok, *nextoken;
+
+ // It's from me.. But to whom?
+ // CHATMESSAGE .. USERS doesn't return anything, so we have to query the CHAT-Object
+ if (!(ptr=SkypeGetErr ("CHAT", chat, "ACTIVEMEMBERS"))) {
+ db_free (&dbv);
+ __leave;
+ }
+
+ for (pTok = strtok_r (ptr, " ", &nextoken); pTok; pTok=strtok_r(NULL, " ", &nextoken)) {
+ if (strcmp (pTok, dbv.pszVal)) break; // Take the first dude in the list who is not me
+ }
+
+ if (!pTok) {
+ free (ptr);
+ db_free (&dbv);
+ __leave; // We failed
+ }
+ free (who);
+ who=(char *)memmove (ptr, pTok, strlen(pTok)+1);
+ direction = DBEF_SENT;
+ }
+ db_free (&dbv);
+
+ if (!(hContact=find_contact(who))) {
+ // Permanent adding of user obsolete, we use the BUDDYSTATUS now (bug #0000005)
+ ResetEvent(hBuddyAdded);
+ SkypeSend("GET USER %s BUDDYSTATUS", who);
+ WaitForSingleObject(hBuddyAdded, INFINITE);
+ if (!(hContact=find_contact(who))) {
+ // Arrgh, the user has been deleted from contact list.
+ // In this case, we add him temp. to receive the msg at least.
+ hContact=add_contact(who, PALF_TEMPORARY);
+ }
+ }
+ // Text which was sent (on edited msg, BODY may already be in queue, check)
+ sprintf (szBuf, "GET %s %s BODY", cmdMessage, args.msgnum);
+ if (!args.pMsgEntry || !args.pMsgEntry->tEdited || !(ptr=SkypeRcv(szBuf+4, 1000)))
+ {
+ if (SkypeSend(szBuf)==-1 || !(ptr=SkypeRcv(szBuf+4, INFINITE)))
+ __leave;
+ }
+ if (strncmp(ptr, "ERROR", 5)) {
+ msgptr = ptr+strlen(szBuf+4)+1;
+ bHasPartList = strncmp(msgptr,"<partlist ",10)==0;
+ if (args.pMsgEntry && args.pMsgEntry->tEdited) {
+ // Mark the message as edited
+ if (!*msgptr && args.pMsgEntry->hEvent != INVALID_HANDLE_VALUE) {
+ // Empty message and edited -> Delete event
+ if ((int)(hContact = db_event_getContact(args.pMsgEntry->hEvent)) != -1) {
+ db_event_delete(hContact, args.pMsgEntry->hEvent);
+ free (ptr);
+ __leave;
+ }
+ } else {
+ msgptr-=9;
+ memcpy (msgptr, "[EDITED] ", 9);
+ }
+ }
+ if( bEmoted && !isGroupChat) {
+ CONTACTINFO ci = {0};
+ int newlen;
+ char *pMsg, *pszUTFnick=NULL;
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ if (ci.hContact = hContact) {
+ CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci);
+ if (ci.pszVal) {
+#ifdef _UNICODE
+ pszUTFnick = (char*)make_utf8_string(ci.pszVal);
+#else
+ utf8_encode (ci.pszVal, &pszUTFnick);
+#endif
+ mir_free (ci.pszVal);
+ }
+ }
+ newlen = strlen(msgptr) + (pszUTFnick?strlen(pszUTFnick):0) + 9;
+ if (pMsg = (char *)malloc(newlen)) {
+ sprintf (pMsg, "** %s%s%s **", (pszUTFnick?pszUTFnick:""),(pszUTFnick?" ":""),(char*)msgptr);
+ free (ptr);
+ ptr = msgptr = pMsg;
+ }
+ if (pszUTFnick) free(pszUTFnick);
+ }
+
+ if (mirandaVersion >= 0x070000 && // 0.7.0+ supports PREF_UTF flag, no need to decode UTF8
+ !isGroupChat) { // I guess Groupchat doesn't support UTF8?
+ msg = ptr;
+ pre.flags |= PREF_UTF;
+ } else { // Older version has to decode either UTF8->ANSI or UTF8->UNICODE
+ // This could be replaced by mir_getUTFI - functions for Miranda 0.5+ builds, but we stay
+ // 0.4 compatible for backwards compatibility. Unfortunately this requires us to link with utf8.c
+#ifdef _UNICODE
+ int wcLen;
+#endif
+
+ if (utf8_decode(msgptr, &msg)==-1) {
+ free(ptr);
+ __leave;
+ }
+#ifdef _UNICODE
+ msglen = strlen(msg)+1;
+ msgptr = (char*)make_unicode_string ((const unsigned char*)msgptr);
+ wcLen = (_tcslen((TCHAR*)msgptr)+1)*sizeof(TCHAR);
+ msg=(char*)realloc(msg, msglen+wcLen);
+ memcpy (msg+msglen, msgptr, wcLen);
+ free(msgptr);
+ pre.flags |= PREF_UNICODE;
+#endif
+ msgptr = msg;
+ free (ptr);
+ }
+ msglen = strlen(msgptr)+1;
+ } else {
+ free (ptr);
+ __leave;
+ }
+ // skype sends some xml statics after a call has finished. Check if thats the case and suppress it if necessary...
+ if ((db_get_b(NULL, SKYPE_PROTONAME, "SuppressCallSummaryMessage", 1) &&
+ bHasPartList) || msgptr[0]==0) __leave;
+
+ if (isGroupChat && bUseGroupChat) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ DBVARIANT dbv = {0};
+ CONTACTINFO ci = {0};
+
+ LOG(("FetchMessageThread This is a group chat message"));
+ if (!hChat) ChatStart(chat, FALSE);
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = make_nonutf_tchar_string((const unsigned char*)chat);
+ gcd.iType = bEmoted?GC_EVENT_ACTION:GC_EVENT_MESSAGE;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ if ((gce.bIsMe = (direction&DBEF_SENT)?TRUE:FALSE) &&
+ db_get_s(NULL, SKYPE_PROTONAME, SKYPE_NAME, &dbv)==0)
+ {
+ free(who);
+ who = _strdup(dbv.pszVal);
+ db_free(&dbv);
+ }
+ gce.ptszUID = make_nonutf_tchar_string((const unsigned char*)who);
+ ci.cbSize = sizeof(ci);
+ ci.szProto = SKYPE_PROTONAME;
+ ci.dwFlag = CNF_DISPLAY | CNF_TCHAR;
+ ci.hContact = !gce.bIsMe?hContact:NULL;
+ gce.ptszNick=gce.ptszUID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) gce.ptszNick=ci.pszVal;
+ gce.time = timestamp>0?timestamp:(DWORD)SkypeTime(NULL);
+ gce.pszText = msgptr;
+ if (pre.flags & PREF_UNICODE) gce.pszText += msglen;
+ gce.dwFlags = GCEF_ADDTOLOG | GC_TCHAR;
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ MsgList_Add (pre.lParam, INVALID_HANDLE_VALUE); // Mark as groupchat
+ if (ci.pszVal) mir_free (ci.pszVal);
+ free_nonutf_tchar_string((void*)gce.ptszUID);
+ free_nonutf_tchar_string(gcd.ptszID);
+
+ // Yes, we have successfully read the msg
+ if (!args.bDontMarkSeen)
+ SkypeSend("SET %s %s SEEN", cmdMessage, args.msgnum);
+ __leave;
+ }
+
+ if (args.QueryMsgDirection || (direction&DBEF_SENT)) {
+ // Check if the timestamp is valid
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ if (hDbEvent=db_event_first(hContact)) {
+ db_event_get(hDbEvent,&dbei);
+ lwr=dbei.timestamp;
+ }
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ dbei.timestamp=0;
+ if (hDbEvent=db_event_last(hContact))
+ db_event_get(hDbEvent, &dbei);
+ LOG(("FetchMessageThread timestamp %ld between %ld and %ld", timestamp, lwr, dbei.timestamp));
+ if (timestamp<lwr || (direction&DBEF_SENT)) {
+ TYP_MSGLENTRY *pme;
+
+ LOG(("FetchMessageThread Adding event"));
+ if (!(dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)))
+ dbei.szModule=SKYPE_PROTONAME;
+ dbei.cbBlob=msglen;
+ if (pre.flags & PREF_UNICODE)
+ dbei.cbBlob += sizeof(WCHAR)*( (DWORD)wcslen((WCHAR*)&msgptr[dbei.cbBlob])+1);
+ dbei.pBlob=(PBYTE)msgptr;
+ dbei.timestamp=timestamp>0?timestamp:(DWORD)SkypeTime(NULL);
+ dbei.flags=direction;
+ if (pre.flags & PREF_CREATEREAD) dbei.flags|=DBEF_READ;
+ if (pre.flags & PREF_UTF) dbei.flags|=DBEF_UTF;
+ dbei.eventType=EVENTTYPE_MESSAGE;
+ pme = MsgList_Add (pre.lParam, db_event_add(hContact, &dbei));
+
+ // We could call MS_PROTO_CHAINSEND if we want to have MetaContact adding the history for us,
+ // however we all know that CCSDATA doesn't contain timestamp-information which is
+ // really bad on importing history for example, as all messages would be added with current
+ // timestamp. This would cause unreliable jumbled timestamps in metacontact, so we better do this
+ // ourself.
+ if (db_get_b(hContact, "MetaContacts", "IsSubcontact", 0))
+ {
+ DWORD dwMetaLink = db_get_dw(hContact, "MetaContacts", "MetaLink", MAXDWORD);
+ HANDLE hMetaContact;
+
+ if (dwMetaLink != MAXDWORD && (hMetaContact = GetMetaHandle(dwMetaLink)))
+ {
+ dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hMetaContact, 0);
+ pme->hMetaEvent = db_event_add(hMetaContact, &dbei);
+ }
+ }
+
+ if (!args.QueryMsgDirection && !args.bDontMarkSeen)
+ SkypeSend("SET %s %s SEEN", cmdMessage, args.msgnum);
+ }
+ }
+
+
+ if (!(direction&DBEF_SENT) && (!args.QueryMsgDirection || (args.QueryMsgDirection && timestamp>dbei.timestamp))) {
+ LOG(("FetchMessageThread Normal message add..."));
+ // Normal message received, process it
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)&pre;
+ pre.flags |= direction;
+ if(isGroupChat && db_get_b(NULL, SKYPE_PROTONAME, "MarkGroupchatRead", 0))
+ pre.flags |= PREF_CREATEREAD;
+ pre.timestamp = timestamp>0?timestamp:(DWORD)SkypeTime(NULL);
+ pre.szMessage = msgptr;
+ CallServiceSync(MS_PROTO_CHAINRECV, 0, (LPARAM) &ccs);
+
+ // Yes, we have successfully read the msg
+ if (!args.bDontMarkSeen) SkypeSend("SET %s %s SEEN", cmdMessage, args.msgnum);
+ }
+ }
+ __finally {
+ if (status) free(status);
+ if (msg) free(msg);
+ if (users) free(users);
+ if (chat) free(chat);
+ if (type) free(type);
+ if (who) free (who);
+ }
+
+}
+
+void FetchMessageThreadSync(fetchmsg_arg *pargs) {
+ // Secure this thread with a mutex.
+ // This is needed to ensure that we get called after an old msg in the queue has
+ // been added so that MsgList_FindEntry will find it.
+ WaitForSingleObject (FetchMessageEvent, 30000); // Wait max. 30 sec. for previous message fetch to complete
+ if ((pargs->pMsgEntry = MsgList_FindMessage(strtoul(pargs->msgnum, NULL, 10))) && !pargs->pMsgEntry->tEdited) {
+ // Better don't do this, as we set the msg as read and with this code, we would
+ // mark messages not opened by user as read which isn't that good
+ /*
+ if (pargs->bIsRead && pMsgEvent->hEvent != INVALID_HANDLE_VALUE)
+ {
+ HANDLE hContact;
+ if ((int)(hContact = (HANDLE)CallService (MS_DB_EVENT_GETCONTACT, (WPARAM)pMsgEntry->hEvent, 0)) != -1)
+ CallService (MS_DB_EVENT_MARKREAD, (WPARAM)hContact, (LPARAM)hDBEvent);
+ }
+ */
+ free (pargs);
+ }
+ else FetchMessageThread (pargs);
+ SetEvent (FetchMessageEvent);
+}
+
+static int MsglCmpProc(const void *pstPElement,const void *pstPToFind)
+{
+ return strcmp ((char*)((fetchmsg_arg*)pstPElement)->pMsgEntry, (char*)((fetchmsg_arg*)pstPToFind)->pMsgEntry);
+}
+
+void MessageListProcessingThread(char *str) {
+ char *token, *nextoken, *chat=NULL;
+ fetchmsg_arg *args;
+ TYP_LIST *hListMsgs = List_Init(32);
+ int i, nCount;
+
+ // Frst we need to sort the message timestamps
+ for ((token=strtok_r(str, ", ", &nextoken)); token; token=strtok_r(NULL, ", ", &nextoken)) {
+ if (args=(fetchmsg_arg*)calloc(1, sizeof(fetchmsg_arg)+sizeof(DWORD))) {
+ strncpy (args->msgnum, token, sizeof(args->msgnum));
+ args->getstatus=TRUE;
+ args->bIsRead=TRUE;
+ args->bDontMarkSeen=TRUE;
+ args->QueryMsgDirection=TRUE;
+ args->pMsgEntry = (TYP_MSGLENTRY*) SkypeGet ("CHATMESSAGE", token, "TIMESTAMP");
+ if (!chat) chat=SkypeGet ("CHATMESSAGE", token, "CHATNAME");
+ if (args->pMsgEntry) List_InsertSort (hListMsgs, MsglCmpProc, args);
+ else free(args);
+ }
+ }
+ for (i=0, nCount=List_Count(hListMsgs); i<nCount; i++) {
+ args = (fetchmsg_arg*)List_ElementAt (hListMsgs, i);
+ free (args->pMsgEntry);
+ args->pMsgEntry = NULL;
+ FetchMessageThreadSync (args);
+ }
+ if (chat) {
+ SkypeSend ("GET CHAT %s MEMBERS", chat);
+ free (chat);
+ }
+ List_Exit (hListMsgs);
+ free (str);
+}
+
+char *GetCallerHandle(char *szSkypeMsg) {
+ return SkypeGet(szSkypeMsg, "PARTNER_HANDLE", "");
+}
+
+
+HANDLE GetCallerContact(char *szSkypeMsg) {
+ char *szHandle;
+ HANDLE hContact=NULL;
+
+ if (!(szHandle=GetCallerHandle(szSkypeMsg))) return NULL;
+ if (!(hContact=find_contact(szHandle))) {
+ // If it's a SkypeOut-contact, PARTNER_HANDLE = SkypeOUT number
+ DBVARIANT dbv;
+ int tCompareResult;
+
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ if (db_get_s(hContact, SKYPE_PROTONAME, "SkypeOutNr", &dbv)) continue;
+ tCompareResult = strcmp(dbv.pszVal, szHandle);
+ db_free(&dbv);
+ if (tCompareResult) continue; else break;
+ }
+ }
+ free(szHandle);
+ if (!hContact) {LOG(("GetCallerContact Not found!"));}
+ return hContact;
+}
+
+HANDLE GetMetaHandle(DWORD dwId) {
+ HANDLE hContact;
+ char *szProto;
+
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, "MetaContacts") &&
+ db_get_dw(hContact, "MetaContacts", "MetaID", MAXDWORD)==dwId)
+ return hContact;
+ }
+ return 0;
+}
+
+LRESULT CALLBACK InCallPopUpProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg)
+ {
+ case WM_COMMAND:
+ break;
+
+ case WM_CONTEXTMENU:
+ SendMessage(hwnd,UM_DESTROYPOPUP,0,0);
+ break;
+ case UM_FREEPLUGINDATA:
+ //Here we'd free our own data, if we had it.
+ return FALSE;
+ case UM_INITPOPUP:
+ break;
+ case UM_DESTROYPOPUP:
+ break;
+ case WM_NOTIFY:
+ default:
+ break;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+void RingThread(char *szSkypeMsg) {
+ HANDLE hContact;
+ DBEVENTINFO dbei={0};
+ DBVARIANT dbv;
+ char *ptr = NULL;
+
+ // We use a single critical section for the RingThread- and the EndCallThread-functions
+ // so that only one function is running at the same time. This is needed, because when
+ // a initated and unaccepted call (which is still ringing) is hangup/canceled, skype
+ // sends two messages. First "CALL xxx STATUS RINGING" .. second "CALL xx STATUS CANCELED".
+ // This starts two independend threads (first: RingThread; second: EndCallThread). Now
+ // the two message are processed in reverse order sometimes. This causes the EndCallThread to
+ // delete the contacts "CallId" property and after that the RingThread saves the contacts
+ // "CallId" again. After that its not possible to call this contact, because the plugin
+ // thinks that there is already a call going and the hangup-function isnt working, because
+ // skype doesnt accept status-changes for finished calls. The CriticalSection syncronizes
+ // the threads and the messages are processed in correct order.
+ // Not the best solution, but it works.
+ EnterCriticalSection (&RingAndEndcallMutex);
+
+ LOG(("RingThread started."));
+ if (protocol >= 5) SkypeSend ("MINIMIZE");
+ if (hContact=GetCallerContact(szSkypeMsg)) {
+ // Make sure that an answering thread is not already in progress so that we don't get
+ // the 'Incoming call' event twice
+ if (!db_get_s(hContact, SKYPE_PROTONAME, "CallId", &dbv)) {
+ db_free(&dbv);
+ LOG(("RingThread terminated."));
+ goto l_exitRT;
+ }
+ db_set_s(hContact, SKYPE_PROTONAME, "CallId", szSkypeMsg);
+ }
+
+ if (!(ptr=SkypeGet(szSkypeMsg, "TYPE", ""))) {
+ LOG(("RingThread terminated."));
+ goto l_exitRT;;
+ }
+
+ if (!strncmp(ptr, "INCOMING", 8))
+ NofifyVoiceService(hContact, szSkypeMsg, VOICE_STATE_RINGING);
+ else
+ NofifyVoiceService(hContact, szSkypeMsg, VOICE_STATE_CALLING);
+
+ if (!strncmp(ptr, "INCOMING", 8)) {
+ if (!hContact) {
+ char *szHandle;
+
+ if (szHandle=GetCallerHandle(szSkypeMsg)) {
+ if (!(hContact=add_contact(szHandle, PALF_TEMPORARY))) {
+ free(szHandle);
+ goto l_exitRT;
+ }
+ db_unset(hContact, "CList", "Hidden");
+ db_set_w(hContact, SKYPE_PROTONAME, "Status", (WORD)SkypeStatusToMiranda("SKYPEOUT"));
+ db_set_s(hContact, SKYPE_PROTONAME, "SkypeOutNr", szHandle);
+ free(szHandle);
+ } else goto l_exitRT;
+ }
+ }
+
+ if (HasVoiceService()) {
+ // Voice service will handle it
+ goto l_exitRT;
+ }
+
+ dbei.cbSize=sizeof(dbei);
+ dbei.eventType=EVENTTYPE_CALL;
+ dbei.szModule=SKYPE_PROTONAME;
+ dbei.timestamp=(DWORD)SkypeTime(NULL);
+ dbei.pBlob=(unsigned char*)Translate("Phonecall");
+ dbei.cbBlob=strlen((const char*)dbei.pBlob)+1;
+ if (!strncmp(ptr, "INCOMING", 8))
+ {
+ CLISTEVENT cle={0};
+ char toolTip[256];
+
+ if(PopupServiceExists)
+ {
+ BOOL showPopup, popupWindowColor;
+ unsigned int popupBackColor, popupTextColor;
+ int popupTimeSec;
+ POPUPDATAT InCallPopup;
+ TCHAR * lpzContactName = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,GCDNF_TCHAR);
+
+ popupTimeSec = db_get_dw(NULL, SKYPE_PROTONAME, "popupTimeSec", 4);
+ popupTextColor = db_get_dw(NULL, SKYPE_PROTONAME, "popupTextColor", GetSysColor(COLOR_WINDOWTEXT));
+ popupBackColor = db_get_dw(NULL, SKYPE_PROTONAME, "popupBackColor", GetSysColor(COLOR_BTNFACE));
+ popupWindowColor = (0 != db_get_b(NULL, SKYPE_PROTONAME, "popupWindowColor", TRUE));
+ showPopup = (0 != db_get_b(NULL, SKYPE_PROTONAME, "showPopup", TRUE));
+
+ InCallPopup.lchContact = hContact;
+ InCallPopup.lchIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALL));
+ InCallPopup.colorBack = ! popupWindowColor ? popupBackColor : GetSysColor(COLOR_BTNFACE);
+ InCallPopup.colorText = ! popupWindowColor ? popupTextColor : GetSysColor(COLOR_WINDOWTEXT);
+ InCallPopup.iSeconds = popupTimeSec;
+ InCallPopup.PluginWindowProc = (WNDPROC)InCallPopUpProc;
+ InCallPopup.PluginData = (void *)1;
+
+ lstrcpy(InCallPopup.lptzText, TranslateT("Incoming Skype Call"));
+
+ lstrcpy(InCallPopup.lptzContactName, lpzContactName);
+
+ if(showPopup)
+ CallService(MS_POPUP_ADDPOPUPT,(WPARAM)&InCallPopup,0);
+
+ }
+ cle.cbSize=sizeof(cle);
+ cle.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALL));
+ cle.pszService=SKYPE_ANSWERCALL;
+ dbei.flags=DBEF_READ;
+ cle.hContact=hContact;
+ cle.hDbEvent=db_event_add(hContact, &dbei);
+ _snprintf(toolTip,sizeof(toolTip),Translate("Incoming call from %s"),(char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0));
+ cle.pszTooltip=toolTip;
+ CallServiceSync(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ }
+ else
+ {
+ dbei.flags=DBEF_SENT;
+ db_event_add(hContact, &dbei);
+ }
+
+l_exitRT:
+ if (ptr) free (ptr);
+ free(szSkypeMsg);
+ LeaveCriticalSection (&RingAndEndcallMutex);
+}
+
+void EndCallThread(char *szSkypeMsg) {
+ HANDLE hContact=NULL, hDbEvent;
+ DBEVENTINFO dbei={0};
+ DBVARIANT dbv;
+ int tCompareResult;
+
+ // We use a single critical section for the RingThread- and the EndCallThread-functions
+ // so that only one function is running at the same time. This is needed, because when
+ // a initated and unaccepted call (which is still ringing) is hangup/canceled, skype
+ // sends two messages. First "CALL xxx STATUS RINGING" .. second "CALL xx STATUS CANCELED".
+ // This starts two independend threads (first: RingThread; second: EndCallThread). Now
+ // the two message are processed in reverse order sometimes. This causes the EndCallThread to
+ // delete the contacts "CallId" property and after that the RingThread saves the contacts
+ // "CallId" again. After that its not possible to call this contact, because the plugin
+ // thinks that there is already a call going and the hangup-function isnt working, because
+ // skype doesnt accept status-changes for finished calls. The CriticalSection syncronizes
+ // the threads and the messages are processed in correct order.
+ // Not the best solution, but it works.
+ EnterCriticalSection (&RingAndEndcallMutex);
+
+ LOG(("EndCallThread started."));
+ if (szSkypeMsg) {
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ if (db_get_s(hContact, SKYPE_PROTONAME, "CallId", &dbv)) continue;
+ tCompareResult = strcmp(dbv.pszVal, szSkypeMsg);
+ db_free(&dbv);
+ if (tCompareResult) continue; else break;
+ }
+ }
+ if (hContact)
+ {
+ NofifyVoiceService(hContact, szSkypeMsg, VOICE_STATE_ENDED);
+
+ db_unset(hContact, SKYPE_PROTONAME, "CallId");
+
+ if (!HasVoiceService()) {
+ dbei.cbSize=sizeof(dbei);
+ hDbEvent=db_event_firstUnread(hContact);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ db_event_get(hDbEvent, &dbei);
+ if (!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_CALL) {
+ db_event_markRead(hContact,hDbEvent);
+ CallService(MS_CLIST_REMOVEEVENT,(WPARAM)hContact,(LPARAM)hDbEvent);
+ }
+ if (dbei.pBlob) free(dbei.pBlob);
+ hDbEvent=db_event_next(hDbEvent);
+ }
+ }
+
+ if (!db_get_s(hContact, SKYPE_PROTONAME, "SkypeOutNr", &dbv)) {
+ db_free(&dbv);
+ if (!strcmp((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0), SKYPE_PROTONAME) &&
+ db_get_b(hContact, "CList", "NotOnList", 0)
+ )
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ }
+ }
+ free(szSkypeMsg);
+ LeaveCriticalSection (&RingAndEndcallMutex);
+}
+
+void HoldCallThread(char *szSkypeMsg) {
+ HANDLE hContact;
+
+ LOG(("HoldCallThread started"));
+ if (!szSkypeMsg) {
+ LOG(("HoldCallThread terminated."));
+ return;
+ }
+ if (hContact=GetCallerContact(szSkypeMsg)) {
+ db_set_b(hContact, SKYPE_PROTONAME, "OnHold", 1);
+ NofifyVoiceService(hContact, szSkypeMsg, VOICE_STATE_ON_HOLD);
+ }
+ free(szSkypeMsg);
+ LOG(("HoldCallThread terminated gracefully"));
+}
+
+void ResumeCallThread(char *szSkypeMsg) {
+ HANDLE hContact;
+
+ LOG(("ResumeCallThread started"));
+ if (!szSkypeMsg) {
+ LOG(("ResumeCallThread terminated."));
+ return;
+ }
+ if (hContact=GetCallerContact(szSkypeMsg)) {
+ db_unset(hContact, SKYPE_PROTONAME, "OnHold");
+ NofifyVoiceService(hContact, szSkypeMsg, VOICE_STATE_TALKING);
+ }
+ free(szSkypeMsg);
+ LOG(("ResumeCallThread terminated gracefully."));
+}
+
+int SetUserStatus(void) {
+ if (RequestedStatus && AttachStatus!=-1) {
+ if (SkypeSend("SET USERSTATUS %s", RequestedStatus)==-1) return 1;
+ }
+ return 0;
+}
+
+void LaunchSkypeAndSetStatusThread(void *newStatus) {
+
+/* if (!db_get_b(NULL, SKYPE_PROTONAME, "UnloadOnOffline", 0)) {
+ logoff_contacts();
+ return 1;
+ }
+*/
+ int oldStatus=SkypeStatus;
+ static BOOL bLaunching = FALSE;
+
+ UNREFERENCED_PARAMETER(newStatus);
+
+ if (bLaunching) return;
+ bLaunching = TRUE;
+ LOG (("LaunchSkypeAndSetStatusThread started."));
+ InterlockedExchange((long *)&SkypeStatus, (int)ID_STATUS_CONNECTING);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, SkypeStatus);
+
+ if (ConnectToSkypeAPI(skype_path, 1)!=-1) {
+ pthread_create(( pThreadFunc )SkypeSystemInit, NULL);
+ //InterlockedExchange((long *)&SkypeStatus, (int)newStatus);
+ //ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, SkypeStatus);
+ SetUserStatus();
+ }
+
+ LOG (("LaunchSkypeAndSetStatusThread terminated gracefully."));
+ bLaunching = FALSE;
+}
+
+LONG APIENTRY WndProc(HWND hWndDlg, UINT message, UINT wParam, LONG lParam)
+{
+ PCOPYDATASTRUCT CopyData;
+ char *ptr, *szSkypeMsg=NULL, *nick, *buf;
+ static char *onlinestatus=NULL;
+ static BOOL RestoreUserStatus=FALSE;
+ int sstat, oldstatus, flag;
+ HANDLE hContact;
+ fetchmsg_arg *args;
+ static int iReentranceCnt = 0;
+
+ iReentranceCnt++;
+ switch (message)
+ {
+ case WM_COPYDATA:
+ LOG(("WM_COPYDATA start"));
+ if(hSkypeWnd==(HWND)wParam) {
+ char *pData;
+ CopyData=(PCOPYDATASTRUCT)lParam;
+ pData = (char*)CopyData->lpData;
+ while (*pData==' ') pData++;
+ szSkypeMsg=_strdup((char*)pData);
+ ReplyMessage(1);
+ LOG(("< %s", szSkypeMsg));
+
+ if (!strncmp(szSkypeMsg, "CONNSTATUS", 10)) {
+ if (!strncmp(szSkypeMsg+11, "LOGGEDOUT", 9)) {
+ SkypeInitialized=FALSE;
+ ResetEvent(SkypeReady);
+ AttachStatus=-1;
+ sstat=ID_STATUS_OFFLINE;
+ if (g_hWnd) KillTimer (g_hWnd, 1);
+ logoff_contacts(TRUE);
+ } else
+ sstat=SkypeStatusToMiranda(szSkypeMsg+11);
+
+ if (sstat) {
+ oldstatus=SkypeStatus;
+ InterlockedExchange((long*)&SkypeStatus, sstat);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ if (sstat!=ID_STATUS_OFFLINE) {
+ if (sstat!=ID_STATUS_CONNECTING && (oldstatus==ID_STATUS_OFFLINE || oldstatus==ID_STATUS_CONNECTING)) {
+
+ SkypeInitialized=FALSE;
+ pthread_create(( pThreadFunc )SkypeSystemInit, NULL);
+ }
+ if (db_get_b(NULL, SKYPE_PROTONAME, "KeepState", 0)) RestoreUserStatus=TRUE;
+ }
+
+// if (SkypeStatus==ID_STATUS_ONLINE) SkypeSend("SEARCH MISSEDMESSAGES");
+ }
+// break;
+ }
+ if (!strncmp(szSkypeMsg, "USERSTATUS", 10)) {
+// if ((sstat=SkypeStatusToMiranda(szSkypeMsg+11)) && SkypeStatus!=ID_STATUS_CONNECTING) {
+ if ((sstat=SkypeStatusToMiranda(szSkypeMsg+11))) {
+ if (RestoreUserStatus && RequestedStatus) {
+ RestoreUserStatus=FALSE;
+ SkypeSend ("SET USERSTATUS %s", RequestedStatus);
+ }
+ oldstatus=SkypeStatus;
+ InterlockedExchange((long*)&SkypeStatus, sstat);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, sstat);
+#ifdef SKYPEBUG_OFFLN
+ if ((oldstatus==ID_STATUS_OFFLINE || oldstatus==ID_STATUS_CONNECTING) &&
+ SkypeStatus!=ID_STATUS_CONNECTING && SkypeStatus!=ID_STATUS_OFFLINE)
+ pthread_create(( pThreadFunc )SearchFriendsThread, NULL);
+#endif
+ }
+#ifdef SKYPEBUG_OFFLN
+ SetEvent(GotUserstatus);
+#endif
+ break;
+ }
+ if (!strncmp(szSkypeMsg, "APPLICATION libpurple_typing", 28)) {
+ char *nextoken, *p;
+
+ if (p=strtok_r(szSkypeMsg+29, " ", &nextoken))
+ {
+ if (!strcmp (p, "STREAMS")) {
+ char *pStr;
+
+ while (p=strtok_r(NULL, " ", &nextoken)) {
+ if (pStr = strchr(p, ':')) {
+ *pStr=0;
+ if (hContact=find_contact(p)) {
+ *pStr=':';
+ db_set_s(hContact, SKYPE_PROTONAME, "Typing_Stream", p);
+ }
+ }
+ }
+ }
+ else if (!strcmp (p, "DATAGRAM")) {
+ if (p=strtok_r(NULL, " ", &nextoken)) {
+ char *pStr;
+
+ if (pStr = strchr(p, ':')) {
+ *pStr=0;
+ if (hContact=find_contact(p)) {
+ *pStr=':';
+ db_set_s(hContact, SKYPE_PROTONAME, "Typing_Stream", p);
+
+ if (p=strtok_r(NULL, " ", &nextoken)) {
+ LPARAM lTyping = PROTOTYPE_CONTACTTYPING_OFF;
+
+ if (!strcmp(p, "PURPLE_TYPING")) lTyping=PROTOTYPE_CONTACTTYPING_INFINITE;
+ CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, lTyping);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!strncmp(szSkypeMsg, "USER ", 5)) {
+ char *nextoken;
+
+ buf=_strdup(szSkypeMsg+5);
+ nick=strtok_r(buf, " ", &nextoken);
+ ptr=strtok_r(NULL, " ", &nextoken);
+
+ if (strcmp(ptr, "BUDDYSTATUS")) {
+ if (!strcmp(ptr, "RECEIVEDAUTHREQUEST")) {
+ pthread_create(( pThreadFunc )SearchUsersWaitingMyAuthorization, NULL);
+ free (buf);
+ break;
+ }
+
+ if (!(hContact=find_contact(nick)) && strcmp(ptr, "FULLNAME")) {
+ SkypeSend("GET USER %s BUDDYSTATUS", nick);
+ free (buf);
+ break;
+ }
+
+ if (!strcmp(ptr, "ONLINESTATUS")) {
+ if (SkypeStatus!=ID_STATUS_OFFLINE)
+ {
+ db_set_w(hContact, SKYPE_PROTONAME, "Status", (WORD)SkypeStatusToMiranda(ptr+13));
+ if((WORD)SkypeStatusToMiranda(ptr+13) != ID_STATUS_OFFLINE)
+ {
+ LOG(("WndProc Status is not offline so get user info"));
+ pthread_create(GetInfoThread, hContact);
+ }
+ }
+ }
+
+
+ /* We handle the following properties right here in the wndProc, in case that
+ * Skype protocol broadcasts them to us.
+ *
+ * However, we still let them be added to the Message queue im memory, as they
+ * may get consumed by GetInfoThread.
+ * This is necessary to have a proper error handling in case the property is
+ * not supported (i.e. imo2sproxy).
+ *
+ * If one of the property GETs returns an error, the error-message has to be
+ * removed from the message queue, as the error is the answer to the query.
+ * If we don't remove the ERRORs from the list, another consumer may see the ERROR
+ * as a reply to his query and process it.
+ * In case the SKYPE Protocol really broadcasts one of these messages without being
+ * requested by GetInfoThread (i.e. MOOD_TEXT), the garbage collector will take
+ * care of them and remove them after some time.
+ * This may not be the most efficient way, but ensures that we finally do proper
+ * error handling.
+ */
+ if (!strcmp(ptr, "FULLNAME")) {
+ char *nm;
+
+ if (nm = strtok_r(NULL, " ", &nextoken))
+ {
+ db_set_utf(hContact, SKYPE_PROTONAME, "FirstName", nm);
+ if (!(nm=strtok_r(NULL, "", &nextoken))) db_unset(hContact, SKYPE_PROTONAME, "LastName");
+ else
+ db_set_utf(hContact, SKYPE_PROTONAME, "LastName", nm);
+ }
+ } else
+ if (!strcmp(ptr, "BIRTHDAY")) {
+ unsigned int y, m, d;
+ if (sscanf(ptr+9, "%04d%02d%02d", &y, &m, &d)==3) {
+ db_set_w(hContact, SKYPE_PROTONAME, "BirthYear", (WORD)y);
+ db_set_b(hContact, SKYPE_PROTONAME, "BirthMonth", (BYTE)m);
+ db_set_b(hContact, SKYPE_PROTONAME, "BirthDay", (BYTE)d);
+ } else {
+ db_unset(hContact, SKYPE_PROTONAME, "BirthYear");
+ db_unset(hContact, SKYPE_PROTONAME, "BirthMonth");
+ db_unset(hContact, SKYPE_PROTONAME, "BirthDay");
+ }
+ } else
+ if (!strcmp(ptr, "COUNTRY")) {
+ if (ptr[8]) {
+ struct CountryListEntry *countries;
+ int countryCount, i;
+
+ CallService(MS_UTILS_GETCOUNTRYLIST, (WPARAM)&countryCount, (LPARAM)&countries);
+ for (i=0; i<countryCount; i++) {
+ if (countries[i].id == 0 || countries[i].id == 0xFFFF) continue;
+ if (!_stricmp(countries[i].szName, ptr+8))
+ {
+ db_set_w(hContact, SKYPE_PROTONAME, "Country", (BYTE)countries[i].id);
+ break;
+ }
+ }
+ } else db_unset(hContact, SKYPE_PROTONAME, "Country");
+ } else
+ if (!strcmp(ptr, "SEX")) {
+ if (ptr[4]) {
+ BYTE sex=0;
+ if (!_stricmp(ptr+4, "MALE")) sex=0x4D;
+ if (!_stricmp(ptr+4, "FEMALE")) sex=0x46;
+ if (sex) db_set_b(hContact, SKYPE_PROTONAME, "Gender", sex);
+ } else db_unset(hContact, SKYPE_PROTONAME, "Gender");
+ } else
+ /* if (!strcmp(ptr, "AVATAR" )){
+ LOG("WndProc", "AVATAR");
+ if (!(hContact=find_contact(nick)))
+ SkypeSend("GET USER %s BUDDYSTATUS", nick);
+ else
+ {
+ TCHAR *unicode = NULL;
+
+ if(utf8_decode((ptr+9), &Avatar)==-1) break;
+
+ if( ServiceExists(MS_AV_SETAVATAR) )
+ {
+ CallService(MS_AV_SETAVATAR,(WPARAM) hContact,(LPARAM) Avatar);
+ }
+ else
+ {
+
+ if(db_set_ts(hContact, "ContactPhoto", "File", Avatar))
+ {
+ #if defined( _UNICODE )
+ char buff[TEXT_LEN];
+ WideCharToMultiByte(code_page, 0, Avatar, -1, buff, TEXT_LEN, 0, 0);
+ buff[TEXT_LEN] = 0;
+ db_set_s(hContact, "ContactPhoto", "File", buff);
+ #endif
+ }
+
+ }
+
+
+ }
+ free(buf);
+ break;
+ }
+ */
+ if (!strcmp(ptr, "MOOD_TEXT")){
+
+ LOG(("WndProc MOOD_TEXT"));
+ db_set_utf(hContact, "CList", "StatusMsg", ptr+10);
+ } else
+ if (!strcmp(ptr, "TIMEZONE")){
+ time_t temp;
+ struct tm tms;
+ int value=atoi(ptr+9), tz;
+
+ LOG(("WndProc: TIMEZONE %s", nick));
+
+ if (value && !db_get_b(NULL, SKYPE_PROTONAME, "IgnoreTimeZones", 0)) {
+ temp = SkypeTime(NULL);
+ tms = *localtime(&temp);
+ //memcpy(&tms,localtime(&temp), sizeof(tm));
+ //tms = localtime(&temp)
+ tz=(value >= 86400 )?(256-((2*(atoi(ptr+9)-86400))/3600)):((-2*(atoi(ptr+9)-86400))/3600);
+ if (tms.tm_isdst == 1 && db_get_b(NULL, SKYPE_PROTONAME, "UseTimeZonePatch", 0))
+ {
+ LOG(("WndProc: Using the TimeZonePatch"));
+ db_set_b(hContact, "UserInfo", "Timezone", (BYTE)(tz+2));
+ }
+ else
+ {
+ LOG(("WndProc: Not using the TimeZonePatch"));
+ db_set_b(hContact, "UserInfo", "Timezone", (BYTE)(tz+0));
+ }
+ } else {
+ LOG(("WndProc: Deleting the TimeZone in UserInfo Section"));
+ db_unset(hContact, "UserInfo", "Timezone");
+ }
+ } else
+ if (!strcmp(ptr, "IS_VIDEO_CAPABLE")){
+ if (!_stricmp(ptr + 17, "True"))
+ db_set_s(hContact, SKYPE_PROTONAME, "MirVer", "Skype 2.0");
+ else
+ db_set_s(hContact, SKYPE_PROTONAME, "MirVer", "Skype");
+ } else
+ if (!strcmp(ptr, "RICH_MOOD_TEXT")) {
+ db_set_s(hContact, SKYPE_PROTONAME, "MirVer", "Skype 3.0");
+ } else
+ if (!strcmp(ptr, "DISPLAYNAME")) {
+ // Skype Bug? -> If nickname isn't customised in the Skype-App, this won't return anything :-(
+ if (ptr[12])
+ db_set_utf(hContact, SKYPE_PROTONAME, "Nick", ptr+12);
+ } else // Other proerties that can be directly assigned to a DB-Value
+ {
+ int i;
+ char *pszProp;
+
+ for (i=0; i<sizeof(m_settings)/sizeof(m_settings[0]); i++) {
+ if (!strcmp(ptr, m_settings[i].SkypeSetting)) {
+ pszProp = ptr+strlen(m_settings[i].SkypeSetting)+1;
+ if (*pszProp)
+ db_set_utf(hContact, SKYPE_PROTONAME, m_settings[i].MirandaSetting, pszProp);
+ else
+ db_unset(hContact, SKYPE_PROTONAME, m_settings[i].MirandaSetting);
+ }
+ }
+ }
+ } else { // BUDDYSTATUS:
+ flag=0;
+ switch(atoi(ptr+12)) {
+ case 1: if (hContact=find_contact(nick)) CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); break;
+ case 0: break;
+ case 2: flag=PALF_TEMPORARY;
+ case 3: add_contact(nick, flag);
+ SkypeSend("GET USER %s ONLINESTATUS", nick);
+ break;
+ }
+ free(buf);
+ if (!SetEvent(hBuddyAdded)) TellError(GetLastError());
+ break;
+ }
+ free(buf);
+ }
+ if (!strncmp(szSkypeMsg, "CURRENTUSERHANDLE", 17)) { // My username
+ DBVARIANT dbv={0};
+
+ if(db_get_s(NULL,SKYPE_PROTONAME,"LoginUserName",&dbv) ||
+ !*dbv.pszVal || _stricmp (szSkypeMsg+18, dbv.pszVal)==0)
+ {
+ db_set_s(NULL, SKYPE_PROTONAME, SKYPE_NAME, szSkypeMsg+18);
+ db_set_s(NULL, SKYPE_PROTONAME, "Nick", szSkypeMsg+18);
+ pthread_create(( pThreadFunc )GetDisplaynameThread, NULL);
+ }
+ if (dbv.pszVal) db_free(&dbv);
+ }
+ if (strstr(szSkypeMsg, "AUTOAWAY") || !strncmp(szSkypeMsg, "OPEN ",5) ||
+ (SkypeInitialized && !strncmp (szSkypeMsg, "PONG", 4)) ||
+ !strncmp (szSkypeMsg, "MINIMIZE", 8))
+ {
+ // Currently we do not process these messages
+ break;
+ }
+ if (!strncmp(szSkypeMsg, "CHAT ", 5)) {
+ // Currently we only process these notifications
+ if (db_get_b(NULL, SKYPE_PROTONAME, "UseGroupchat", 0) &&
+ (ptr = strchr (szSkypeMsg, ' ')) && (ptr = strchr (++ptr, ' ')))
+ {
+ if (strncmp(ptr, " MEMBERS", 8) == 0) {
+ LOG(("WndProc AddMembers"));
+ pthread_create(( pThreadFunc )AddMembersThread, _strdup(szSkypeMsg));
+ } else
+ if (strncmp(ptr, " FRIENDLYNAME ", 14) == 0) {
+ // Chat session name
+ HANDLE hContact;
+
+ *ptr=0;
+ if (hContact = find_chatA(szSkypeMsg+5))
+ {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ if (db_get_w(hContact, SKYPE_PROTONAME, "Status", ID_STATUS_OFFLINE) !=
+ ID_STATUS_OFFLINE)
+ {
+ gcd.pszModule = SKYPE_PROTONAME;
+ gcd.ptszID = make_nonutf_tchar_string((const unsigned char*)szSkypeMsg+5);
+ gcd.iType = GC_EVENT_CHANGESESSIONAME;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.ptszText = make_tchar_string((const unsigned char*)ptr+14);
+ gce.dwFlags = GC_TCHAR;
+ if (gce.ptszText) {
+ CallService(MS_GC_EVENT, 0, (LPARAM)&gce);
+ db_set_ts (hContact, SKYPE_PROTONAME, "Nick", gce.ptszText);
+ free((void*)gce.ptszText);
+ }
+ free_nonutf_tchar_string((void*)gcd.ptszID);
+ }
+ }
+ *ptr=' ';
+ } else
+ if (strncmp(ptr, " CHATMESSAGES ", 14) == 0) {
+ pthread_create(( pThreadFunc )MessageListProcessingThread, _strdup(ptr+14));
+ break;
+ }
+ }
+ }
+ if (!strncmp(szSkypeMsg, "CALL ",5)) {
+ // incoming calls are already processed by Skype, so no need for us
+ // to do this.
+ // However we can give a user the possibility to hang up a call via Miranda's
+ // context menu
+ if (ptr=strstr(szSkypeMsg, " STATUS ")) {
+ ptr[0]=0; ptr+=8;
+ if (!strcmp(ptr, "RINGING") || !strcmp(ptr, "ROUTING")) pthread_create(( pThreadFunc )RingThread, _strdup(szSkypeMsg));
+ if (!strcmp(ptr, "FAILED") || !strcmp(ptr, "FINISHED") ||
+ !strcmp(ptr, "MISSED") || !strcmp(ptr, "REFUSED") ||
+ !strcmp(ptr, "BUSY") || !strcmp(ptr, "CANCELLED"))
+ pthread_create(( pThreadFunc )EndCallThread, _strdup(szSkypeMsg));
+ if (!strcmp(ptr, "ONHOLD") || !strcmp(ptr, "LOCALHOLD") ||
+ !strcmp(ptr, "REMOTEHOLD")) pthread_create(( pThreadFunc )HoldCallThread, _strdup(szSkypeMsg));
+ if (!strcmp(ptr, "INPROGRESS")) pthread_create(( pThreadFunc )ResumeCallThread, _strdup(szSkypeMsg));
+ break;
+ } else if ((!strstr(szSkypeMsg, "PARTNER_HANDLE") && !strstr(szSkypeMsg, "FROM_HANDLE"))
+ && !strstr(szSkypeMsg, "TYPE")) break;
+ }
+ if (!strncmp(szSkypeMsg, "PRIVILEGE SKYPEOUT", 18)) {
+ if (!strncmp(szSkypeMsg+19, "TRUE", 4)) {
+ if (!bSkypeOut) {
+ CLISTMENUITEM mi={0};
+
+ bSkypeOut=TRUE;
+ mi.cbSize=sizeof(mi);
+ mi.position=-2000005000;
+ mi.flags=0;
+ mi.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALLSKYPEOUT));
+ mi.pszContactOwner=SKYPE_PROTONAME;
+ mi.pszName=Translate("Do a SkypeOut-call");
+ mi.pszService=SKYPEOUT_CALL;
+ Menu_AddMainMenuItem(&mi);
+ }
+
+ } else {
+ bSkypeOut=FALSE;
+ if (httbButton) {
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)httbButton, 0);
+ httbButton=0;
+ }
+ }
+ break;
+ }
+ if (!strncmp(szSkypeMsg, "MESSAGES", 8) || !strncmp(szSkypeMsg, "CHATMESSAGES", 12)) {
+ if (strlen(szSkypeMsg)<=(UINT)(strchr(szSkypeMsg, ' ')-szSkypeMsg+1))
+ {
+ LOG(( "%s %d %s %d", szSkypeMsg,(UINT)(strchr(szSkypeMsg, ' ')-szSkypeMsg+1),
+ strchr(szSkypeMsg, ' '), strlen(szSkypeMsg)));
+ break;
+ }
+ LOG(("MessageListProcessingThread launched"));
+ pthread_create(( pThreadFunc )MessageListProcessingThread, _strdup(strchr(szSkypeMsg, ' ')+1));
+ break;
+ }
+ if (!strncmp(szSkypeMsg, "MESSAGE", 7) || !strncmp(szSkypeMsg, "CHATMESSAGE", 11))
+ {
+ char *pMsgNum;
+ TYP_MSGLENTRY *pEntry;
+
+ if ((pMsgNum = strchr (szSkypeMsg, ' ')) && (ptr = strchr (++pMsgNum, ' ')))
+ {
+ BOOL bFetchMsg = FALSE;
+
+ if (strncmp(ptr, " EDITED_TIMESTAMP", 17) == 0) {
+ ptr[0]=0;
+ if (pEntry = MsgList_FindMessage(strtoul(pMsgNum, NULL, 10))) {
+ pEntry->tEdited = atol(ptr+18);
+ }
+ bFetchMsg = TRUE;
+ } else bFetchMsg = (strncmp(ptr, " STATUS RE", 10) == 0 && !rcvwatchers) ||
+ (strncmp(ptr, " STATUS SENT", 12) == 0 && !sendwatchers);
+
+ if (bFetchMsg) {
+ // If new message is available, fetch it
+ ptr[0]=0;
+ if (!(args=(fetchmsg_arg *)calloc(1, sizeof(*args)))) break;
+ strncpy (args->msgnum, pMsgNum, sizeof(args->msgnum));
+ args->getstatus=FALSE;
+ //args->bIsRead = strncmp(ptr+8, "READ", 4) == 0;
+ pthread_create(( pThreadFunc )FetchMessageThreadSync, args);
+ break;
+ }
+ }
+ }
+ if (!strncmp(szSkypeMsg, "ERROR 68", 8)) {
+ LOG(("We got a sync problem :( -> SendMessage() will try to recover..."));
+ break;
+ }
+ if (!strncmp(szSkypeMsg, "PROTOCOL ", 9)) {
+ if ((protocol=(char)atoi(szSkypeMsg+9))>=3) {
+ strcpy(cmdMessage, "CHATMESSAGE");
+ strcpy(cmdPartner, "FROM");
+ }
+ bProtocolSet = TRUE;
+
+ if (protocol<5 && !hMenuAddSkypeContact &&
+ db_get_b(NULL, SKYPE_PROTONAME, "EnableMenu", 1))
+ {
+ hMenuAddSkypeContact = add_mainmenu();
+ }
+ }
+ LOG(("SkypeMsgAdd launched"));
+ SkypeMsgAdd(szSkypeMsg);
+ ReleaseSemaphore(SkypeMsgReceived, receivers, NULL);
+ }
+ break;
+
+ case WM_TIMER:
+ if (iReentranceCnt>1) break;
+ if (!bIsImoproxy) SkypeSend("PING");
+ SkypeMsgCollectGarbage(MAX_MSG_AGE);
+ MsgList_CollectGarbage();
+ if (receivers>1)
+ {
+ LOG(("Watchdog WARNING: there are still %d receivers waiting for MSGs", receivers));
+ }
+ break;
+
+ case WM_CLOSE:
+ PostQuitMessage (0);
+ break;
+ case WM_DESTROY:
+ KillTimer (hWndDlg, 1);
+ break;
+ case WM_COPYDATALOCAL:
+ return WndProc (hWndDlg, WM_COPYDATA, wParam, lParam);
+
+ default:
+ if(message==ControlAPIAttach) {
+ // Skype responds with Attach to the discover-message
+ if ((HWND)wParam == hForbiddenSkypeWnd) {
+ ResetEvent(SkypeReady);
+ break;
+ }
+ AttachStatus=lParam;
+ if (lParam==SKYPECONTROLAPI_ATTACH_SUCCESS) {
+ LOG (("AttachStatus success, got hWnd %08X", (HWND)wParam));
+
+ if (hSkypeWnd && (HWND)wParam!=hSkypeWnd && IsWindow(hSkypeWnd))
+ hSkypeWndSecondary = (HWND)wParam;
+ else {
+ hSkypeWnd=(HWND)wParam; // Skype gave us the communication window handle
+ hSkypeWndSecondary = NULL;
+ }
+ }
+ if (AttachStatus!=SKYPECONTROLAPI_ATTACH_API_AVAILABLE &&
+ AttachStatus!=SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE)
+ {
+ LOG(("Attaching: SkypeReady fired, Attachstatus is %d", AttachStatus));
+ SetEvent(SkypeReady);
+ }
+ AttachStatus=lParam;
+ break;
+ }
+ --iReentranceCnt;
+ return (DefWindowProc(hWndDlg, message, wParam, lParam));
+ }
+ LOG(("WM_COPYDATA exit (%08X)", message));
+ if (szSkypeMsg) free(szSkypeMsg);
+ --iReentranceCnt;
+ return 1;
+}
+
+void TellError(DWORD err) {
+ LPVOID lpMsgBuf;
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
+ MessageBox( NULL, (TCHAR*)lpMsgBuf, _T("GetLastError"), MB_OK|MB_ICONINFORMATION );
+ LocalFree( lpMsgBuf );
+ return;
+}
+
+
+// SERVICES //
+INT_PTR SkypeSetStatus(WPARAM wParam, LPARAM lParam)
+{
+ int oldStatus, iRet;
+ BOOL UseCustomCommand, UnloadOnOffline;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (MirandaShuttingDown) return 0;
+ LOG (("SkypeSetStatus enter"));
+ UseCustomCommand = db_get_b(NULL, SKYPE_PROTONAME, "UseCustomCommand", 0);
+ UnloadOnOffline = db_get_b(NULL, SKYPE_PROTONAME, "UnloadOnOffline", 0);
+
+ //if (!SkypeInitialized && !db_get_b(NULL, SKYPE_PROTONAME, "UnloadOnOffline", 0)) return 0;
+
+ // Workaround for Skype status-bug
+ if ((int)wParam==ID_STATUS_OFFLINE) logoff_contacts(TRUE);
+ if (SkypeStatus==(int)wParam) return 0;
+ oldStatus = SkypeStatus;
+
+ if ((int)wParam==ID_STATUS_CONNECTING) return 0;
+#ifdef MAPDND
+ if ((int)wParam==ID_STATUS_OCCUPIED || (int)wParam==ID_STATUS_ONTHEPHONE) wParam=ID_STATUS_DND;
+ if ((int)wParam==ID_STATUS_OUTTOLUNCH) wParam=ID_STATUS_NA;
+#endif
+#ifdef MAPNA
+ if ((int)wParam==ID_STATUS_NA) wParam = ID_STATUS_AWAY;
+#endif
+
+ RequestedStatus=MirandaStatusToSkype((int)wParam);
+
+ /*
+ if (SkypeStatus != ID_STATUS_OFFLINE)
+ {
+ InterlockedExchange((long*)&SkypeStatus, (int)wParam);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldStatus, SkypeStatus);
+ }
+ */
+
+ if ((int)wParam==ID_STATUS_OFFLINE && UnloadOnOffline)
+ {
+ if(UseCustomCommand)
+ {
+ DBVARIANT dbv;
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"CommandLine",&dbv))
+ {
+ CloseSkypeAPI(dbv.pszVal);
+ db_free(&dbv);
+ }
+ }
+ else
+ {
+ CloseSkypeAPI(skype_path);
+ }
+
+ } else if (AttachStatus==-1)
+ {
+ pthread_create(LaunchSkypeAndSetStatusThread, (void *)wParam);
+ return 0;
+ }
+
+ iRet = SetUserStatus();
+ LOG (("SkypeSetStatus exit"));
+ return iRet;
+}
+
+int __stdcall SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam )
+{
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = SKYPE_PROTONAME;
+ ack.hContact = hContact;
+ ack.type = type;
+ ack.result = result;
+ ack.hProcess = hProcess;
+ ack.lParam = lParam;
+ return CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+static void __cdecl SkypeGetAwayMessageThread( HANDLE hContact )
+{
+ DBVARIANT dbv;
+ if ( !db_get_ts( hContact, "CList", "StatusMsg", &dbv )) {
+ SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, ( LPARAM )dbv.ptszVal );
+ db_free( &dbv );
+ }
+ else SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, ( LPARAM )0 );
+}
+
+INT_PTR SkypeGetAwayMessage(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ pthread_create( SkypeGetAwayMessageThread, ccs->hContact );
+ return 1;
+}
+
+#define POLYNOMIAL (0x488781ED) /* This is the CRC Poly */
+#define TOPBIT (1 << (WIDTH - 1)) /* MSB */
+#define WIDTH 32
+
+static int GetFileHash(char* filename)
+{
+ HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ int remainder = 0, byte, bit;
+ char data[1024];
+ DWORD dwRead;
+
+ if(hFile == INVALID_HANDLE_VALUE) return 0;
+
+ do
+ {
+ // Read file chunk
+ dwRead = 0;
+ ReadFile(hFile, data, 1024, &dwRead, NULL);
+
+ /* loop through each byte of data */
+ for (byte = 0; byte < (int) dwRead; ++byte) {
+ /* store the next byte into the remainder */
+ remainder ^= (data[byte] << (WIDTH - 8));
+ /* calculate for all 8 bits in the byte */
+ for ( bit = 8; bit > 0; --bit) {
+ /* check if MSB of remainder is a one */
+ if (remainder & TOPBIT)
+ remainder = (remainder << 1) ^ POLYNOMIAL;
+ else
+ remainder = (remainder << 1);
+ }
+ }
+ } while(dwRead == 1024);
+
+ CloseHandle(hFile);
+
+ return remainder;
+}
+
+static int _GetFileSize(char* filename)
+{
+ HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ int size;
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ return 0;
+ size = GetFileSize(hFile, NULL);
+ CloseHandle(hFile);
+ return size;
+}
+
+/* RetrieveUserAvatar
+ *
+ * Purpose: Get a user avatar from skype itself
+ * Params : param=(void *)(HANDLE)hContact
+ */
+void RetrieveUserAvatar(void *param)
+{
+ HANDLE hContact = (HANDLE) param, file;
+ PROTO_AVATAR_INFORMATION AI={0};
+ ACKDATA ack = {0};
+ DBVARIANT dbv;
+ char AvatarFile[MAX_PATH+1], AvatarTmpFile[MAX_PATH+10], *ptr, *pszTempFile;
+
+ if (hContact == NULL)
+ return;
+
+ // Mount default ack
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = SKYPE_PROTONAME;
+ ack.hContact = hContact;
+ ack.type = ACKTYPE_AVATAR;
+ ack.result = ACKRESULT_FAILED;
+
+ AI.cbSize = sizeof( AI );
+ AI.hContact = hContact;
+
+ // Get skype name
+ if (db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv) == 0)
+ {
+ if (dbv.pszVal)
+ {
+ // Get filename
+ FoldersGetCustomPath(hProtocolAvatarsFolder, AvatarFile, sizeof(AvatarFile), DefaultAvatarsFolder);
+ if (!*AvatarFile) strcpy (AvatarFile, DefaultAvatarsFolder);
+ mir_snprintf(AvatarTmpFile, sizeof(AvatarTmpFile), "AVATAR 1 %s\\%s_tmp.jpg", AvatarFile, dbv.pszVal);
+ pszTempFile = AvatarTmpFile+9;
+ mir_snprintf(AvatarFile, sizeof(AvatarFile), "%s\\%s.jpg", AvatarFile, dbv.pszVal);
+
+ // Just to be sure
+ DeleteFileA(pszTempFile);
+ file = CreateFileA(pszTempFile, 0, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (file != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(file);
+ if (ptr=SkypeGet ("USER", dbv.pszVal, AvatarTmpFile))
+ {
+ if (strncmp(ptr, "ERROR", 5) &&
+ GetFileAttributesA(pszTempFile) != INVALID_FILE_ATTRIBUTES)
+ {
+ ack.result = ACKRESULT_SUCCESS;
+
+ // Is no avatar image?
+ if (!db_get_b(NULL, SKYPE_PROTONAME, "ShowDefaultSkypeAvatar", 0)
+ && GetFileHash(pszTempFile) == 0x8d34e05d && _GetFileSize(pszTempFile) == 3751)
+ {
+ // Has no avatar
+ AI.format = PA_FORMAT_UNKNOWN;
+ ack.hProcess = (HANDLE)&AI;
+ DeleteFileA(AvatarFile);
+ }
+ else
+ {
+ // Got it
+ MoveFileExA(pszTempFile, AvatarFile, MOVEFILE_REPLACE_EXISTING);
+ AI.format = PA_FORMAT_JPEG;
+ strcpy(AI.filename, AvatarFile);
+ ack.hProcess = (HANDLE)&AI;
+ }
+
+ }
+ free (ptr);
+ }
+ DeleteFileA(pszTempFile);
+ }
+
+ }
+ db_free(&dbv);
+ }
+ CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+
+/* SkypeGetAvatarInfo
+ *
+ * Purpose: Set user avatar in profile
+ * Params : wParam=0
+ * lParam=(LPARAM)(const char*)filename
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeGetAvatarInfo(WPARAM wParam,LPARAM lParam)
+{
+
+ DBVARIANT dbv;
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+ if (AI->hContact == NULL) // User
+ {
+ if (!db_get_s(NULL,SKYPE_PROTONAME, "AvatarFile", &dbv))
+ {
+ lstrcpynA(AI->filename, dbv.pszVal, sizeof(AI->filename));
+ db_free(&dbv);
+ return GAIR_SUCCESS;
+ }
+ else
+ return GAIR_NOAVATAR;
+ }
+ else // Contact
+ {
+ DBVARIANT dbv;
+ char AvatarFile[MAX_PATH+1];
+
+ if (protocol < 7 && !bIsImoproxy)
+ return GAIR_NOAVATAR;
+
+ if (wParam & GAIF_FORCE)
+ {
+ // Request anyway
+ pthread_create(RetrieveUserAvatar, (void *) AI->hContact);
+ return GAIR_WAITFOR;
+ }
+
+ if (db_get_s(AI->hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ // No skype name ??
+ return GAIR_NOAVATAR;
+
+ if (dbv.pszVal == NULL)
+ {
+ // No skype name ??
+ db_free(&dbv);
+ return GAIR_NOAVATAR;
+ }
+
+ // Get filename
+ FoldersGetCustomPath(hProtocolAvatarsFolder, AvatarFile, sizeof(AvatarFile), DefaultAvatarsFolder);
+ mir_snprintf(AvatarFile, sizeof(AvatarFile), "%s\\%s.jpg", AvatarFile, dbv.pszVal);
+ db_free(&dbv);
+
+ // Check if the file exists
+ if (GetFileAttributesA(AvatarFile) == INVALID_FILE_ATTRIBUTES)
+ return GAIR_NOAVATAR;
+
+ // Return the avatar
+ AI->format = PA_FORMAT_JPEG;
+ strcpy(AI->filename, AvatarFile);
+ return GAIR_SUCCESS;
+ }
+}
+
+
+/* SkypeGetAvatarCaps
+ *
+ * Purpose: Query avatar caps for a protocol
+ * Params : wParam=One of AF_*
+ * lParam=Depends on wParam
+ * Returns: Depends on wParam
+ */
+INT_PTR SkypeGetAvatarCaps(WPARAM wParam, LPARAM lParam)
+{
+ switch(wParam)
+ {
+ case AF_MAXSIZE:
+ {
+ POINT *p = (POINT *) lParam;
+ if (p == NULL)
+ return -1;
+
+ p->x = 96;
+ p->y = 96;
+ return 0;
+ }
+ case AF_PROPORTION:
+ {
+ return PIP_NONE;
+ }
+ case AF_FORMATSUPPORTED:
+ {
+ if (lParam == PA_FORMAT_PNG || lParam == PA_FORMAT_JPEG)
+ return TRUE;
+ else
+ return FALSE;
+ }
+ case AF_ENABLED:
+ {
+ return TRUE;
+ }
+ case AF_DONTNEEDDELAYS:
+ {
+ return FALSE;
+ }
+ }
+ return -1;
+}
+
+
+INT_PTR SkypeGetStatus(WPARAM wParam, LPARAM lParam) {
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ return SkypeStatus;
+}
+
+INT_PTR SkypeGetInfo(WPARAM wParam,LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ pthread_create(GetInfoThread, ccs->hContact);
+ return 0;
+}
+
+INT_PTR SkypeAddToList(WPARAM wParam, LPARAM lParam) {
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)lParam;
+
+ LOG(("SkypeAddToList Adding API function called"));
+ if (psr->cbSize!=sizeof(PROTOSEARCHRESULT) || !psr->nick) return 0;
+ LOG(("SkypeAddToList OK"));
+ return (INT_PTR)add_contact(_T2A(psr->nick), wParam);
+}
+
+INT_PTR SkypeBasicSearch(WPARAM wParam, LPARAM lParam) {
+ UNREFERENCED_PARAMETER(wParam);
+
+ LOG(("SkypeBasicSearch %s", (char *)lParam));
+ if (!SkypeInitialized) return 0;
+ return (hSearchThread=pthread_create(( pThreadFunc )BasicSearchThread, _strdup((char *)lParam)));
+}
+
+void MessageSendWatchThread(void *a) {
+ char *str, *err;
+
+ msgsendwt_arg *arg = (msgsendwt_arg*)a;
+
+ LOG(("MessageSendWatchThread started."));
+
+ str=SkypeRcvMsg(arg->szId, SkypeTime(NULL)-1, arg->hContact, db_get_dw(NULL, "SRMsg", "MessageTimeout", TIMEOUT_MSGSEND));
+ InterlockedDecrement (&sendwatchers);
+ if (str)
+ {
+ if (!db_get_b(arg->hContact, SKYPE_PROTONAME, "ChatRoom", 0)) {
+ if (err=GetSkypeErrorMsg(str)) {
+ ProtoBroadcastAck(SKYPE_PROTONAME, arg->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate(err));
+ free(err);
+ free(str);
+ free(arg);
+ LOG(("MessageSendWatchThread terminated."));
+ return;
+ }
+ ProtoBroadcastAck(SKYPE_PROTONAME, arg->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE) 1, 0);
+ }
+ free(str);
+ LOG(("MessageSendWatchThread terminated gracefully."));
+ }
+ free (arg);
+}
+
+INT_PTR SkypeSendMessage(WPARAM wParam, LPARAM lParam) {
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ DBVARIANT dbv;
+ BOOL sendok=TRUE;
+ char *msg = (char *) ccs->lParam, *utfmsg=NULL, *mymsgcmd=cmdMessage, szId[16]={0};
+ static DWORD dwMsgNum = 0;
+ BYTE bIsChatroom = 0 != db_get_b(ccs->hContact, SKYPE_PROTONAME, "ChatRoom", 0);
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ if (bIsChatroom)
+ {
+ if (db_get_s(ccs->hContact, SKYPE_PROTONAME, "ChatRoomID", &dbv))
+ return 0;
+ mymsgcmd="CHATMESSAGE";
+ }
+ else
+ {
+ if (db_get_s(ccs->hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return 0;
+ mymsgcmd="MESSAGE";
+ }
+
+ if (ccs->wParam & PREF_UTF) {
+ utfmsg = msg;
+ } else if (ccs->wParam & PREF_UNICODE) {
+ utfmsg = (char*)make_utf8_string((WCHAR*)(msg+strlen(msg)+1));
+ } else {
+ if (utf8_encode(msg, &utfmsg)==-1) utfmsg=NULL;
+ }
+ if (protocol>=4) {
+ InterlockedIncrement ((LONG*)&dwMsgNum);
+ sprintf (szId, "#M%d ", dwMsgNum++);
+ }
+ InterlockedIncrement (&sendwatchers);
+ if (!utfmsg || SkypeSend("%s%s %s %s", szId, mymsgcmd, dbv.pszVal, utfmsg)) sendok=FALSE;
+ if (utfmsg && utfmsg!=msg) free(utfmsg);
+ db_free(&dbv);
+
+ if (sendok) {
+ msgsendwt_arg *psendarg = (msgsendwt_arg*)calloc(1, sizeof(msgsendwt_arg));
+
+ if (psendarg) {
+ psendarg->hContact = ccs->hContact;
+ strcpy (psendarg->szId, szId);
+ pthread_create(MessageSendWatchThread, psendarg);
+ } else InterlockedDecrement (&sendwatchers);
+ return 1;
+ } else InterlockedDecrement (&sendwatchers);
+ if (!bIsChatroom)
+ ProtoBroadcastAck(SKYPE_PROTONAME, ccs->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE) 1, (LPARAM)Translate("Connection to Skype lost"));
+ return 0;
+}
+
+INT_PTR SkypeRecvMessage(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTINFO dbei={0};
+ CCSDATA *ccs = (CCSDATA *) lParam;
+ PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ db_unset(ccs->hContact, "CList", "Hidden");
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = SKYPE_PROTONAME;
+ dbei.timestamp = pre->timestamp;
+ if (pre->flags & PREF_CREATEREAD) dbei.flags|=DBEF_READ;
+ if (pre->flags & PREF_UTF) dbei.flags|=DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen(pre->szMessage) + 1;
+ if (pre->flags & PREF_UNICODE)
+ dbei.cbBlob += sizeof( wchar_t )*( (DWORD)wcslen(( wchar_t* )&pre->szMessage[dbei.cbBlob] )+1 );
+ dbei.pBlob = (PBYTE) pre->szMessage;
+ MsgList_Add (pre->lParam, db_event_add(ccs->hContact, &dbei));
+ return 0;
+}
+
+INT_PTR SkypeUserIsTyping(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv={0};
+ HANDLE hContact = (HANDLE)wParam;
+
+ if (protocol<5 && !bIsImoproxy) return 0;
+ if (db_get_s(hContact, SKYPE_PROTONAME, "Typing_Stream", &dbv)) {
+ if (db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv) == 0) {
+ char szCmd[256];
+ _snprintf (szCmd, sizeof(szCmd),
+ "ALTER APPLICATION libpurple_typing CONNECT %s", dbv.pszVal);
+ SkypeSend (szCmd);
+ db_free (&dbv);
+ testfor (szCmd, 2000);
+ // TODO: We should somehow cache the typing notify result and send it
+ // after we got a connection, but in the meantime this notification won't
+ // get sent on first run
+ }
+ return 0;
+ }
+
+ SkypeSend ("ALTER APPLICATION libpurple_typing DATAGRAM %s %s", dbv.pszVal,
+ (lParam==PROTOTYPE_SELFTYPING_ON?"PURPLE_TYPING":"PURPLE_NOT_TYPING"));
+ db_free(&dbv);
+ return 0;
+}
+
+
+INT_PTR SkypeSendAuthRequest(WPARAM wParam, LPARAM lParam) {
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ DBVARIANT dbv;
+ int retval;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ if (!ccs->lParam || db_get_s(ccs->hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return 1;
+ retval = SkypeSend("SET USER %s BUDDYSTATUS 2 %s", dbv.pszVal, (char *)ccs->lParam);
+ db_free(&dbv);
+ if (retval) return 1; else return 0;
+}
+
+INT_PTR SkypeRecvAuth(WPARAM wParam, LPARAM lParam) {
+ DBEVENTINFO dbei = {0};
+ CCSDATA* ccs = (CCSDATA*)lParam;
+ PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ db_unset(ccs->hContact, "CList", "Hidden");
+
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = SKYPE_PROTONAME;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ((pre->flags & PREF_CREATEREAD)?DBEF_READ:0);
+ dbei.eventType = EVENTTYPE_AUTHREQUEST;
+ dbei.cbBlob = pre->lParam;
+ dbei.pBlob = (PBYTE)pre->szMessage;
+
+ db_event_add(NULL, &dbei);
+ return 0;
+}
+
+char *__skypeauth(WPARAM wParam) {
+ DBEVENTINFO dbei={0};
+
+ if (!SkypeInitialized) return NULL;
+
+ dbei.cbSize = sizeof(dbei);
+ if ((dbei.cbBlob = db_event_getBlobSize((HANDLE)wParam)==-1 ||
+ !(dbei.pBlob = (unsigned char*)malloc(dbei.cbBlob))))
+ { return NULL; }
+
+ if (db_event_get((HANDLE)wParam, &dbei) ||
+ dbei.eventType != EVENTTYPE_AUTHREQUEST ||
+ strcmp(dbei.szModule, SKYPE_PROTONAME))
+ {
+ free(dbei.pBlob);
+ return NULL;
+ }
+ return (char *)dbei.pBlob;
+}
+
+INT_PTR SkypeAuthAllow(WPARAM wParam, LPARAM lParam) {
+ char *pBlob;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (pBlob=__skypeauth(wParam))
+ {
+ int retval=SkypeSend("SET USER %s ISAUTHORIZED TRUE", pBlob+sizeof(DWORD)+sizeof(HANDLE));
+ free(pBlob);
+ if (!retval) return 0;
+ }
+ return 1;
+}
+
+INT_PTR SkypeAuthDeny(WPARAM wParam, LPARAM lParam) {
+ char *pBlob;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (pBlob=__skypeauth(wParam))
+ {
+ int retval=SkypeSend("SET USER %s ISAUTHORIZED FALSE", pBlob+sizeof(DWORD)+sizeof(HANDLE));
+ free(pBlob);
+ if (!retval) return 0;
+ }
+ return 1;
+}
+
+
+INT_PTR SkypeAddToListByEvent(WPARAM wParam, LPARAM lParam) {
+ char *pBlob;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (pBlob=__skypeauth(wParam))
+ {
+ HANDLE hContact=add_contact(pBlob+sizeof(DWORD)+sizeof(HANDLE), LOWORD(wParam));
+ free(pBlob);
+ if (hContact) return (int)hContact;
+ }
+ return 0;
+}
+
+INT_PTR SkypeRegisterProxy(WPARAM wParam, LPARAM lParam) {
+ UNREFERENCED_PARAMETER(wParam);
+
+ if (!lParam) {
+ free (pszProxyCallout);
+ pszProxyCallout = NULL;
+ }
+ pszProxyCallout = _strdup((char*)lParam);
+ bIsImoproxy = TRUE;
+ return 0;
+}
+
+
+void CleanupNicknames(char *dummy) {
+ HANDLE hContact;
+ char *szProto;
+ DBVARIANT dbv, dbv2;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ LOG(("CleanupNicknames Cleaning up..."));
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) &&
+ db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0)==0)
+ {
+ if (db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) continue;
+ if (db_get_s(hContact, SKYPE_PROTONAME, "Nick", &dbv2)) {
+ db_free(&dbv);
+ continue;
+ }
+ db_unset(hContact, SKYPE_PROTONAME, "Nick");
+ GetInfoThread(hContact);
+ db_free(&dbv);
+ db_free(&dbv2);
+ }
+ }
+ OUTPUT(_T("Cleanup finished."));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// EnterBitmapFileName - enters a bitmap filename
+
+int __stdcall EnterBitmapFileName( char* szDest )
+{
+ char szFilter[ 512 ];
+ OPENFILENAMEA ofn = {0};
+ *szDest = 0;
+
+ CallService( MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof szFilter, ( LPARAM )szFilter );
+ ofn.lStructSize = sizeof( OPENFILENAME );
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = szDest;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "bmp";
+ if ( !GetOpenFileNameA( &ofn ))
+ return 1;
+
+ return ERROR_SUCCESS;
+}
+
+int MirandaExit(WPARAM wParam, LPARAM lParam) {
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ MirandaShuttingDown=TRUE;
+ return 0;
+}
+
+int OkToExit(WPARAM wParam, LPARAM lParam) {
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+// logoff_contacts();
+ MirandaShuttingDown=TRUE;
+
+ // Trigger all semaphores and events just to be sure that there is no deadlock
+ ReleaseSemaphore(SkypeMsgReceived, receivers, NULL);
+ SetEvent (SkypeReady);
+ SetEvent (MessagePumpReady);
+#ifdef SKYPEBUG_OFFLN
+ SetEvent(GotUserstatus);
+#endif
+ SetEvent (hBuddyAdded);
+
+ SkypeFlush ();
+ PostMessage (g_hWnd, WM_CLOSE, 0, 0);
+ return 0;
+}
+
+
+struct PLUGINDI {
+ char **szSettings;
+ int dwCount;
+};
+
+// Taken from pluginopts.c and modified
+int EnumOldPluginName(const char *szSetting,LPARAM lParam)
+{
+ struct PLUGINDI *pdi=(struct PLUGINDI*)lParam;
+ if (pdi && lParam) {
+ pdi->szSettings=(char**)realloc(pdi->szSettings,(pdi->dwCount+1)*sizeof(char*));
+ pdi->szSettings[pdi->dwCount++]=_strdup(szSetting);
+ }
+ return 0;
+}
+
+// Are there any Skype users on list?
+// 1 --> Yes
+// 0 --> No
+int AnySkypeusers(void)
+{
+ HANDLE hContact;
+ DBVARIANT dbv;
+ int tCompareResult;
+
+ // already on list?
+ for (hContact=db_find_first();
+ hContact != NULL;
+ hContact=db_find_next(hContact))
+ {
+ // GETCONTACTBASEPROTO doesn't work on not loaded protocol, therefore get
+ // protocol from DB
+ if (db_get_s(hContact, "Protocol", "p", &dbv)) continue;
+ tCompareResult = !strcmp(dbv.pszVal, SKYPE_PROTONAME);
+ db_free(&dbv);
+ if (tCompareResult) return 1;
+ }
+ return 0;
+}
+
+
+/*void UpgradeName(char *OldName)
+{
+ DBCONTACTENUMSETTINGS cns;
+ DBCONTACTWRITESETTING cws;
+ DBVARIANT dbv;
+ HANDLE hContact=NULL;
+ struct PLUGINDI pdi;
+
+ LOG(("Updating old database settings if there are any..."));
+ cns.pfnEnumProc=EnumOldPluginName;
+ cns.lParam=(LPARAM)&pdi;
+ cns.szModule=OldName;
+ cns.ofsSettings=0;
+
+ hContact = db_find_first();
+
+ for ( ;; ) {
+ memset(&pdi,0,sizeof(pdi));
+ CallService(MS_DB_CONTACT_ENUMSETTINGS,(WPARAM)hContact,(LPARAM)&cns);
+ // Upgrade Protocol settings to new string
+ if (pdi.szSettings) {
+ int i;
+
+ LOG(("We're currently upgrading..."));
+ for (i=0;i<pdi.dwCount;i++) {
+ if (!db_get_s(hContact, OldName, pdi.szSettings[i], &dbv)) {
+ cws.szModule=SKYPE_PROTONAME;
+ cws.szSetting=pdi.szSettings[i];
+ cws.value=dbv;
+ if (!CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)hContact,(LPARAM)&cws))
+ db_unset(hContact,OldName,pdi.szSettings[i]);
+ db_free(&dbv);
+ }
+ free(pdi.szSettings[i]);
+ }
+ free(pdi.szSettings);
+ }
+ // Upgrade Protocol assignment, if we are not main contact
+ if (hContact && !db_get_s(hContact, "Protocol", "p", &dbv)) {
+ if (!strcmp(dbv.pszVal, OldName))
+ db_set_s(hContact, "Protocol", "p", SKYPE_PROTONAME);
+ db_free(&dbv);
+ }
+ if (!hContact) break;
+ hContact = db_find_next(hContact);
+ }
+
+ db_set_b(NULL, SKYPE_PROTONAME, "UpgradeDone", (BYTE)1);
+ return;
+}*/
+
+void __cdecl MsgPump (char *dummy)
+{
+ MSG msg;
+
+ WNDCLASS WndClass;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ // Create window class
+ WndClass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
+ WndClass.lpfnWndProc = (WNDPROC)WndProc;
+ WndClass.cbClsExtra = 0;
+ WndClass.cbWndExtra = 0;
+ WndClass.hInstance = hInst;
+ WndClass.hIcon = NULL;
+ WndClass.hCursor = NULL;
+ WndClass.hbrBackground = NULL;
+ WndClass.lpszMenuName = NULL;
+ WndClass.lpszClassName = _T("SkypeApiDispatchWindow");
+ RegisterClass(&WndClass);
+ // Do not check the retval of RegisterClass, because on non-unicode
+ // win98 it will fail, as it is a stub that returns false() there
+
+ // Create main window
+ g_hWnd=CreateWindowEx( WS_EX_APPWINDOW|WS_EX_WINDOWEDGE,
+ _T("SkypeApiDispatchWindow"), _T(""), WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, 128, 128, NULL, 0, (HINSTANCE)WndClass.hInstance, 0);
+
+ LOG (("Created Dispatch window with handle %08X", (long)g_hWnd));
+ if (!g_hWnd) {
+ OUTPUT(_T("Cannot create window."));
+ TellError(GetLastError());
+ SetEvent(MessagePumpReady);
+ return;
+ }
+ ShowWindow(g_hWnd, 0);
+ UpdateWindow(g_hWnd);
+ msgPumpThreadId = GetCurrentThreadId();
+ SetEvent(MessagePumpReady);
+
+ LOG (("Messagepump started."));
+ while (GetMessage (&msg, NULL, 0, 0) > 0 && !Miranda_Terminated()) {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ UnregisterClass (WndClass.lpszClassName, hInst);
+ LOG (("Messagepump stopped."));
+}
+
+// DLL Stuff //
+
+extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirVersion)
+{
+ mirandaVersion = mirVersion;
+
+ return &pluginInfo;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MUUID_SKYPE_CALL, MIID_LAST};
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
+{
+ UNREFERENCED_PARAMETER(fdwReason);
+ UNREFERENCED_PARAMETER(lpvReserved);
+
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+
+int PreShutdown(WPARAM wParam, LPARAM lParam) {
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ PostThreadMessage(msgPumpThreadId, WM_QUIT, 0, 0);
+ return 0;
+}
+
+extern "C" int __declspec(dllexport) Load(void)
+{
+ DWORD Buffsize;
+ HKEY MyKey;
+ BOOL SkypeInstalled;
+ BOOL UseCustomCommand;
+ WSADATA wsaData;
+ char path[MAX_PATH];
+
+ mir_getLP(&pluginInfo);
+
+ // RM: commented so it will always use predefined name - or was this really needed?
+ ///GetModuleFileNameA( hInst, path, sizeof( path ));
+ ///_splitpath (path, NULL, NULL, SKYPE_PROTONAME, NULL);
+ ///CharUpperA( SKYPE_PROTONAME );
+
+ InitializeCriticalSection(&RingAndEndcallMutex);
+ InitializeCriticalSection(&QueryThreadMutex);
+ InitializeCriticalSection(&TimeMutex);
+
+
+#ifdef _DEBUG
+ init_debug();
+#endif
+
+ LOG(("Load: Skype Plugin loading..."));
+
+ // We need to upgrade SKYPE_PROTOCOL internal name to Skype if not already done
+/* if (!db_get_b(NULL, SKYPE_PROTONAME, "UpgradeDone", 0))
+ UpgradeName("SKYPE_PROTOCOL");*/
+
+ // Initialisation of Skype MsgQueue must be done because of Cleanup in end and
+ // Mutex is also initialized here.
+ LOG(("SkypeMsgInit initializing Skype MSG-queue"));
+ if (SkypeMsgInit()==-1) {
+ OUTPUT(_T("Memory allocation error on startup."));
+ return 0;
+ }
+
+ // On first run on new profile, ask user, if he wants to enable the plugin in
+ // this profile
+ // --> Fixing Issue #0000006 from bugtracker.
+ if (!db_get_b(NULL, SKYPE_PROTONAME, "FirstRun", 0)) {
+ db_set_b(NULL, SKYPE_PROTONAME, "FirstRun", 1);
+ if (AnySkypeusers()==0) // First run, it seems :)
+ if (MessageBox(NULL, TranslateT("This seems to be the first time that you're running the Skype protocol plugin. Do you want to enable the protocol for this Miranda-Profile? (If you chose NO, you can always enable it in the plugin options later."), _T("Welcome!"), MB_ICONQUESTION|MB_YESNO)==IDNO) {
+ char path[MAX_PATH], *filename;
+ GetModuleFileNameA(hInst, path, sizeof(path));
+ if (filename = strrchr(path,'\\')+1)
+ db_set_b(NULL,"PluginDisable",filename,1);
+ return 0;
+ }
+ }
+
+
+ // Check if Skype is installed
+ SkypeInstalled=TRUE;
+ UseCustomCommand = (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UseCustomCommand", 0);
+ UseSockets = (BOOL)db_get_b(NULL, SKYPE_PROTONAME, "UseSkype2Socket", 0);
+
+ if (!UseSockets && !UseCustomCommand)
+ {
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Skype\\Phone"), 0, KEY_READ, &MyKey)!=ERROR_SUCCESS)
+ {
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Skype\\Phone"), 0, KEY_READ, &MyKey)!=ERROR_SUCCESS)
+ {
+ SkypeInstalled=FALSE;
+ }
+ }
+
+ Buffsize=sizeof(skype_path);
+
+ if (SkypeInstalled==FALSE || RegQueryValueExA(MyKey, "SkypePath", NULL, NULL, (unsigned char *)skype_path, &Buffsize)!=ERROR_SUCCESS)
+ {
+ //OUTPUT("Skype was not found installed :( \nMaybe you are using portable skype.");
+ RegCloseKey(MyKey);
+ skype_path[0]=0;
+ //return 0;
+ }
+ RegCloseKey(MyKey);
+ }
+ WSAStartup(MAKEWORD(2,2), &wsaData);
+
+ // Start Skype connection
+ if (!(ControlAPIAttach=RegisterWindowMessage(_T("SkypeControlAPIAttach"))) || !(ControlAPIDiscover=RegisterWindowMessage(_T("SkypeControlAPIDiscover"))))
+ {
+ OUTPUT(_T("Cannot register Window message."));
+ return 0;
+ }
+
+ SkypeMsgReceived=CreateSemaphore(NULL, 0, MAX_MSGS, NULL);
+ if (!(SkypeReady=CreateEvent(NULL, TRUE, FALSE, NULL)) ||
+ !(MessagePumpReady=CreateEvent(NULL, FALSE, FALSE, NULL)) ||
+#ifdef SKYPEBUG_OFFLN
+ !(GotUserstatus=CreateEvent(NULL, TRUE, FALSE, NULL)) ||
+#endif
+ !(hBuddyAdded=CreateEvent(NULL, FALSE, FALSE, NULL)) ||
+ !(FetchMessageEvent=CreateEvent(NULL, FALSE, TRUE, NULL))) {
+ OUTPUT(_T("Unable to create Mutex!"));
+ return 0;
+ }
+
+ /* Register the module */
+ PROTOCOLDESCRIPTOR pd = { PROTOCOLDESCRIPTOR_V3_SIZE };
+ pd.szName = SKYPE_PROTONAME;
+ pd.type = PROTOTYPE_PROTOCOL;
+ CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);
+
+ VoiceServiceInit();
+
+ CreateServices();
+ HookEvents();
+ InitVSApi();
+ MsgList_Init();
+
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, PreShutdown);
+
+ // Startup Message-pump
+ pthread_create (( pThreadFunc )MsgPump, NULL);
+ WaitForSingleObject(MessagePumpReady, INFINITE);
+ return 0;
+}
+
+
+
+extern "C" int __declspec( dllexport ) Unload(void)
+{
+ BOOL UseCustomCommand = db_get_b(NULL, SKYPE_PROTONAME, "UseCustomCommand", 0);
+ BOOL Shutdown = db_get_b(NULL, SKYPE_PROTONAME, "Shutdown", 0);
+
+ LOG (("Unload started"));
+
+ if ( Shutdown && ((skype_path && skype_path[0]) ||UseCustomCommand) ) {
+
+ if(UseCustomCommand)
+ {
+ DBVARIANT dbv;
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"CommandLine",&dbv))
+ {
+ char szAbsolutePath[MAX_PATH];
+
+ TranslateMirandaRelativePathToAbsolute(dbv.pszVal, szAbsolutePath, FALSE);
+ _spawnl(_P_NOWAIT, szAbsolutePath, szAbsolutePath, "/SHUTDOWN", NULL);
+ LOG (("Unload Sent /shutdown to %s", szAbsolutePath));
+ db_free(&dbv);
+ }
+ }
+ else
+ {
+ _spawnl(_P_NOWAIT, skype_path, skype_path, "/SHUTDOWN", NULL);
+ LOG (("Unload Sent /shutdown to %s", skype_path));
+ }
+
+ }
+ SkypeMsgCleanup();
+ //WSACleanup();
+ FreeVSApi();
+ UnhookEvents();
+ UnhookEvent(hChatEvent);
+ UnhookEvent (hChatMenu);
+ UnhookEvent (hEvInitChat);
+ DestroyHookableEvent(hInitChat);
+ VoiceServiceExit();
+ GCExit();
+ MsgList_Exit();
+
+ CloseHandle(SkypeReady);
+ CloseHandle(SkypeMsgReceived);
+#ifdef SKYPEBUG_OFFLN
+ CloseHandle(GotUserstatus);
+#endif
+ CloseHandle(MessagePumpReady);
+ CloseHandle(hBuddyAdded);
+ CloseHandle(FetchMessageEvent);
+
+ DeleteCriticalSection(&RingAndEndcallMutex);
+ DeleteCriticalSection(&QueryThreadMutex);
+
+ SkypeRegisterProxy (0, 0);
+ LOG (("Unload: Shutdown complete"));
+#ifdef _DEBUG
+ end_debug();
+#endif
+ DeleteCriticalSection(&TimeMutex);
+ return 0;
+}
+
diff --git a/protocols/SkypeClassic/skype.h b/protocols/SkypeClassic/skype.h
new file mode 100644
index 0000000000..b5afb7e8f1
--- /dev/null
+++ b/protocols/SkypeClassic/skype.h
@@ -0,0 +1,181 @@
+#pragma once
+
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define TEXT_LEN 1024
+#define CP_ACP 0
+
+#define code_page CP_ACP;
+#define MIRANDA_CUSTOM_LP
+
+
+// System includes
+#include <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <process.h>
+#include <time.h>
+#include "resource.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <shlobj.h>
+#include <time.h>
+#include "util.h"
+
+#pragma warning (push)
+#pragma warning (disable: 4100) // unreferenced formal parameter
+
+// Miranda Includes
+#include <newpluginapi.h>
+#include <m_utils.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_skin.h>
+#include <m_message.h>
+#include <m_database.h>
+#include <m_clist.h>
+#include <m_system.h>
+#include <m_folders.h>
+#include <m_options.h>
+#include <m_langpack.h>
+#include <m_userinfo.h>
+#include <m_avatars.h>
+#include <m_contacts.h>
+#include <m_popup.h>
+
+#pragma warning (pop)
+
+// MyDetails defines
+
+// wParam=NULL
+// lParam=(char *) new nickname - do not free
+// return=0 for sucess
+#define PS_SETMYNICKNAME "/SetNickname"
+
+// Optional, default value is 1024
+// wParam=NULL
+// lParam=NULL
+// return= <=0 for error, >0 the max length of the nick
+#define PS_GETMYNICKNAMEMAXLENGTH "/GetMyNicknameMaxLength"
+
+// wParam=(char *)Buffer to file name
+// lParam=(int)Buffer size
+// return=0 for sucess
+#define PS_GETMYAVATAR "/GetMyAvatar"
+
+// wParam=0
+// lParam=(const char *)Avatar file name
+// return=0 for sucess
+#define PS_SETMYAVATAR "/SetMyAvatar"
+
+
+// Program defines
+#define SKYPE_NAME "Username"
+#define SKYPE_PROTO "PROTOCOL 7"
+#define SKYPE_PROTONAME g_szProtoName // Name of our protocol, taken from .DLL name
+#define MAX_MSGS 128 // Maximum messages in queue
+#define MAX_USERLEN 32 // Maximum length of a username in Skype
+#define PING_INTERVAL 10000 // Ping every 10000 msec to see if Skype is still available
+#define USEPOPUP 1 // Use the popup-plugin?
+#define TIMEOUT_MSGSEND 60000 // Stolen from msgdialog.c
+#define MAX_MSG_AGE 30 // Maximum age in seconds before a Message from queue gets trashed
+#define SKYPEBUG_OFFLN 1 // Activate fix for the SkypeAPI Offline-Bug
+
+// Program hooks
+typedef struct {
+ char ChatNew[MAXMODULELABELLENGTH];
+ char SetAvatar[MAXMODULELABELLENGTH];
+ char SendFile[MAXMODULELABELLENGTH];
+ char HoldCall[MAXMODULELABELLENGTH];
+ char AnswerCall[MAXMODULELABELLENGTH];
+ char ImportHistory[MAXMODULELABELLENGTH];
+ char AddUser[MAXMODULELABELLENGTH];
+ char SkypeOutCallUser[MAXMODULELABELLENGTH];
+ char CallHangupUser[MAXMODULELABELLENGTH];
+ char CallUser[MAXMODULELABELLENGTH];
+} SKYPE_SVCNAMES;
+#define SKYPE_CALL g_svcNames.CallUser
+#define SKYPE_CALLHANGUP g_svcNames.CallHangupUser
+#define SKYPEOUT_CALL g_svcNames.SkypeOutCallUser
+#define SKYPE_ADDUSER g_svcNames.AddUser
+#define SKYPE_IMPORTHISTORY g_svcNames.ImportHistory
+#define SKYPE_ANSWERCALL g_svcNames.AnswerCall
+#define SKYPE_HOLDCALL g_svcNames.HoldCall
+#define SKYPE_SENDFILE g_svcNames.SendFile
+#define SKYPE_SETAVATAR g_svcNames.SetAvatar
+#define SKYPE_CHATNEW g_svcNames.ChatNew
+#define EVENTTYPE_CALL 2000
+
+#define WM_COPYDATALOCAL WM_USER+100 // WM_COPYDATA for local window communication, needed due to Win98 bug
+
+#ifndef __SKYPESVC_C__
+extern SKYPE_SVCNAMES g_svcNames;
+#endif
+
+// Skype API Communication services
+#define PSS_SKYPEAPIMSG "/SendSkypeAPIMsg"
+#define SKYPE_REGPROXY "/RegisterProxySvc"
+
+#define MUUID_SKYPE_CALL { 0x245241eb, 0x178c, 0x4b3f, { 0x91, 0xa, 0x4c, 0x4d, 0xf0, 0xa0, 0xc3, 0xb6 } }
+
+
+// Common used code-pieces
+#define OUTPUT(a) ShowMessage(IDI_ERRORS, a, 1);
+#define OUTPUTA(a) ShowMessageA(IDI_ERRORS, a, 1);
+
+typedef void ( __cdecl* pThreadFunc )( void* );
+
+// Prototypes
+
+void __cdecl SkypeSystemInit(char *);
+void __cdecl MsgPump (char *dummy);
+void PingPong(void);
+void CheckIfApiIsResponding(char *);
+void TellError(DWORD err);
+int ShowMessage(int, TCHAR*, int);
+#ifdef _UNICODE
+int ShowMessageA(int iconID, char *lpzText, int mustShow);
+#else
+#define ShowMessageA ShowMessage
+#endif
+void EndCallThread(char *);
+void GetInfoThread(HANDLE);
+int OnDetailsInit( WPARAM, LPARAM );
+INT_PTR SkypeGetAvatarInfo(WPARAM wParam,LPARAM lParam);
+INT_PTR SkypeGetAvatarCaps(WPARAM wParam,LPARAM lParam);
+INT_PTR SkypeGetAwayMessage(WPARAM wParam,LPARAM lParam);
+int HookContactAdded(WPARAM wParam, LPARAM lParam);
+int HookContactDeleted(WPARAM wParam, LPARAM lParam);
+INT_PTR ImportHistory(WPARAM wParam, LPARAM lParam);
+int CreateTopToolbarButton(WPARAM wParam, LPARAM lParam);
+int OnModulesLoaded(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSetStatus(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeGetStatus(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeGetInfo(WPARAM wParam,LPARAM lParam);
+INT_PTR SkypeAddToList(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeBasicSearch(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSendMessage(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeRecvMessage(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeUserIsTyping(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSendAuthRequest(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeRecvAuth(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeAuthAllow(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeAuthDeny(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeAddToListByEvent(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeRegisterProxy(WPARAM wParam, LPARAM lParam);
+time_t SkypeTime(time_t *timer);
+void MessageSendWatchThread(void*);
+int OkToExit(WPARAM wParam, LPARAM lParam);
+int MirandaExit(WPARAM wParam, LPARAM lParam);
+int __stdcall EnterBitmapFileName( char* szDest );
+void CleanupNicknames(char *dummy);
+int InitVSApi();
+int FreeVSApi();
+HANDLE GetMetaHandle(DWORD dwId);
+void LaunchSkypeAndSetStatusThread(void *newStatus);
+
+// Structs
+
+typedef struct {
+ char *SkypeSetting;
+ char *MirandaSetting;
+} settings_map;
diff --git a/protocols/SkypeClassic/skypeapi.cpp b/protocols/SkypeClassic/skypeapi.cpp
new file mode 100644
index 0000000000..966972f8fe
--- /dev/null
+++ b/protocols/SkypeClassic/skypeapi.cpp
@@ -0,0 +1,1706 @@
+/*
+ * SkypeAPI - All more or less important functions that deal with Skype
+ */
+
+#include "skype.h"
+#include "skypeapi.h"
+#include "utf8.h"
+#include "debug.h"
+#include "contacts.h"
+#include "skypeproxy.h"
+#include "pthread.h"
+#include "gchat.h"
+#include "alogon.h"
+#include "msgq.h"
+#include <malloc.h>
+#pragma warning (push)
+#pragma warning (disable: 4100) // unreferenced formal parameter
+#include <m_utils.h>
+#include <m_langpack.h>
+#pragma warning (push)
+#include <m_toptoolbar.h>
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+// Imported Globals
+extern HWND hSkypeWnd, g_hWnd;
+extern BOOL SkypeInitialized, UseSockets, MirandaShuttingDown, bIsImoproxy;
+extern int SkypeStatus, receivers;
+extern HANDLE SkypeReady, SkypeMsgReceived, httbButton;
+extern UINT ControlAPIAttach, ControlAPIDiscover;
+extern LONG AttachStatus;
+extern HINSTANCE hInst;
+extern PLUGININFOEX pluginInfo;
+extern HANDLE hProtocolAvatarsFolder, hHookSkypeApiRcv;
+extern char DefaultAvatarsFolder[MAX_PATH+1], *pszProxyCallout, protocol, g_szProtoName[];
+
+// -> Skype Message Queue functions //
+
+static TYP_MSGQ SkypeMsgs, SkypeSendQueue;
+
+status_map status_codes[] = {
+ {ID_STATUS_AWAY, "AWAY"},
+ {ID_STATUS_NA, "NA"},
+ {ID_STATUS_DND, "DND"},
+ {ID_STATUS_ONLINE, "ONLINE"},
+ {ID_STATUS_FREECHAT, "SKYPEME"}, // Unfortunately Skype API tells us userstatus ONLINE, if we are free for chat
+ {ID_STATUS_OFFLINE, "OFFLINE"},
+ {ID_STATUS_INVISIBLE, "INVISIBLE"},
+ {ID_STATUS_CONNECTING, "CONNECTING"},
+ {0, NULL}
+};
+
+//status_map
+
+
+static CRITICAL_SECTION ConnectMutex;
+static BOOL rcvThreadRunning=FALSE, isConnecting = FALSE;
+static SOCKET ClientSocket=INVALID_SOCKET;
+static HANDLE SkypeMsgToSend=NULL;
+
+static char *m_szSendBuf = NULL;
+static DWORD m_iBufSize = 0;
+
+
+static int _ConnectToSkypeAPI(char *path, BOOL bStart);
+
+
+/* SkypeReceivedMessage
+ *
+ * Purpose: Hook to be called when a message is received, if some caller is
+ * using our internal I/O services.
+ * Params : wParam - Not used
+ * lParam - COPYDATASTRUCT like in WM_COPYDATA
+ * Returns: Result from SendMessage
+ */
+INT_PTR SkypeReceivedAPIMessage(WPARAM wParam, LPARAM lParam) {
+ return SendMessage(g_hWnd, WM_COPYDATALOCAL, (WPARAM)hSkypeWnd, lParam);
+}
+
+/*
+ * Skype via Socket --> Skype2Socket connection
+ */
+
+void rcvThread(char *dummy) {
+ unsigned int length;
+ char *buf;
+ COPYDATASTRUCT CopyData;
+ int rcv;
+
+ if (!UseSockets) return;
+ rcvThreadRunning=TRUE;
+ for ( ;; ) {
+ if (ClientSocket==INVALID_SOCKET) {
+ rcvThreadRunning=FALSE;
+ return;
+ }
+ LOG(("rcvThread Receiving from socket.."));
+ if ((rcv=recv(ClientSocket, (char *)&length, sizeof(length), 0))==SOCKET_ERROR || rcv==0) {
+ rcvThreadRunning=FALSE;
+ if (rcv==SOCKET_ERROR) {LOG(("rcvThread Socket error"));}
+ else {LOG(("rcvThread lost connection, graceful shutdown"));}
+ return;
+ }
+ LOG(("rcvThread Received length, recieving message.."));
+ buf=(char *)calloc(1, length+1);
+ if ((rcv = recv(ClientSocket, buf, length, 0))==SOCKET_ERROR || rcv==0) {
+ rcvThreadRunning=FALSE;
+ if (rcv==SOCKET_ERROR) {LOG(("rcvThread Socket error"));}
+ else {LOG(("rcvThread lost connection, graceful shutdown"));}
+ free(buf);
+ return;
+ }
+ LOG(("Received message: %s", buf));
+
+ CopyData.dwData=0;
+ CopyData.lpData=buf;
+ CopyData.cbData=(DWORD)strlen(buf)+1;
+ if (!SendMessage(g_hWnd, WM_COPYDATALOCAL, (WPARAM)hSkypeWnd, (LPARAM)&CopyData))
+ {
+ LOG(("SendMessage failed: %08X", GetLastError()));
+ }
+ free(buf);
+ }
+}
+
+void sendThread(char *dummy) {
+ COPYDATASTRUCT CopyData;
+ LRESULT SendResult;
+ int oldstatus;
+ unsigned int length;
+ char *szMsg;
+
+ while (SkypeMsgToSend) {
+ if (WaitForSingleObject(SkypeMsgToSend, INFINITE) != WAIT_OBJECT_0) return;
+ if (!(szMsg = MsgQ_Get(&SkypeSendQueue))) continue;
+ length=(unsigned int)strlen(szMsg);
+
+ if (UseSockets) {
+ if (send(ClientSocket, (char *)&length, sizeof(length), 0) != SOCKET_ERROR &&
+ send(ClientSocket, szMsg, length, 0) != SOCKET_ERROR) {
+ free (szMsg);
+ continue;
+ }
+ SendResult = 0;
+ } else {
+ CopyData.dwData=0;
+ CopyData.lpData=szMsg;
+ CopyData.cbData=length+1;
+
+ // Internal comm channel
+ if (pszProxyCallout) {
+ CallService (pszProxyCallout, 0, (LPARAM)&CopyData);
+ free(szMsg);
+ continue;
+ }
+
+ // If this didn't work, proceed with normal Skype API
+ if (!hSkypeWnd)
+ {
+ LOG(("SkypeSend: DAMN! No Skype window handle! :("));
+ }
+ SendResult=SendMessage(hSkypeWnd, WM_COPYDATA, (WPARAM)g_hWnd, (LPARAM)&CopyData);
+ LOG(("SkypeSend: SendMessage returned %d", SendResult));
+ free(szMsg);
+ }
+ if (!SendResult) {
+ SkypeInitialized=FALSE;
+ AttachStatus=-1;
+ ResetEvent(SkypeReady);
+ if (g_hWnd) KillTimer (g_hWnd, 1);
+ if (SkypeStatus!=ID_STATUS_OFFLINE) {
+ // Go offline
+ logoff_contacts(FALSE);
+ oldstatus=SkypeStatus;
+ InterlockedExchange((long *)&SkypeStatus, (int)ID_STATUS_OFFLINE);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ }
+ // Reconnect to Skype
+ ResetEvent(SkypeReady);
+ pthread_create(LaunchSkypeAndSetStatusThread, (void *)ID_STATUS_ONLINE);
+ WaitForSingleObject (SkypeReady, 10000);
+ // SendMessageTimeout(HWND_BROADCAST, ControlAPIDiscover, (WPARAM)g_hWnd, 0, SMTO_ABORTIFHUNG, 3000, NULL);
+ }
+ }
+}
+
+
+/*
+ * Skype Messagequeue - Implemented as a linked list
+ */
+
+/* SkypeMsgInit
+ *
+ * Purpose: Initializes the Skype Message queue and API
+ * Returns: 0 - Success
+ * -1 - Memory allocation failure
+ */
+int SkypeMsgInit(void) {
+
+ MsgQ_Init(&SkypeMsgs);
+ MsgQ_Init(&SkypeSendQueue);
+ InitializeCriticalSection(&ConnectMutex);
+ if (SkypeMsgToSend=CreateSemaphore(NULL, 0, MAX_MSGS, NULL)) {
+ if (m_szSendBuf = (char*)malloc(m_iBufSize=512)) {
+ if (_beginthread(( pThreadFunc )sendThread, 0, NULL)!=-1)
+ return 0;
+ free(m_szSendBuf);
+ }
+ CloseHandle (SkypeMsgToSend);
+ }
+ return -1;
+}
+
+/* SkypeMsgAdd
+ *
+ * Purpose: Add Message to linked list
+ * Params : msg - Message to add to queue
+ * Returns: 0 - Success
+ * -1 - Memory allocation failure
+ */
+int SkypeMsgAdd(char *msg) {
+ return MsgQ_Add(&SkypeMsgs, msg)?0:-1;
+}
+
+/* SkypeMsgCleanup
+ *
+ * Purpose: Clean up the whole MESSagequeue - free() all
+ */
+void SkypeMsgCleanup(void) {
+ int i;
+
+ LOG(("SkypeMsgCleanup Cleaning up message queue.."));
+ if (receivers>1)
+ {
+ LOG (("SkypeMsgCleanup Releasing %d receivers", receivers));
+ for (i=0;i<receivers; i++)
+ {
+ SkypeMsgAdd ("ERROR Semaphore was blocked");
+ }
+ ReleaseSemaphore (SkypeMsgReceived, receivers, NULL);
+ }
+
+ EnterCriticalSection(&ConnectMutex);
+ MsgQ_Exit(&SkypeMsgs);
+ LeaveCriticalSection(&ConnectMutex);
+ DeleteCriticalSection(&ConnectMutex);
+ CloseHandle(SkypeMsgToSend);
+ SkypeMsgToSend=NULL;
+ MsgQ_Exit(&SkypeSendQueue);
+ if (m_szSendBuf)
+ {
+ free (m_szSendBuf);
+ m_szSendBuf = NULL;
+ m_iBufSize = 0;
+ }
+ LOG(("SkypeMsgCleanup Done."));
+}
+
+/* SkypeMsgGet
+ *
+ * Purpose: Fetch next message from message queue
+ * Returns: The next message
+ * Warning: Don't forget to free() return value!
+ */
+char *SkypeMsgGet(void) {
+ return MsgQ_Get(&SkypeMsgs);
+}
+
+// Message sending routine, for internal use by SkypeSend
+static int __sendMsg(char *szMsg) {
+ COPYDATASTRUCT CopyData;
+
+ LOG(("> %s", szMsg));
+
+ // Fake PING-PONG, as PING-PONG is not supported by Skype2Socket
+ if ((UseSockets || bIsImoproxy) && !strcmp(szMsg, "PING")) {
+ CopyData.dwData=0;
+ CopyData.lpData="PONG";
+ CopyData.cbData=5;
+ SendMessage(g_hWnd, WM_COPYDATALOCAL, (WPARAM)hSkypeWnd, (LPARAM)&CopyData);
+ return 0;
+ }
+
+ if (UseSockets && ClientSocket==INVALID_SOCKET) return -1;
+ if (!MsgQ_Add(&SkypeSendQueue, szMsg) || !ReleaseSemaphore(SkypeMsgToSend, 1, NULL))
+ return -1;
+ return 0;
+}
+
+/* SkypeSend
+ *
+ * Purpose: Sends the specified message to the Skype API.
+ * If it fails, try to reconnect zu the Skype API
+ * Params: use like sprintf without first param (dest. buffer)
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+int SkypeSend(char *szFmt, ...) {
+ char *pNewBuf;
+ va_list ap;
+ size_t iLen;
+
+ // 0.0.0.17+ - Build message-String from supplied parameter list
+ // so the user doesn't have to care about memory allocation any more.
+ // 0.0.0.47+ - No more restrictions apply to the format string.
+ // The temporary buffer remains allocated during the session and gets
+ // dynamically expanded when needed. This makes sense, as this function
+ // is used very often and therefore it is faster to not allocate
+ // memory on every send.
+ if (!m_szSendBuf && !(m_szSendBuf=(char*)malloc(m_iBufSize=512))) return -1;
+ do
+ {
+ va_start(ap, szFmt);
+ iLen = _vsnprintf(m_szSendBuf, m_iBufSize, szFmt, ap);
+ va_end(ap);
+ if (iLen == -1)
+ {
+ if (!(pNewBuf = (char*)realloc (m_szSendBuf, m_iBufSize*2)))
+ {
+ iLen = strlen (m_szSendBuf);
+ break;
+ }
+ m_szSendBuf = pNewBuf;
+ m_iBufSize*=2;
+ }
+ } while (iLen == -1);
+
+ return __sendMsg(m_szSendBuf);
+}
+
+/* SkypeRcvTime
+ *
+ * Purpose: Wait, until either the message "what" is received or maxwait-Time has passed
+ * or there was an error and return it
+ * Params : what - Wait for this string-part at the beginning of a received string
+ * If the first character of the string is NULL, the rest after the NULL
+ * character will be searched in the entire received message-string.
+ * You can tokenize the string by using NULL characters.
+ * You HAVE TO end the string with a extra \0, otherwise the tokenizer
+ * will run amok in memory!
+ * st - The message timestamp must be newer or equal to st.
+ * Set to 0, if you do not need this and want the first message of this
+ * kind in the queue.
+ * maxwait - Wait this time before returning, if nothing was received,
+ * can be INFINITE
+ * Returns: The received message containing "what" or a ERROR-Message or NULL if
+ * time is up and nothing was received
+ * Warning: Don't forget to free() return value!
+ */
+char *SkypeRcvTime(char *what, time_t st, DWORD maxwait) {
+ char *msg, *token=NULL;
+ struct MsgQueue *ptr;
+ int j;
+ DWORD dwWaitStat;
+ BOOL bChatMsg = FALSE, bIsChatMsg = FALSE;
+
+ LOG (("SkypeRcv - Requesting answer: %s", what));
+ if (what) bChatMsg = strncmp(what, "CHATMESSAGE", 11)==0;
+ do {
+ EnterCriticalSection(&SkypeMsgs.cs);
+ // First, search for the requested message. On second run, also accept an ERROR
+ for (j=0; j<2; j++)
+ {
+ for (ptr=SkypeMsgs.l.tqh_first; ptr; ptr=ptr->l.tqe_next) {
+ if (what && what[0]==0) {
+ // Tokenizer syntax active
+ token=what+1;
+ while (*token) {
+ if (!strstr (ptr->message, token)) {
+ token=NULL;
+ break;
+ }
+ token+=strlen(token)+1;
+ }
+ }
+
+ //if (j==1) {LOG(("SkypeRcv compare %s (%lu) -- %s (%lu)", ptr->message, ptr->tReceived, what, st));}
+ if ((st == 0 || ptr->tReceived >= st) &&
+ (what==NULL || token || (what[0] && !strncmp(ptr->message, what, strlen(what))) ||
+ (bIsChatMsg = (j==1 && bChatMsg && !strncmp(ptr->message, what+4, strlen(what+4)))) ||
+ (j==1 && !strncmp(ptr->message, "ERROR", 5))))
+ {
+ msg=MsgQ_RemoveMsg(&SkypeMsgs, ptr);
+ LOG(("<SkypeRcv: %s", msg));
+ if (bIsChatMsg) {
+ msg=(char*)realloc(msg, strlen(msg)+5);
+ memmove (msg+4, msg, strlen(msg)+1);
+ memcpy (msg, "CHAT", 4);
+
+ // This may be a sign that protocol negotiation failed, so we can try to send
+ // our supported protocol version again, just in case... (Skype API bug?)
+ //SkypeSend(SKYPE_PROTO);
+ }
+ LeaveCriticalSection(&SkypeMsgs.cs);
+ return msg;
+ }
+ }
+ }
+ LeaveCriticalSection(&SkypeMsgs.cs);
+ InterlockedIncrement ((long *)&receivers); //receivers++;
+ dwWaitStat = WaitForSingleObject(SkypeMsgReceived, maxwait);
+ if (receivers>1) InterlockedDecrement ((long *)&receivers); // receivers--;
+ if (receivers>1) {LOG (("SkypeRcv: %d receivers still waiting", receivers));}
+
+ } while(dwWaitStat == WAIT_OBJECT_0 && !MirandaShuttingDown);
+ InterlockedDecrement ((long *)&receivers);
+ LOG(("<SkypeRcv: (empty)"));
+ return NULL;
+}
+char *SkypeRcv(char *what, DWORD maxwait) {
+ return SkypeRcvTime(what, 0, maxwait);
+}
+
+char *SkypeRcvMsg(char *what, time_t st, HANDLE hContact, DWORD maxwait) {
+ char *msg, msgid[32]={0}, *pMsg, *pCurMsg;
+ struct MsgQueue *ptr;
+ int iLenWhat = strlen(what);
+ DWORD dwWaitStat;
+ BOOL bIsError, bProcess;
+
+ LOG (("SkypeRcvMsg - Requesting answer: %s ", what));
+ do {
+ EnterCriticalSection(&SkypeMsgs.cs);
+ ptr=SkypeMsgs.l.tqh_first;
+ while(ptr) {
+ //LOG (("SkypeRcvMsg - msg: %s -- %s", ptr->message, what));
+ pCurMsg = ptr->message;
+ bIsError = FALSE;
+ if (*what && !strncmp(pCurMsg, what, iLenWhat)) {
+ // Now we received a MESSAGE with an identifier. So this one is definitely for us
+ // However the status can be SENDING instead of SENT and next message with this number
+ // isn't using the ID anymore, so we have to save the ID as new identifier for message recognition
+ pCurMsg+=iLenWhat;
+ if ((pMsg = strchr (pCurMsg, ' ')) && (pMsg=strchr (pMsg+1, ' ')))
+ strncpy (msgid, pCurMsg, pMsg-pCurMsg);
+ else if (strncmp (pCurMsg, "ERROR", 5) == 0) bIsError = TRUE;
+ }
+
+ if ((*msgid && strncmp (pCurMsg, msgid, strlen(msgid)) == 0) ||
+ (!*what && ptr->tReceived >= st &&
+ (strncmp(pCurMsg, "MESSAGE", 7) == 0 || strncmp(pCurMsg, "CHATMESSAGE", 11) == 0 )
+ ) || bIsError ||
+ (ptr->tReceived >= st && ptr->tReceived <=st+1 &&
+ (bIsError=(strncmp(pCurMsg, "ERROR 26", 8)==0 || strncmp(pCurMsg, "ERROR 43", 8)==0))
+ ) )
+ {
+ bProcess = bIsError;
+ if (!bIsError) {
+ if ((pMsg = strchr (pCurMsg, ' ')) && (pMsg=strchr (pMsg+1, ' '))) {
+ pMsg++;
+ if (strncmp (pMsg, "STATUS ", 7) == 0) {
+ pMsg+=7;
+ if (strcmp (pMsg, "SENDING") == 0) {
+ // Remove dat shit
+ struct MsgQueue *ptr_=ptr->l.tqe_next;
+
+ free(MsgQ_RemoveMsg(&SkypeMsgs, ptr));
+ ptr=ptr_;
+ continue;
+ }
+ bProcess = (strcmp (pMsg, "SENT") == 0 || strcmp (pMsg, "QUEUED") == 0 ||
+ strcmp (pMsg, "FAILED") == 0 || strcmp (pMsg, "IGNORED") == 0 ||
+ strcmp (pMsg, "SENDING") == 0);
+ }
+ }
+ }
+ if (bProcess) {
+ msg=MsgQ_RemoveMsg(&SkypeMsgs, ptr);
+ LOG(("<SkypeRcv: %s", msg));
+ LeaveCriticalSection(&SkypeMsgs.cs);
+ return msg;
+ }
+ }
+ ptr=ptr->l.tqe_next;
+ }
+ LeaveCriticalSection(&SkypeMsgs.cs);
+ InterlockedIncrement ((long *)&receivers); //receivers++;
+ dwWaitStat = WaitForSingleObject(SkypeMsgReceived, maxwait);
+ if (receivers>1) InterlockedDecrement ((long *)&receivers); // receivers--;
+ if (receivers>1) {LOG (("SkypeRcvMsg: %d receivers still waiting", receivers));}
+
+ } while(dwWaitStat == WAIT_OBJECT_0 && !MirandaShuttingDown);
+ InterlockedDecrement ((long *)&receivers);
+ LOG(("<SkypeRcvMsg: (empty)"));
+ return NULL;
+}
+
+/*
+ Introduced in 0.0.0.17
+
+ Issues a GET szWhat szWho szProperty and waits until the answer is received
+ Returns the answer or NULL on failure
+ BEWARE: Don't forget to free() return value!
+
+ For example: SkypeGet("USER", dbv.pszVal, "FULLNAME");
+*/
+static char *__SkypeGet(char *szID, char *szWhat, char *szWho, char *szProperty) {
+ char *str, *ptr;
+ size_t len, len_id;
+ time_t st = 0;
+
+ st = *szID?0:SkypeTime(NULL);
+ str=(char *)_alloca((len=strlen(szWhat)+strlen(szWho)+strlen(szProperty)+(*szWho?2:1)+(len_id=strlen(szID)))+5);
+ sprintf(str, "%sGET %s%s%s %s", szID, szWhat, *szWho?" ":"", szWho, szProperty);
+ if (__sendMsg(str)) return NULL;
+ if (*szProperty) len++;
+ if (*szID) {
+ sprintf(str, "%s%s%s%s %s", szID, szWhat, *szWho?" ":"", szWho, szProperty);
+ ptr = SkypeRcvTime(str, st, INFINITE);
+ } else ptr = SkypeRcvTime(str+4, st, INFINITE);
+ if (ptr && strncmp (ptr+len_id, "ERROR", 5)) memmove(ptr, ptr+len, strlen(ptr)-len+1);
+ LOG(("SkypeGet - Request %s -> Answer %s", str, ptr));
+ return ptr;
+}
+
+char *SkypeGetID(char *szWhat, char *szWho, char *szProperty) {
+ char szID[16]={0};
+ static DWORD dwId = 0;
+
+ if (protocol>=4 || bIsImoproxy) sprintf (szID, "#G%d ", dwId++);
+ return __SkypeGet (szID, szWhat, szWho, szProperty);
+}
+
+char *SkypeGet(char *szWhat, char *szWho, char *szProperty) {
+ return __SkypeGet ("", szWhat, szWho, szProperty);
+}
+
+#ifdef _UNICODE
+WCHAR *SkypeGetW(char *szWhat, WCHAR *szWho, char *szProperty) {
+ char *ptszWho = (char*)make_utf8_string(szWho);
+ char *pRet = SkypeGet (szWhat, ptszWho, szProperty);
+ free (ptszWho);
+ if (pRet) {
+ WCHAR *ptr = make_unicode_string((const unsigned char*)pRet);
+ free (pRet);
+ return ptr;
+ }
+ return NULL;
+}
+#endif
+
+char *SkypeGetErr(char *szWhat, char *szWho, char *szProperty) {
+ char *ret = SkypeGet(szWhat, szWho, szProperty);
+ if (ret && !strncmp(ret, "ERROR", 5)) {
+ free (ret);
+ return NULL;
+ }
+ return ret;
+}
+
+#ifdef _UNICODE
+WCHAR *SkypeGetErrW(char *szWhat, TCHAR *szWho, char *szProperty) {
+ WCHAR *ret = SkypeGetW(szWhat, szWho, szProperty);
+ if (ret && !_tcsncmp(ret, _T("ERROR"), 5)) {
+ free (ret);
+ return NULL;
+ }
+ return ret;
+}
+#endif
+
+
+/* SkypeGetProfile
+ *
+ * Issues a SET PROFILE szProperty szValue and waits until the answer is received
+ * Returns the answer or NULL on failure
+ * BEWARE: Don't forget to free() return value!
+ *
+ * For example: SkypeGetProfile("FULLNAME", "Tweety");
+*/
+char *SkypeGetProfile(char *szProperty) {
+ return SkypeGet ("PROFILE", "", szProperty);
+}
+
+/* SkypeSetProfile
+ *
+ *
+*/
+int SkypeSetProfile(char *szProperty, char *szValue) {
+ return SkypeSend("SET PROFILE %s %s", szProperty, szValue);
+}
+
+/* SkypeMsgCollectGarbage
+ *
+ * Purpose: Runs the garbage collector on the Skype Message-Queue to throw out old
+ * messages which may unnecessarily eat up memory.
+ * Params : age - Time in seconds. Messages older than this value will be
+ * thrown out.
+ * Returns: 0 - No messages were thrown out
+ * >0 - n messages were thrown out
+ */
+int SkypeMsgCollectGarbage(time_t age) {
+ return MsgQ_CollectGarbage(&SkypeMsgs, age);
+}
+
+
+/* SkypeCall
+ *
+ * Purpose: Give a Skype call to the given User in wParam
+ * or hangs up existing call
+ * (hangUp is moved over to SkypeCallHangup)
+ * Params : wParam - Handle to the User to be called
+ * lParam - Can be NULL
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeCall(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ char *msg=0;
+ int res;
+
+ if (!db_get_s((HANDLE)wParam, SKYPE_PROTONAME, "CallId", &dbv)) {
+ res = -1; // no direct return, because dbv needs to be freed
+ } else {
+ if (db_get_s((HANDLE)wParam, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) return -1;
+ msg=(char *)malloc(strlen(dbv.pszVal)+6);
+ strcpy(msg, "CALL ");
+ strcat(msg, dbv.pszVal);
+ res=SkypeSend(msg);
+ }
+ db_free(&dbv);
+ free(msg);
+ return res;
+}
+
+/* SkypeCallHangup
+ *
+ * Prupose: Hangs up the existing call to the given User
+ * in wParam.
+ *
+ * Params : wParam - Handle to the User to be called
+ * lParam - Can be NULL
+ *
+ * Returns: 0 - Success
+ * -1 - Failure
+ *
+ */
+INT_PTR SkypeCallHangup(WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ char *msg=0;
+ int res = -1;
+
+ if (!db_get_s((HANDLE)wParam, SKYPE_PROTONAME, "CallId", &dbv)) {
+ msg=(char *)malloc(strlen(dbv.pszVal)+21);
+ sprintf(msg, "SET %s STATUS FINISHED", dbv.pszVal);
+ //sprintf(msg, "ALTER CALL %s HANGUP", dbv.pszVal);
+ res=SkypeSend(msg);
+#if _DEBUG
+ db_unset((HANDLE)wParam, SKYPE_PROTONAME, "CallId");
+#endif
+ //} else {
+ // if (db_get((HANDLE)wParam, SKYPE_PROTONAME, SKYPE_NAME, &dbv)) return -1;
+ // msg=(char *)malloc(strlen(dbv.pszVal)+6);
+ // strcpy(msg, "CALL ");
+ // strcat(msg, dbv.pszVal);
+ // res=SkypeSend(msg);
+ }
+ db_free(&dbv);
+ free(msg);
+ return res;
+}
+
+/* FixNumber
+ *
+ * Purpose: Eliminates all non-numeric chars from the given phonenumber
+ * Params : p - Pointer to the buffer with the number
+ */
+static void FixNumber(char *p) {
+ unsigned int i;
+
+ for (i=0;i<=strlen(p);i++)
+ if ((p[i]<'0' || p[i]>'9'))
+ if (p[i]) {
+ memmove(p+i, p+i+1, strlen(p+i));
+ i--;
+ } else break;
+}
+
+
+/* DialDlgProc
+ *
+ * Purpose: Dialog procedure for the Dial-Dialog
+ */
+static INT_PTR CALLBACK DialDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ static HANDLE hContact;
+ static unsigned int entries=0;
+ BOOL TempAdded=FALSE;
+ char number[64], *msg, *ptr=NULL;
+
+ switch (uMsg){
+ case WM_INITDIALOG:
+ hContact=(HANDLE)lParam;
+ Utils_RestoreWindowPosition(hwndDlg, NULL, SKYPE_PROTONAME, "DIALdlg");
+ TranslateDialogDefault(hwndDlg);
+
+ if (lParam) {
+ DBVARIANT dbv;
+ BOOL bDialNow=TRUE;
+
+ if (!db_get(hContact,"UserInfo","MyPhone1",&dbv)) {
+ int j;
+ char idstr[16];
+
+ // Multiple phone numbers, select one
+ bDialNow=FALSE;
+ db_free(&dbv);
+ for(j=0;;j++) {
+ sprintf(idstr,"MyPhone%d",j);
+ if(db_get_s(hContact,"UserInfo",idstr,&dbv)) break;
+ FixNumber(dbv.pszVal+1); // Leave + alone
+ SendDlgItemMessage(hwndDlg,IDC_NUMBER,CB_ADDSTRING,0,(LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ }
+ if (db_get_s(hContact,SKYPE_PROTONAME,"SkypeOutNr",&dbv)) {
+ db_get_s(hContact,"UserInfo","MyPhone0",&dbv);
+ FixNumber(dbv.pszVal+1);
+ }
+ SetDlgItemTextA(hwndDlg, IDC_NUMBER, dbv.pszVal);
+ db_free(&dbv);
+ if (bDialNow) PostMessage(hwndDlg, WM_COMMAND, IDDIAL, 0);
+ } else {
+ DBVARIANT dbv;
+ char number[64];
+
+ for (entries=0;entries<MAX_ENTRIES;entries++) {
+ sprintf(number, "LastNumber%d", entries);
+ if (!db_get_ts(NULL, SKYPE_PROTONAME, number, &dbv)) {
+ SendDlgItemMessage(hwndDlg,IDC_NUMBER,CB_ADDSTRING,0,(LPARAM)dbv.ptszVal);
+ db_free(&dbv);
+ } else break ;
+ }
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDC_NUMBER));
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDDIAL:
+ EnableWindow(GetDlgItem(hwndDlg, IDDIAL), FALSE);
+ GetDlgItemTextA(hwndDlg, IDC_NUMBER, number, sizeof(number));
+ if (!strncmp(number, "00", 2)) {
+ memmove(number, number+1, sizeof(number)-1);
+ number[0]='+';
+ number[sizeof(number)]=0;
+ }
+ if (!hContact) {
+ if (!(hContact=add_contact(number, PALF_TEMPORARY))) {
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ db_unset(hContact, "CList", "Hidden");
+ db_set_w(hContact, SKYPE_PROTONAME, "Status", (WORD)SkypeStatusToMiranda("SKYPEOUT"));
+ if (SendDlgItemMessage(hwndDlg,IDC_NUMBER,CB_FINDSTRING,0,(LPARAM)number)==CB_ERR) {
+ int i;
+ char buf[64];
+ DBVARIANT dbv;
+
+ if (entries>MAX_ENTRIES) entries=MAX_ENTRIES;
+ for (i=entries;i>0;i--) {
+ sprintf(buf, "LastNumber%d", i-1);
+ if (!db_get_s(NULL, SKYPE_PROTONAME, buf, &dbv)) {
+ sprintf(buf, "LastNumber%d", i);
+ db_set_s(NULL, SKYPE_PROTONAME, buf, dbv.pszVal);
+ db_free(&dbv);
+ } else break;
+ }
+ db_set_s(NULL, SKYPE_PROTONAME, "LastNumber0", number);
+ }
+ TempAdded=TRUE;
+ }
+ if (!db_set_s(hContact, SKYPE_PROTONAME, "SkypeOutNr", number)) {
+ msg=(char *)malloc(strlen(number)+6);
+ strcpy(msg, "CALL ");
+ strcat(msg, number);
+ if (SkypeSend(msg) || (ptr=SkypeRcv("ERROR", 500))) {
+ db_unset(hContact, SKYPE_PROTONAME, "SkypeOutNr");
+ if (ptr) {
+ OUTPUTA(ptr);
+ free(ptr);
+ }
+ if (TempAdded) CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
+ }
+ free(msg);
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ Utils_SaveWindowPosition(hwndDlg, NULL, SKYPE_PROTONAME, "DIALdlg");
+ if (httbButton) CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)httbButton, TTBST_RELEASED);
+ break;
+ }
+ return FALSE;
+}
+
+/* CallstatDlgProc
+ *
+ * Purpose: Dialog procedure for the CallStatus Dialog
+ */
+static INT_PTR CALLBACK CallstatDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ static int selected;
+ static DBVARIANT dbv, dbv2={0};
+
+ switch (uMsg){
+ case WM_INITDIALOG:
+ {
+ HANDLE hContact;
+ char *szProto;
+
+ if (!db_get_s((HANDLE)lParam, SKYPE_PROTONAME, "CallId", &dbv)) {
+
+ // Check, if another call is in progress
+ for (hContact=db_find_first();hContact != NULL;hContact=db_find_next(hContact)) {
+ szProto = (char*)CallService( MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0 );
+ if (szProto!=NULL && !strcmp(szProto, SKYPE_PROTONAME) && hContact!=(HANDLE)lParam &&
+ db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 0 &&
+ !db_get_s(hContact, SKYPE_PROTONAME, "CallId", &dbv2))
+ {
+ if (db_get_b(hContact, SKYPE_PROTONAME, "OnHold", 0)) {
+ db_free(&dbv2);
+ continue;
+ } else break;
+ }
+ }
+
+ if (dbv2.pszVal)
+ {
+ char buf[256], buf2[256];
+ char *szOtherCaller=(char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,0);
+
+ Utils_RestoreWindowPosition(hwndDlg, NULL, SKYPE_PROTONAME, "CALLSTATdlg");
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_COMMAND, IDC_JOIN, 0);
+
+ GetWindowTextA(hwndDlg, buf, sizeof(buf));
+ _snprintf(buf2, sizeof(buf), buf, CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)lParam,0));
+ SetWindowTextA(hwndDlg, buf2);
+
+ GetDlgItemTextA(hwndDlg, IDC_JOIN, buf, sizeof(buf));
+ _snprintf(buf2, sizeof(buf), buf, szOtherCaller);
+ SetDlgItemTextA(hwndDlg, IDC_JOIN, buf2);
+
+ GetDlgItemTextA(hwndDlg, IDC_HOLD, buf, sizeof(buf));
+ _snprintf(buf2, sizeof(buf), buf, szOtherCaller);
+ SetDlgItemTextA(hwndDlg, IDC_HOLD, buf2);
+
+ return TRUE;
+ }
+
+ // No other call in progress, no need for this Dlg., just answer the call
+ SkypeSend("SET %s STATUS INPROGRESS", dbv.pszVal);
+ testfor ("ERROR", 200);
+ db_free(&dbv);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_JOIN:
+ case IDC_HOLD:
+ case IDC_HANGUP:
+ CheckRadioButton(hwndDlg, IDC_JOIN, IDC_HANGUP, (selected=LOWORD(wParam)));
+ break;
+ case IDOK:
+ {
+ char *szIdCall2;
+
+ switch (selected) {
+ case IDC_JOIN:
+ if (szIdCall2=strchr(dbv2.pszVal, ' '))
+ SkypeSend("SET %s JOIN_CONFERENCE%s", dbv.pszVal, szIdCall2);
+ break;
+ case IDC_HOLD:
+ SkypeSend("SET %s STATUS ONHOLD", dbv2.pszVal);
+ SkypeSend("SET %s STATUS INPROGRESS", dbv.pszVal);
+ break;
+ case IDC_HANGUP:
+ SkypeSend("SET %s STATUS FINISHED", dbv.pszVal);
+ break;
+ }
+
+ db_free(&dbv);
+ db_free(&dbv2);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ }
+ break;
+ case WM_DESTROY:
+ Utils_SaveWindowPosition(hwndDlg, NULL, SKYPE_PROTONAME, "CALLSTATdlg");
+ break;
+ }
+ return FALSE;
+}
+
+
+/* SkypeOutCallErrorCheck
+ *
+ * Purpose: Checks, if an error has occured after call and
+ * if so, hangs up the call
+ * This procedure is a seperate thread to not block the core
+ * while waiting for "ERROR"
+ * Params : szCallId - ID of the call
+ */
+void SkypeOutCallErrorCheck(char *szCallId) {
+ if (testfor("ERROR", 500)) EndCallThread(szCallId);
+}
+
+/* SkypeOutCall
+ *
+ * Purpose: Give a SkypeOut call to the given User in wParam
+ * or hangs up existing call
+ * The user's record is searched for Phone-number entries.
+ * If there is more than 1 entry, the Dial-Dialog is shown
+ * Params : wParam - Handle to the User to be called
+ * If NULL, the dial-dialog is shown
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeOutCall(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ int res = -1;
+
+ if (wParam && !db_get_s((HANDLE)wParam, SKYPE_PROTONAME, "CallId", &dbv)) {
+ res=SkypeSend("SET %s STATUS FINISHED", dbv.pszVal);
+ pthread_create(( pThreadFunc )SkypeOutCallErrorCheck, _strdup(dbv.pszVal));
+ db_free(&dbv);
+ } else if (!CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIAL), NULL, DialDlgProc, (LPARAM)wParam)) return -1;
+ return res;
+}
+
+/* SkypeHoldCall
+ *
+ * Purpose: Put the call to the User given in wParam on Hold or Resumes it
+ * Params : wParam - Handle to the User
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeHoldCall(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ int retval;
+
+ LOG(("SkypeHoldCall started"));
+ if (!wParam || db_get_s((HANDLE)wParam, SKYPE_PROTONAME, "CallId", &dbv))
+ return -1;
+ retval = SkypeSend ("SET %s STATUS %s", dbv.pszVal,
+ db_get_b((HANDLE)wParam, SKYPE_PROTONAME, "OnHold", 0)?"INPROGRESS":"ONHOLD");
+ db_free(&dbv);
+ return retval;
+}
+
+/* SkypeAnswerCall
+ *
+ * Purpose: Answer a Skype-call when a user double-clicks on
+ * The incoming-call-Symbol. Works for both, Skype and SkypeOut-calls
+ * Params : wParam - Not used
+ * lParam - CLISTEVENT*
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeAnswerCall(WPARAM wParam, LPARAM lParam) {
+
+ LOG(("SkypeAnswerCall started"));
+ CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_CALLSTAT), NULL, CallstatDlgProc, (LPARAM)((CLISTEVENT*)lParam)->hContact);
+ return 0;
+}
+/* SkypeSetNick
+ *
+ * Purpose: Set Full Name in profile
+ * Params : wParam=0
+ * lParam=(LPARAM)(const char*)Nick text
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeSetNick(WPARAM wParam, LPARAM lParam) {
+ int retval = -1;
+ char *Nick = NULL;
+
+ if (wParam & SMNN_UNICODE)
+ {
+ db_set_ws(0, SKYPE_PROTONAME, "Nick", (WCHAR*)lParam);
+ if (AttachStatus == SKYPECONTROLAPI_ATTACH_SUCCESS &&
+ !(Nick = (char*)make_utf8_string((WCHAR*)lParam))) return -1;
+ }
+ else
+ {
+ db_set_s(0, SKYPE_PROTONAME, "Nick", (char*)lParam);
+ if(AttachStatus == SKYPECONTROLAPI_ATTACH_SUCCESS &&
+ utf8_encode((const char *)lParam, &Nick) == -1 ) return -1;
+ }
+ if(AttachStatus == SKYPECONTROLAPI_ATTACH_SUCCESS)
+ retval = SkypeSend("SET PROFILE FULLNAME %s", Nick);
+ if (Nick) free (Nick);
+
+ return retval;
+
+}
+/* SkypeSetAwayMessage
+ *
+ * Purpose: Set Mood message in profile
+ * Params : wParam=status mode
+ * lParam=(LPARAM)(const char*)message text
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeSetAwayMessage(WPARAM wParam, LPARAM lParam) {
+ int retval = -1;
+ char *Mood = NULL;
+
+ if (!lParam) lParam=(LPARAM)"";
+ if(utf8_encode((const char *)lParam, &Mood) == -1 ) return -1;
+ db_set_s(NULL, SKYPE_PROTONAME, "MoodText", (const char *)lParam);
+
+ if(AttachStatus == SKYPECONTROLAPI_ATTACH_SUCCESS)
+ retval = SkypeSend("SET PROFILE MOOD_TEXT %s", Mood);
+ free (Mood);
+
+ return retval;
+}
+INT_PTR SkypeSetAwayMessageW(WPARAM wParam, LPARAM lParam) {
+ int retval = -1;
+ char *Mood = NULL;
+
+ if (!lParam) lParam=(LPARAM)"";
+ if (!(Mood = (char*)make_utf8_string((WCHAR*)lParam))) return -1;
+ db_set_ws(NULL, SKYPE_PROTONAME, "MoodText", (WCHAR*)lParam);
+
+ if(AttachStatus == SKYPECONTROLAPI_ATTACH_SUCCESS)
+ retval = SkypeSend("SET PROFILE MOOD_TEXT %s", Mood);
+ free (Mood);
+
+ return retval;
+}
+
+/* SkypeSetAvatar
+ *
+ * Purpose: Set user avatar in profile
+ * Params : wParam=0
+ * lParam=(LPARAM)(const char*)filename
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeSetAvatar(WPARAM wParam, LPARAM lParam) {
+ char *filename = (char *) lParam, *ext;
+ char AvatarFile[MAX_PATH+1], OldAvatarFile[1024];
+ char *ptr = NULL;
+ int ret;
+ char command[500];
+ DBVARIANT dbv = {0};
+ BOOL hasOldAvatar = (db_get_s(NULL, SKYPE_PROTONAME, "AvatarFile", &dbv) == 0 && dbv.type == DBVT_ASCIIZ);
+ size_t len;
+
+ if (AttachStatus != SKYPECONTROLAPI_ATTACH_SUCCESS)
+ return -3;
+
+ if (filename == NULL)
+ return -1;
+ len = strlen(filename);
+ if (len < 4)
+ return -1;
+
+ ext = &filename[len-4];
+ if (_stricmp(ext, ".jpg")==0 || _stricmp(ext-1, ".jpeg")==0)
+ ext = "jpg";
+ else if (_stricmp(ext, ".png")==0)
+ ext = "png";
+ else
+ return -2;
+
+ FoldersGetCustomPath(hProtocolAvatarsFolder, AvatarFile, sizeof(AvatarFile), DefaultAvatarsFolder);
+ if (!*AvatarFile) strcpy (AvatarFile, DefaultAvatarsFolder);
+ mir_snprintf(AvatarFile, sizeof(AvatarFile), "%s\\%s avatar.%s", AvatarFile, SKYPE_PROTONAME, ext);
+
+ // Backup old file
+ if (hasOldAvatar)
+ {
+ strncpy(OldAvatarFile, dbv.pszVal, sizeof(OldAvatarFile)-4);
+ OldAvatarFile[sizeof(OldAvatarFile)-5] = '\0';
+ strcat(OldAvatarFile, "_old");
+ DeleteFileA(OldAvatarFile);
+ if (!MoveFileA(dbv.pszVal, OldAvatarFile))
+ {
+ db_free(&dbv);
+ return -3;
+ }
+ }
+
+ // Copy new file
+ if (!CopyFileA(filename, AvatarFile, FALSE))
+ {
+ if (hasOldAvatar)
+ {
+ MoveFileA(OldAvatarFile, dbv.pszVal);
+ db_free(&dbv);
+ }
+ return -3;
+ }
+
+ // Try to set with skype
+ mir_snprintf(command, sizeof(command), "SET AVATAR 1 %s", AvatarFile);
+ if (SkypeSend(command) || (ptr = SkypeRcv(command+4, INFINITE)) == NULL || !strncmp(ptr, "ERROR", 5))
+ {
+ DeleteFileA(AvatarFile);
+
+ if (hasOldAvatar)
+ MoveFileA(OldAvatarFile, dbv.pszVal);
+
+ ret = -4;
+ }
+ else
+ {
+ if (hasOldAvatar)
+ DeleteFileA(OldAvatarFile);
+
+ db_set_s(NULL, SKYPE_PROTONAME, "AvatarFile", AvatarFile);
+
+ ret = 0;
+ }
+
+ if (ptr != NULL)
+ free(ptr);
+
+ if (hasOldAvatar)
+ db_free(&dbv);
+
+ return ret;
+}
+
+
+/* SkypeSendFile
+ *
+ * Purpose: Opens the Skype-dialog to send a file
+ * Params : wParam - Handle to the User
+ * lParam - Not used
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeSendFile(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ int retval;
+
+ if (!wParam || db_get_s((HANDLE)wParam, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return -1;
+ retval=SkypeSend("OPEN FILETRANSFER %s", dbv.pszVal);
+ db_free(&dbv);
+ return retval;
+}
+
+/* SkypeChatCreate
+ *
+ * Purpose: Creates a groupchat with the user
+ * Params : wParam - Handle to the User
+ * lParam - Not used
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeChatCreate(WPARAM wParam, LPARAM lParam) {
+ DBVARIANT dbv;
+ HANDLE hContact=(HANDLE)wParam;
+ char *ptr, *ptr2;
+
+ if (!hContact || db_get_s(hContact, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return -1;
+ // Flush old messages
+ while (testfor("\0CHAT \0 STATUS \0", 0));
+ if (SkypeSend("CHAT CREATE %s", dbv.pszVal) || !(ptr=SkypeRcv ("\0CHAT \0 STATUS \0", INFINITE)))
+ {
+ db_free(&dbv);
+ return -1;
+ }
+ db_free(&dbv);
+ if (ptr2=strstr (ptr, "STATUS")) {
+ *(ptr2-1)=0;
+ ChatStart (ptr+5, FALSE);
+ }
+ free(ptr);
+ return 0;
+}
+
+/* SkypeAdduserDlg
+ *
+ * Purpose: Show Skype's Add user Dialog
+ */
+INT_PTR SkypeAdduserDlg(WPARAM wParam, LPARAM lParam) {
+ SkypeSend("OPEN ADDAFRIEND");
+ return 0;
+}
+
+/* SkypeFlush
+ *
+ * Purpose: Flush the Skype Message-List
+ */
+void SkypeFlush(void) {
+ char *ptr;
+
+ while ((ptr=SkypeRcv(NULL, 0))!=NULL) free(ptr);
+}
+
+/* SkypeStatusToMiranda
+ *
+ * Purpose: Converts the specified Skype-Status mode to the corresponding Miranda-Status mode
+ * Params : s - Skype Status
+ * Returns: The correct Status
+ * 0 - Nothing found
+ */
+int SkypeStatusToMiranda(char *s) {
+ int i;
+ if (!strcmp("SKYPEOUT", s)) return db_get_dw(NULL, SKYPE_PROTONAME, "SkypeOutStatusMode", ID_STATUS_ONTHEPHONE);
+ for(i=0; status_codes[i].szStat; i++)
+ if (!strcmp(status_codes[i].szStat, s))
+ return status_codes[i].id;
+ return 0;
+}
+
+/* MirandaStatusToSkype
+ *
+ * Purpose: Converts the specified Miranda-Status mode to the corresponding Skype-Status mode
+ * Params : id - Miranda Status
+ * Returns: The correct Status
+ * NULL - Nothing found
+ */
+char *MirandaStatusToSkype(int id) {
+ int i;
+ if (db_get_b(NULL, SKYPE_PROTONAME, "NoSkype3Stats", 0)) {
+ switch (id)
+ {
+ case ID_STATUS_NA: return "AWAY";
+ case ID_STATUS_FREECHAT: return "ONLINE";
+ }
+ }
+ for(i=0; status_codes[i].szStat; i++)
+ if (status_codes[i].id==id)
+ return status_codes[i].szStat;
+ return NULL;
+}
+
+/* GetSkypeErrorMsg
+ *
+ * Purpose: Get a human-readable Error-Message for the supplied Skype Error-Message
+ * Params : str - Skype Error-Message string
+ * Returns: Human-readable Error Message or NULL, if nothing was found
+ * Warning: Don't forget to free() return value
+ */
+char *GetSkypeErrorMsg(char *str) {
+ char *pos, *reason, *msg;
+
+ LOG (("GetSkypeErrorMsg received error: %s", str));
+ if (!strncmp(str, "ERROR", 5)) {
+ reason=_strdup(str);
+ return reason;
+ }
+ if ((pos=strstr(str, "FAILURE")) ) {
+ switch(atoi(pos+14)) {
+ case MISC_ERROR: msg="Misc. Error"; break;
+ case USER_NOT_FOUND: msg="User does not exist, check username"; break;
+ case USER_NOT_ONLINE: msg="Trying to send IM to an user, who is not online"; break;
+ case USER_BLOCKED: msg="IM blocked by recipient"; break;
+ case TYPE_UNSUPPORTED: msg="Type unsupported"; break;
+ case SENDER_NOT_FRIEND: msg="Sending IM message to user, who has not added you to friendslist and has chosen 'only people in my friendslist can start IM'"; break;
+ case SENDER_NOT_AUTHORIZED: msg="Sending IM message to user, who has not authorized you and has chosen 'only people whom I have authorized can start IM'"; break;
+ default: msg="Unknown error";
+ }
+ reason=(char *)malloc(strlen(pos)+strlen(msg)+3);
+ sprintf (reason, "%s: %s", pos, msg);
+ return reason;
+ }
+ return NULL;
+}
+
+/* testfor
+ *
+ * Purpose: Wait, until the given Message-Fragment is received from Skype within
+ * the given amount of time
+ * Params : see SkypeRcv
+ * Returns: TRUE - Message was received within the given amount of time
+ * FALSE- nope, sorry
+ */
+BOOL testfor(char *what, DWORD maxwait) {
+ char *res;
+
+ if ((res=SkypeRcv(what, maxwait))==NULL) return FALSE;
+ free(res);
+ return TRUE;
+}
+
+char SendSkypeproxyCommand(char command) {
+ int length=0;
+ char reply=0;
+ BOOL res;
+
+ res = send(ClientSocket, (char *)&length, sizeof(length), 0)==SOCKET_ERROR
+ || send(ClientSocket, (char *)&command, sizeof(command), 0)==SOCKET_ERROR
+ || recv(ClientSocket, (char *)&reply, sizeof(reply), 0)==SOCKET_ERROR;
+ if (res)
+ return -1;
+ else
+ return reply;
+}
+
+/* ConnectToSkypeAPI
+ *
+ * Purpose: Establish a connection to the Skype API
+ * Params : path - Path to the Skype application
+ * iStart - Need to start skype for status change.
+ * 1 = Normal start if Skype not running
+ * 2 = Forced startp code execution no matter what
+ * Returns: 0 - Connecting succeeded
+ * -1 - Something went wrong
+ */
+int ConnectToSkypeAPI(char *path, int iStart) {
+ static int iRet = -1; // last request result
+ static volatile long newRequest = TRUE;
+
+ InterlockedExchange(&newRequest, TRUE); // place new request
+ EnterCriticalSection(&ConnectMutex); // Prevent reentrance
+ if (iRet == -1 || newRequest)
+ {
+ iRet = _ConnectToSkypeAPI(path, iStart);
+ InterlockedExchange(&newRequest, FALSE); // every thread which is waiting for connect mutex will get our result as well.. but subsequent calls will set this value to true and call _Connect again
+ }
+ LeaveCriticalSection(&ConnectMutex);
+ return iRet;
+}
+
+void TranslateMirandaRelativePathToAbsolute(LPCSTR cszPath, LPSTR szAbsolutePath, BOOL fQuoteSpaces) {
+ *szAbsolutePath = 0;
+ CallService (MS_UTILS_PATHTOABSOLUTE, (WPARAM)(*cszPath ? cszPath : ".\\"), (LPARAM)szAbsolutePath);
+ if(fQuoteSpaces && strchr((LPCSTR)szAbsolutePath, ' ')){
+ memmove (szAbsolutePath+1, szAbsolutePath, strlen(szAbsolutePath)+1);
+ *szAbsolutePath='"';
+ strcat (szAbsolutePath, "\"");
+ }
+
+ TRACEA(szAbsolutePath);
+}
+
+static int my_spawnv(const char *cmdname, const char *const *argv, PROCESS_INFORMATION *pi)
+{
+ int i, iLen=0;
+ char *CommandLine;
+ STARTUPINFOA si={0};
+ BOOL bRet;
+
+ memset (pi, 0, sizeof(PROCESS_INFORMATION));
+ for (i=0; argv[i]; i++) iLen+=strlen(argv[i])+1;
+ if (!(CommandLine = (char*)calloc(1, iLen))) return -1;
+ for (i=0; argv[i]; i++) {
+ if (i) strcat (CommandLine, " ");
+ strcat (CommandLine, argv[i]);
+ }
+ si.cb = sizeof(si);
+
+ bRet = CreateProcessA( cmdname,CommandLine,NULL,NULL,FALSE,0,NULL,NULL,&si,pi);
+ free(CommandLine);
+ if (!bRet) return -1;
+ return (DWORD)pi->hProcess;
+}
+
+static int _ConnectToSkypeAPI(char *path, int iStart) {
+ BOOL SkypeLaunched=FALSE;
+ BOOL UseCustomCommand = db_get_b(NULL, SKYPE_PROTONAME, "UseCustomCommand", 0);
+ int counter=0, i, j, maxattempts=db_get_w(NULL, SKYPE_PROTONAME, "ConnectionAttempts", 10);
+ char *args[16], *pFree = NULL;
+ char *SkypeOptions[]={"/notray", "/nosplash", "/minimized", "/removable", "/datapath:", "/secondary"};
+ const int SkypeDefaults[]={0, 1, 1, 0, 0};
+
+ char szAbsolutePath[MAX_PATH];
+
+ LOG(("ConnectToSkypeAPI started."));
+ if (UseSockets)
+ {
+ SOCKADDR_IN service;
+ DBVARIANT dbv;
+ long inet;
+ struct hostent *hp;
+
+ LOG(("ConnectToSkypeAPI: Connecting to Skype2socket socket..."));
+ if ((ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET) return -1;
+
+ if (!db_get_s(NULL, SKYPE_PROTONAME, "Host", &dbv)) {
+ if ((inet=inet_addr(dbv.pszVal))==-1) {
+ if (hp=gethostbyname(dbv.pszVal))
+ memcpy(&inet, hp->h_addr, sizeof(inet));
+ else {
+ OUTPUT(_T("Cannot resolve host!"));
+ db_free(&dbv);
+ return -1;
+ }
+ }
+ db_free(&dbv);
+ } else {
+ OUTPUT(_T("Cannot find valid host to connect to."));
+ return -1;
+ }
+
+ service.sin_family = AF_INET;
+ service.sin_addr.s_addr = inet;
+ service.sin_port = htons((unsigned short)db_get_w(NULL, SKYPE_PROTONAME, "Port", 1401));
+
+ if ( connect( ClientSocket, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR) return -1;
+
+ if (db_get_b(NULL, SKYPE_PROTONAME, "RequiresPassword", 0) && !db_get_s(NULL, SKYPE_PROTONAME, "Password", &dbv))
+ {
+ char reply=0;
+
+ CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM)dbv.pszVal);
+ if ((reply=SendSkypeproxyCommand(AUTHENTICATE))==-1)
+ {
+ db_free(&dbv);
+ return -1;
+ }
+ if (!reply) {
+ OUTPUT(_T("Authentication is not supported/needed for this Skypeproxy server. It will be disabled."));
+ db_set_b(NULL, SKYPE_PROTONAME, "RequiresPassword", 0);
+ } else {
+ unsigned int length=(unsigned int)strlen(dbv.pszVal);
+ BOOL res;
+ res = send(ClientSocket, (char *)&length, sizeof(length), 0)==SOCKET_ERROR
+ || send(ClientSocket, dbv.pszVal, length, 0)==SOCKET_ERROR
+ || recv(ClientSocket, (char *)&reply, sizeof(reply), 0)==SOCKET_ERROR;
+ if (res)
+ {
+ db_free(&dbv);
+ return -1;
+ }
+ if (!reply)
+ {
+ OUTPUT(_T("Authentication failed for this server, connection was not successful. Verify that your password is correct!"));
+ db_free(&dbv);
+ return -1;
+ }
+ }
+ db_free(&dbv);
+ }
+ else
+ {
+ char reply=0;
+
+ if ((reply=SendSkypeproxyCommand(CAPABILITIES))==-1) return -1;
+ if (reply&USE_AUTHENTICATION) {
+ OUTPUT(_T("The server you specified requires authentication, but you have not supplied a password for it. Check the Skype plugin settings and try again."));
+ return -1;
+ }
+ }
+
+
+ if (!rcvThreadRunning)
+ if(_beginthread(( pThreadFunc )rcvThread, 0, NULL)==-1) return -1;
+
+ AttachStatus=SKYPECONTROLAPI_ATTACH_SUCCESS;
+ return 0;
+ }
+
+ if (pszProxyCallout)
+ {
+ if (SkypeSend("SET USERSTATUS ONLINE")==-1)
+ {
+ AttachStatus=SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE;
+ return -1;
+ }
+ for ( ;; ) {
+ char *ptr = SkypeRcv ("CONNSTATUS", INFINITE);
+ if (!ptr)
+ {
+ AttachStatus=SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE;
+ return -1;
+ }
+
+ if (strcmp (ptr+11, "CONNECTING"))
+ {
+ free (ptr);
+ break;
+ }
+ free (ptr);
+ }
+
+ AttachStatus=SKYPECONTROLAPI_ATTACH_SUCCESS;
+ return 0;
+ }
+
+ do
+ {
+ int retval;
+ /* To initiate communication, Client should broadcast windows message
+ ('SkypeControlAPIDiscover') to all windows in the system, specifying its own
+ window handle in wParam parameter.
+ */
+ if (iStart != 2 || counter)
+ {
+ LOG(("ConnectToSkypeAPI sending discover message.. hWnd=%08X", (long)g_hWnd));
+ retval=SendMessageTimeout(HWND_BROADCAST, ControlAPIDiscover, (WPARAM)g_hWnd, 0, SMTO_ABORTIFHUNG, 3000, NULL);
+ LOG(("ConnectToSkypeAPI sent discover message returning %d", retval));
+ }
+
+ /* In response, Skype responds with
+ message 'SkypeControlAPIAttach' to the handle specified, and indicates
+ connection status
+ SkypeReady is set if there is an answer by Skype other than API_AVAILABLE.
+ If there is no answer after 3 seconds, launch Skype as it's propably
+ not running.
+ */
+ if (iStart == 2 || (WaitForSingleObject(SkypeReady, 3000)==WAIT_TIMEOUT && AttachStatus!=SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION))
+ {
+ if (iStart != 2 && g_hWnd==NULL)
+ {
+ LOG(("ConnectToSkypeAPI: hWnd of SkypeDispatchWindow not yet set.."));
+ continue;
+ }
+ if ((iStart == 2 || !SkypeLaunched) && (path || UseCustomCommand))
+ {
+ static PROCESS_INFORMATION pi={0};
+ DWORD dwExitStatus = 0;
+
+ if ((!pi.hProcess || !GetExitCodeProcess(pi.hProcess, &dwExitStatus) || dwExitStatus != STILL_ACTIVE) &&
+ (db_get_b(NULL, SKYPE_PROTONAME, "StartSkype", 1) || iStart))
+ {
+ LOG(("ConnectToSkypeAPI Starting Skype, as it's not running"));
+
+ j=1;
+ for (i=0; i<sizeof(SkypeOptions)/sizeof(SkypeOptions[0]); i++)
+ if (db_get_b(NULL, SKYPE_PROTONAME, SkypeOptions[i]+1, SkypeDefaults[i])) {
+ DBVARIANT dbv;
+
+ switch (i)
+ {
+ case 4:
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"datapath",&dbv))
+ {
+ int paramSize;
+ TranslateMirandaRelativePathToAbsolute(dbv.pszVal, szAbsolutePath, TRUE);
+ paramSize = strlen(SkypeOptions[i]) + strlen(szAbsolutePath);
+ pFree = args[j] = (char*)malloc(paramSize + 1);
+ sprintf(args[j],"%s%s",SkypeOptions[i],szAbsolutePath);
+ db_free(&dbv);
+ }
+ break;
+ case 2:
+ args[j++]="/legacylogin";
+ default:
+ args[j]=SkypeOptions[i];
+ break;
+ }
+ LOG(("Using Skype parameter: %s", args[j]));
+ //MessageBox(NULL,"Using Skype parameter: ",args[j],0);
+ j++;
+ }
+ args[j]=NULL;
+
+ if(UseCustomCommand)
+ {
+ DBVARIANT dbv;
+
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"CommandLine",&dbv))
+ {
+ TranslateMirandaRelativePathToAbsolute(dbv.pszVal, szAbsolutePath, FALSE);
+ args[0] = (LPSTR)szAbsolutePath;
+ LOG(("ConnectToSkypeAPI: Launch skype using command line"));
+ if (!*szAbsolutePath || my_spawnv(szAbsolutePath, args, &pi) == -1) {
+ LOG(("ConnectToSkypeAPI: Failed to launch skype!"));
+ } else {
+ WaitForInputIdle((HANDLE)pi.hProcess, 5000);
+ setUserNamePassword(pi.dwProcessId);
+ }
+ db_free(&dbv);
+ }
+ }
+ else
+ {
+ args[0]=path;
+ LOG(("ConnectToSkypeAPI: Launch skype"));
+ /*for(int i=0;i<j;i++)
+ {
+ if(args[i] != NULL)
+ LOG("ConnectToSkypeAPI", args[i]);
+ }*/
+
+ // if there is no skype installed and no custom command line, then exit .. else it crashes
+ if (args[0] == NULL || strlen(args[0])==0)
+ {
+ return -1;
+ }
+ if (my_spawnv(path, args, &pi) != -1) {
+ WaitForInputIdle((HANDLE)pi.hProcess, 5000);
+ setUserNamePassword(pi.dwProcessId);
+ }
+ }
+ if (pFree) free(pFree);
+ }
+ ResetEvent(SkypeReady);
+ SkypeLaunched=TRUE;
+ LOG(("ConnectToSkypeAPI: Skype process started."));
+ // Skype launching iniciated, keep sending Discover messages until it responds.
+ continue;
+ }
+ else
+ {
+ LOG(("ConnectToSkypeAPI: Check if Skype was launchable.."));
+ if (db_get_b(NULL, SKYPE_PROTONAME, "StartSkype", 1) && !(path || UseCustomCommand)) return -1;
+ LOG(("Trying to attach: #%d", counter));
+ counter++;
+ if (counter>=maxattempts && AttachStatus==-1)
+ {
+ int oldstatus=SkypeStatus;
+ InterlockedExchange((long *)&SkypeStatus, (int)ID_STATUS_OFFLINE);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ OUTPUT(_T("ERROR: Skype not running / too old / working!"));
+ return -1;
+ }
+ }
+ }
+ LOG(("Attachstatus %d", AttachStatus));
+ } while (AttachStatus==SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE || AttachStatus==SKYPECONTROLAPI_ATTACH_API_AVAILABLE || AttachStatus==-1);
+
+ while (AttachStatus==SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION) Sleep(1000);
+ LOG(("Attachstatus %d", AttachStatus));
+ if (AttachStatus!=SKYPECONTROLAPI_ATTACH_SUCCESS) {
+ int oldstatus;
+
+ switch(AttachStatus) {
+ case SKYPECONTROLAPI_ATTACH_REFUSED:
+ OUTPUT(_T("Skype refused the connection :("));
+ break;
+ case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
+ OUTPUT(_T("The Skype API is not available"));
+ break;
+ default:
+ LOG(("ERROR: AttachStatus: %d", AttachStatus));
+ OUTPUT(_T("Wheee, Skype won't let me use the API. :("));
+ }
+ oldstatus=SkypeStatus;
+ InterlockedExchange((long *)&SkypeStatus, (int)ID_STATUS_OFFLINE);
+ ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) oldstatus, SkypeStatus);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* CloseSkypeAPI
+ * Purpose: Closes existing api connection
+ * Params: path - Path to the Skype application; could be NULL when using proxy
+ * Returns: always 0
+ */
+int CloseSkypeAPI(char *skypePath)
+{
+ char szAbsolutePath[MAX_PATH];
+
+ logoff_contacts(TRUE);
+ if (UseSockets)
+ {
+ if (ClientSocket != INVALID_SOCKET)
+ {
+ closesocket(ClientSocket);
+ ClientSocket = INVALID_SOCKET;
+ }
+ }
+ else {
+ if (!pszProxyCallout)
+ {
+ if (AttachStatus!=-1)
+ {
+ // it was crashing when the skype-network-proxy is used (imo2sproxy for imo.im) and skype-path is empty
+ // now, with the "UseSockets" check and the skypePath[0] != 0 check its fixed
+ if (skypePath != NULL && skypePath[0] != 0) {
+ TranslateMirandaRelativePathToAbsolute(skypePath, szAbsolutePath, FALSE);
+ _spawnl(_P_NOWAIT, szAbsolutePath, szAbsolutePath, "/SHUTDOWN", NULL);
+ }
+ }
+ }
+ }
+ SkypeInitialized=FALSE;
+ ResetEvent(SkypeReady);
+ AttachStatus=-1;
+ if (g_hWnd) KillTimer (g_hWnd, 1);
+ return 0;
+}
+/* ConnectToSkypeAPI
+ *
+ * Purpose: Establish a connection to the Skype API
+ * Params : path - Path to the Skype application
+ * Returns: 0 - Connecting succeeded
+ * -1 - Something went wrong
+ */
+//int __connectAPI(char *path) {
+// int retval;
+//
+// EnterCriticalSection(&ConnectMutex);
+// if (AttachStatus!=-1) {
+// LeaveCriticalSection(&ConnectMutex);
+// return -1;
+// }
+// InterlockedExchange((long *)&SkypeStatus, ID_STATUS_CONNECTING);
+// ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) ID_STATUS_OFFLINE, SkypeStatus);
+// retval=__connectAPI(path);
+// if (retval==-1) {
+// logoff_contacts();
+// InterlockedExchange((long *)&SkypeStatus, ID_STATUS_OFFLINE);
+// ProtoBroadcastAck(SKYPE_PROTONAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE) ID_STATUS_CONNECTING, SkypeStatus);
+// }
+// LeaveCriticalSection(&ConnectMutex);
+// return retval;
+//}
diff --git a/protocols/SkypeClassic/skypeapi.h b/protocols/SkypeClassic/skypeapi.h
new file mode 100644
index 0000000000..fa4f5139a1
--- /dev/null
+++ b/protocols/SkypeClassic/skypeapi.h
@@ -0,0 +1,69 @@
+// Skype API defines
+#define SKYPECONTROLAPI_ATTACH_SUCCESS 0
+#define SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION 1
+#define SKYPECONTROLAPI_ATTACH_REFUSED 2
+#define SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE 3
+#define SKYPECONTROLAPI_ATTACH_API_AVAILABLE 0x8001
+
+#define MISC_ERROR 1
+#define USER_NOT_FOUND 2
+#define USER_NOT_ONLINE 3
+#define USER_BLOCKED 4
+#define TYPE_UNSUPPORTED 5
+#define SENDER_NOT_FRIEND 6
+#define SENDER_NOT_AUTHORIZED 7
+
+#define MAX_ENTRIES 128 // Max. 128 number-Entries in Dial-dlg.
+
+typedef struct {
+ int id;
+ char *szStat;
+} status_map;
+
+// Prototypes
+int SkypeMsgInit(void);
+int SkypeMsgAdd(char *msg);
+void SkypeMsgCleanup(void);
+char *SkypeMsgGet(void);
+int SkypeSend(char*, ...);
+char *SkypeRcv(char *what, DWORD maxwait);
+char *SkypeRcvTime(char *what, time_t st, DWORD maxwait);
+char *SkypeRcvMsg(char *what, time_t st, HANDLE hContact, DWORD maxwait);
+INT_PTR SkypeCall(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeCallHangup(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeOutCall(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeHup(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeHoldCall(WPARAM wParam, LPARAM lParam);
+void SkypeFlush(void);
+int SkypeStatusToMiranda(char *s);
+char *MirandaStatusToSkype(int id);
+char *GetSkypeErrorMsg(char *str);
+BOOL testfor(char *what, DWORD maxwait);
+int ConnectToSkypeAPI(char *path, BOOL bStart);
+int CloseSkypeAPI(char *skypePath);
+INT_PTR SkypeAdduserDlg(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeAnswerCall(WPARAM wParam, LPARAM lParam);
+int SkypeMsgCollectGarbage(time_t age);
+INT_PTR SkypeSendFile(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSetAvatar(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSetAwayMessage(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSetAwayMessageW(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeSetNick(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeChatCreate(WPARAM wParam, LPARAM lParam);
+int SkypeSetProfile(char *szProperty, char *szValue);
+char *SkypeGet(char *szWhat, char *szWho, char *szProperty);
+char *SkypeGetID(char *szWhat, char *szWho, char *szProperty);
+char *SkypeGetErr(char *szWhat, char *szWho, char *szProperty);
+#ifdef _UNICODE
+WCHAR *SkypeGetW(char *szWhat, WCHAR *szWho, char *szProperty);
+WCHAR *SkypeGetErrW(char *szWhat, TCHAR *szWho, char *szProperty);
+#define SkypeGetT SkypeGetW
+#define SkypeGetErrT SkypeGetErrW
+#else
+#define SkypeGetT SkypeGet
+#define SkypeGetErrT SkypeGetErr
+#endif
+char *SkypeGetProfile(char *szProperty);
+void SetUserNamePassword();
+INT_PTR SkypeAdduserDlg(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeReceivedAPIMessage(WPARAM wParam, LPARAM lParam);
diff --git a/protocols/SkypeClassic/skypeopt.cpp b/protocols/SkypeClassic/skypeopt.cpp
new file mode 100644
index 0000000000..60854fbe62
--- /dev/null
+++ b/protocols/SkypeClassic/skypeopt.cpp
@@ -0,0 +1,968 @@
+#include "skype.h"
+#include "skypeopt.h"
+#include "pthread.h"
+#include "gchat.h"
+#include "skypeprofile.h"
+#if(WINVER >= 0x0500)
+#include "uxtheme.h"
+#define HAVE_UXTHEMES
+#endif
+
+#ifdef SKYPE_AUTO_DETECTION
+#include "ezxml/ezxml.c"
+#endif
+
+#ifdef UNICODE
+#include "utf8.h"
+#endif
+
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+// VC6 SDK defines
+#ifndef BIF_SHAREABLE
+#define BIF_SHAREABLE 0x8000 // sharable resources displayed (remote shares, requires BIF_USENEWUI)
+#endif
+#ifndef BIF_NEWDIALOGSTYLE
+#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
+#endif // Caller needs to call OleInitialize() before using this API
+#ifndef BIF_NONEWFOLDERBUTTON
+#define BIF_NONEWFOLDERBUTTON 0x0200 // Do not add the "New Folder" button to the dialog. Only applicable with BIF_NEWDIALOGSTYLE.
+#endif
+
+
+extern HINSTANCE hInst;
+extern char protocol, g_szProtoName[];
+extern BOOL SkypeInitialized, bProtocolSet, bIsImoproxy;
+extern DWORD mirandaVersion;
+
+BOOL showPopup, showPopupErr, popupWindowColor, popupWindowColorErr;
+unsigned int popupBackColor, popupBackColorErr;
+unsigned int popupTextColor, popupTextColorErr;
+int popupTimeSec, popupTimeSecErr;
+POPUPDATAT InCallPopup;
+POPUPDATAT ErrorPopup;
+
+static SkypeProfile myProfile;
+static HBITMAP hAvatar = NULL;
+
+extern BOOL PopupServiceExists;
+extern BOOL (WINAPI *MyEnableThemeDialogTexture)(HANDLE, DWORD);
+
+int RegisterOptions(WPARAM wParam, LPARAM lParam) {
+ OPTIONSDIALOGPAGE odp;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ ZeroMemory(&odp, sizeof(odp));
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS);
+ odp.pszGroup = "Network";
+ odp.pszTitle = SKYPE_PROTONAME;
+ odp.pfnDlgProc = OptionsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ Options_AddPage(wParam, &odp);
+
+ if(PopupServiceExists)
+ {
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_POPUP);
+ odp.pszGroup = "Popups";
+ odp.pfnDlgProc = OptPopupDlgProc;
+ Options_AddPage(wParam, &odp);
+ }
+
+ return 0;
+}
+
+INT_PTR CALLBACK OptPopupDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static RECT r;
+
+ switch ( msg )
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwnd );
+ // Message Popup
+ popupTimeSec = db_get_dw(NULL, SKYPE_PROTONAME, "popupTimeSec", 4);
+ popupTextColor = db_get_dw(NULL, SKYPE_PROTONAME, "popupTextColor", GetSysColor(COLOR_WINDOWTEXT));
+ popupBackColor = db_get_dw(NULL, SKYPE_PROTONAME, "popupBackColor", GetSysColor(COLOR_BTNFACE));
+ popupWindowColor = db_get_b(NULL, SKYPE_PROTONAME, "popupWindowColor", FALSE);
+ showPopup = db_get_b(NULL, SKYPE_PROTONAME, "showPopup", TRUE);
+ // ERROR Message Popup
+ popupTimeSecErr = db_get_dw(NULL, SKYPE_PROTONAME, "popupTimeSecErr", 4);
+ popupTextColorErr = db_get_dw(NULL, SKYPE_PROTONAME, "popupTextColorErr", GetSysColor(COLOR_WINDOWTEXT));
+ popupBackColorErr = db_get_dw(NULL, SKYPE_PROTONAME, "popupBackColorErr", GetSysColor(COLOR_BTNFACE));
+ popupWindowColorErr = db_get_b(NULL, SKYPE_PROTONAME, "popupWindowColorErr", FALSE);
+ showPopupErr = db_get_b(NULL, SKYPE_PROTONAME, "showPopupErr", TRUE);
+
+ EnableWindow(GetDlgItem(hwnd,IDC_USEWINCOLORS),showPopup);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPBACKCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPBACKCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTEXTCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPTEXTCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTIME),showPopup);
+ EnableWindow(GetDlgItem(hwnd,IDC_PREVIEW),showPopup);
+ EnableWindow(GetDlgItem(hwnd,IDC_USEWINCOLORSERR),showPopupErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPBACKCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPBACKCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTEXTCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPTEXTCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTIMEERR),showPopupErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_PREVIEWERR),showPopupErr);
+ CheckDlgButton(hwnd, IDC_POPUPINCOMING, (WPARAM) showPopup);
+ CheckDlgButton(hwnd, IDC_USEWINCOLORS, (WPARAM) popupWindowColor);
+ CheckDlgButton(hwnd, IDC_POPUPERROR, (WPARAM) showPopupErr);
+ CheckDlgButton(hwnd, IDC_USEWINCOLORSERR, (WPARAM) popupWindowColorErr);
+ SendDlgItemMessage(hwnd, IDC_POPUPTIME, EM_SETLIMITTEXT, 3, 0L);
+ SetDlgItemInt(hwnd, IDC_POPUPTIME, popupTimeSec,FALSE);
+ SendDlgItemMessage(hwnd, IDC_POPUPTIMEERR, EM_SETLIMITTEXT, 3, 0L);
+ SetDlgItemInt(hwnd, IDC_POPUPTIMEERR, popupTimeSecErr,FALSE);
+ SendDlgItemMessage(hwnd, IDC_POPUPBACKCOLOR, CPM_SETCOLOUR,0, popupBackColor);
+ SendDlgItemMessage(hwnd, IDC_POPUPBACKCOLOR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(hwnd, IDC_POPUPTEXTCOLOR, CPM_SETCOLOUR,0, popupTextColor);
+ SendDlgItemMessage(hwnd, IDC_POPUPTEXTCOLOR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_WINDOWTEXT));
+ SendDlgItemMessage(hwnd, IDC_POPUPBACKCOLORERR, CPM_SETCOLOUR,0, popupBackColorErr);
+ SendDlgItemMessage(hwnd, IDC_POPUPBACKCOLORERR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(hwnd, IDC_POPUPTEXTCOLORERR, CPM_SETCOLOUR,0, popupTextColorErr);
+ SendDlgItemMessage(hwnd, IDC_POPUPTEXTCOLORERR, CPM_SETDEFAULTCOLOUR, 0, GetSysColor(COLOR_WINDOWTEXT));
+
+
+ return TRUE;
+ break;
+
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom)
+ {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ db_set_dw(NULL, SKYPE_PROTONAME, "popupBackColor", popupBackColor);
+ db_set_dw(NULL, SKYPE_PROTONAME, "popupTextColor", popupTextColor);
+ db_set_dw(NULL, SKYPE_PROTONAME, "popupTimeSec", popupTimeSec);
+ db_set_b(NULL, SKYPE_PROTONAME, "popupWindowColor", (BYTE)popupWindowColor);
+ db_set_b(NULL, SKYPE_PROTONAME, "showPopup", (BYTE)showPopup);
+ db_set_dw(NULL, SKYPE_PROTONAME, "popupBackColorErr", popupBackColorErr);
+ db_set_dw(NULL, SKYPE_PROTONAME, "popupTextColorErr", popupTextColorErr);
+ db_set_dw(NULL, SKYPE_PROTONAME, "popupTimeSecErr", popupTimeSecErr);
+ db_set_b(NULL, SKYPE_PROTONAME, "popupWindowColorErr", (BYTE)popupWindowColorErr);
+ db_set_b(NULL, SKYPE_PROTONAME, "showPopupErr", (BYTE)showPopupErr);
+ break;
+ }
+ }
+ break;
+
+
+
+ case WM_COMMAND:
+ switch( LOWORD( wParam ))
+ {
+ case IDC_PREVIEW:
+ {
+ HANDLE hContact;
+ TCHAR * lpzContactName;
+
+ hContact = db_find_first();
+ lpzContactName = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)hContact,GCDNF_TCHAR);
+ InCallPopup.lchContact = hContact;
+ InCallPopup.lchIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALL));
+ InCallPopup.colorBack = ! popupWindowColor ? popupBackColor : GetSysColor(COLOR_BTNFACE);
+ InCallPopup.colorText = ! popupWindowColor ? popupTextColor : GetSysColor(COLOR_WINDOWTEXT);
+ InCallPopup.iSeconds = popupTimeSec;
+ InCallPopup.PluginData = (void *)1;
+
+ lstrcpy(InCallPopup.lptzText, TranslateT("Incoming Skype Call"));
+
+ lstrcpy(InCallPopup.lptzContactName, lpzContactName);
+
+ CallService(MS_POPUP_ADDPOPUPT,(WPARAM)&InCallPopup,0);
+
+
+ break;
+ }
+ case IDC_PREVIEWERR:
+ ErrorPopup.lchContact = NULL;
+ ErrorPopup.lchIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_CALL));
+ ErrorPopup.colorBack = ! popupWindowColorErr ? popupBackColorErr : GetSysColor(COLOR_BTNFACE);
+ ErrorPopup.colorText = ! popupWindowColorErr ? popupTextColorErr : GetSysColor(COLOR_WINDOWTEXT);
+ ErrorPopup.iSeconds = popupTimeSecErr;
+ ErrorPopup.PluginData = (void *)1;
+
+ lstrcpy(ErrorPopup.lptzText, TranslateT("Preview Error Message"));
+
+ lstrcpy(ErrorPopup.lptzContactName, _T("Error Message"));
+
+
+ CallService(MS_POPUP_ADDPOPUPT,(WPARAM)&ErrorPopup,0);
+
+ break;
+
+ case IDC_POPUPTIME:
+ case IDC_POPUPTIMEERR:
+ {
+ BOOL Translated;
+ popupTimeSec = GetDlgItemInt(hwnd,IDC_POPUPTIME,&Translated,FALSE);
+ popupTimeSecErr = GetDlgItemInt(hwnd,IDC_POPUPTIMEERR,&Translated,FALSE);
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ break;
+ }
+ case IDC_POPUPTEXTCOLOR:
+ case IDC_POPUPBACKCOLOR:
+ case IDC_POPUPTEXTCOLORERR:
+ case IDC_POPUPBACKCOLORERR:
+ popupBackColor = SendDlgItemMessage(hwnd,IDC_POPUPBACKCOLOR,CPM_GETCOLOUR,0,0);
+ popupTextColor = SendDlgItemMessage(hwnd,IDC_POPUPTEXTCOLOR,CPM_GETCOLOUR,0,0);
+ popupBackColorErr = SendDlgItemMessage(hwnd,IDC_POPUPBACKCOLORERR,CPM_GETCOLOUR,0,0);
+ popupTextColorErr = SendDlgItemMessage(hwnd,IDC_POPUPTEXTCOLORERR,CPM_GETCOLOUR,0,0);
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ break;
+ case IDC_USEWINCOLORS:
+ popupWindowColor = (IsDlgButtonChecked(hwnd,IDC_USEWINCOLORS)==BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPBACKCOLOR), showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPBACKCOLOR), showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTEXTCOLOR), showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPTEXTCOLOR), showPopup && ! popupWindowColor);
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ break;
+ case IDC_POPUPINCOMING:
+ showPopup = (IsDlgButtonChecked(hwnd,IDC_POPUPINCOMING)==BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd,IDC_USEWINCOLORS),showPopup);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPBACKCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPBACKCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTEXTCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPTEXTCOLOR),showPopup && ! popupWindowColor);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTIME),showPopup);
+ EnableWindow(GetDlgItem(hwnd,IDC_PREVIEW),showPopup);
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ break;
+ case IDC_USEWINCOLORSERR:
+ popupWindowColorErr = (IsDlgButtonChecked(hwnd,IDC_USEWINCOLORSERR)==BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPBACKCOLORERR), showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPBACKCOLORERR), showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTEXTCOLORERR), showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPTEXTCOLORERR), showPopupErr && ! popupWindowColorErr);
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ break;
+ case IDC_POPUPERROR:
+ showPopupErr = (IsDlgButtonChecked(hwnd,IDC_POPUPERROR)==BST_CHECKED);
+ EnableWindow(GetDlgItem(hwnd,IDC_USEWINCOLORSERR),showPopupErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPBACKCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPBACKCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTEXTCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_STATIC_POPUPTEXTCOLORERR),showPopupErr && ! popupWindowColorErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_POPUPTIMEERR),showPopupErr);
+ EnableWindow(GetDlgItem(hwnd,IDC_PREVIEWERR),showPopupErr);
+ SendMessage(GetParent(hwnd),PSM_CHANGED,0,0);
+ break;
+ }
+
+ break;
+
+ case WM_DESTROY:
+ break;
+ }
+
+ return 0;
+}
+
+INT_PTR CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ UNREFERENCED_PARAMETER(wParam);
+
+ switch(msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCITEM tci;
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ iInit = TRUE;
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_DEFAULT), hwnd, OptionsDefaultDlgProc);
+ tci.pszText = TranslateT("Skype default");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 0, &tci);
+ MoveWindow((HWND)tci.lParam,1,28,rcClient.right-5,rcClient.bottom-31,1);
+#ifdef HAVE_UXTHEMES
+ if(MyEnableThemeDialogTexture)
+ MyEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+#endif
+
+ tci.lParam = (LPARAM)CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_ADVANCED),hwnd,OptionsAdvancedDlgProc);
+ tci.pszText = TranslateT("Skype advanced");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 1, &tci);
+ MoveWindow((HWND)tci.lParam,1,28,rcClient.right-5,rcClient.bottom-31,1);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+#ifdef HAVE_UXTHEMES
+ if(MyEnableThemeDialogTexture)
+ MyEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+#endif
+
+ tci.lParam = (LPARAM)CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_PROXY),hwnd,OptionsProxyDlgProc);
+ tci.pszText = TranslateT("Skype proxy");
+ TabCtrl_InsertItem(GetDlgItem(hwnd, IDC_OPTIONSTAB), 2, &tci);
+ MoveWindow((HWND)tci.lParam,1,28,rcClient.right-5,rcClient.bottom-31,1);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+#ifdef HAVE_UXTHEMES
+ if(MyEnableThemeDialogTexture)
+ MyEnableThemeDialogTexture((HWND)tci.lParam, ETDT_ENABLETAB);
+#endif
+
+ iInit = FALSE;
+ return FALSE;
+ }
+
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ TCITEM tci;
+ int i,count;
+ tci.mask = TCIF_PARAM;
+ count = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ for (i=0;i<count;i++)
+ {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ }
+ }
+ break;
+ }
+ break;
+ case IDC_OPTIONSTAB:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_SHOW);
+ }
+ break;
+ }
+ break;
+
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK OptionsProxyDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ const int Skype2SocketControls[]={ IDC_STATIC_HOST, IDC_HOST, IDC_STATIC_PORT, IDC_PORT, IDC_REQPASS, IDC_PASSWORD, IDC_STATIC_RESTART };
+ static BOOL initDlg=FALSE;
+ DBVARIANT dbv;
+ int i;
+
+ switch (uMsg){
+ case WM_INITDIALOG:
+ initDlg=TRUE;
+ TranslateDialogDefault(hwndDlg);
+ if (!db_get_s(NULL, SKYPE_PROTONAME, "Host", &dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_HOST, dbv.pszVal);
+ db_free(&dbv);
+ } else SetDlgItemText(hwndDlg, IDC_HOST, _T("localhost"));
+ SendDlgItemMessage(hwndDlg, IDC_PORT, EM_SETLIMITTEXT, 5, 0L);
+ SetDlgItemInt(hwndDlg, IDC_PORT, db_get_w(NULL, SKYPE_PROTONAME, "Port", 1401), FALSE);
+ CheckDlgButton(hwndDlg, IDC_REQPASS, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "RequiresPassword", 0));
+ CheckDlgButton(hwndDlg, IDC_USES2S, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UseSkype2Socket", 0));
+ if (!db_get_s(NULL, SKYPE_PROTONAME, "Password", &dbv)) {
+ CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal)+1, (LPARAM)dbv.pszVal);
+ SetDlgItemTextA(hwndDlg, IDC_PASSWORD, dbv.pszVal);
+ db_free(&dbv);
+ }
+ SendMessage(hwndDlg, WM_COMMAND, IDC_USES2S, 0);
+ SendMessage(hwndDlg, WM_COMMAND, IDC_REQPASS, 0);
+ initDlg=FALSE;
+ return TRUE;
+ case WM_NOTIFY: {
+ NMHDR* nmhdr = (NMHDR*)lParam;
+
+ switch (nmhdr->code){
+ case PSN_APPLY:
+ case PSN_KILLACTIVE:
+ {
+ char buf[1024];
+ GetDlgItemTextA(hwndDlg, IDC_HOST, buf, sizeof(buf));
+ db_set_s(NULL, SKYPE_PROTONAME, "Host", buf);
+ db_set_w(NULL, SKYPE_PROTONAME, "Port", (unsigned short)GetDlgItemInt(hwndDlg, IDC_PORT, NULL, FALSE));
+ db_set_b(NULL, SKYPE_PROTONAME, "RequiresPassword", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_REQPASS), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "UseSkype2Socket", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_USES2S), BM_GETCHECK,0,0)));
+ ZeroMemory(buf, sizeof(buf));
+ GetDlgItemTextA(hwndDlg, IDC_PASSWORD, buf, sizeof(buf));
+ CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(buf), (LPARAM)buf);
+ db_set_s(NULL, SKYPE_PROTONAME, "Password", buf);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case WM_COMMAND: {
+ switch (LOWORD(wParam)) {
+ case IDC_USES2S:
+ for (i=0; i<sizeof(Skype2SocketControls)/sizeof(Skype2SocketControls[0]); i++) EnableWindow(GetDlgItem(hwndDlg, Skype2SocketControls[i]), SendMessage(GetDlgItem(hwndDlg, LOWORD(wParam)), BM_GETCHECK,0,0));
+ if (SendMessage(GetDlgItem(hwndDlg, LOWORD(wParam)), BM_GETCHECK,0,0)) SendMessage(hwndDlg, WM_COMMAND, IDC_REQPASS, 0);
+ break;
+ case IDC_REQPASS:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), SendMessage(GetDlgItem(hwndDlg, LOWORD(wParam)), BM_GETCHECK,0,0));
+ break;
+
+ }
+ if (!initDlg) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ return 0;
+}
+
+INT_PTR CALLBACK OptionsAdvancedDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ static BOOL initDlg=FALSE;
+ static int statusModes[]={ID_STATUS_OFFLINE,ID_STATUS_ONLINE,ID_STATUS_AWAY,ID_STATUS_NA,ID_STATUS_OCCUPIED,ID_STATUS_DND,ID_STATUS_FREECHAT,ID_STATUS_INVISIBLE,ID_STATUS_OUTTOLUNCH,ID_STATUS_ONTHEPHONE};
+ int i, j;
+
+ switch (uMsg){
+ case WM_INITDIALOG:
+ initDlg=TRUE;
+
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_ENABLEMENU, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "EnableMenu", 1));
+ CheckDlgButton(hwndDlg, IDC_NOERRORS, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "SuppressErrors", 0));
+ CheckDlgButton(hwndDlg, IDC_KEEPSTATE, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "KeepState", 0));
+ CheckDlgButton(hwndDlg, IDC_TIMEZONE, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UseTimeZonePatch", 0));
+ CheckDlgButton(hwndDlg, IDC_IGNTZ, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "IgnoreTimeZones", 0));
+ CheckDlgButton(hwndDlg, IDC_SHOWDEFAULTAVATAR, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "ShowDefaultSkypeAvatar", 0));
+ CheckDlgButton(hwndDlg, IDC_SUPPRESSCALLSUMMARYMESSAGE, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "SuppressCallSummaryMessage", 1));
+ CheckDlgButton(hwndDlg, IDC_NOSKYPE3STATS, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "NoSkype3Stats", 0));
+ CheckDlgButton(hwndDlg, IDC_SHOWFULLNAME, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "ShowFullname", 1));
+
+ if (ServiceExists(MS_GC_NEWSESSION) && (!bProtocolSet || protocol>=5)) {
+ CheckDlgButton(hwndDlg, IDC_GROUPCHAT, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UseGroupchat", 0));
+ CheckDlgButton(hwndDlg, IDC_GROUPCHATREAD, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "MarkGroupchatRead", 0));
+ } else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GROUPCHAT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GROUPCHATREAD), FALSE);
+ }
+
+#ifdef USEPOPUP
+ if (ServiceExists(MS_POPUP_ADDPOPUP))
+ CheckDlgButton(hwndDlg, IDC_USEPOPUP, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UsePopup", 0));
+ else
+#endif
+ EnableWindow(GetDlgItem(hwndDlg, IDC_USEPOPUP), FALSE);
+
+ j=db_get_dw(NULL, SKYPE_PROTONAME, "SkypeOutStatusMode", ID_STATUS_ONTHEPHONE);
+ for(i=0;i<sizeof(statusModes)/sizeof(statusModes[0]);i++) {
+ int k;
+
+ k=SendDlgItemMessage(hwndDlg,IDC_SKYPEOUTSTAT,CB_ADDSTRING,0,(LPARAM)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,statusModes[i],/*GCMDF_TCHAR*/0));
+ SendDlgItemMessage(hwndDlg,IDC_SKYPEOUTSTAT,CB_SETITEMDATA,k,statusModes[i]);
+ if (statusModes[i]==j) SendDlgItemMessage(hwndDlg,IDC_SKYPEOUTSTAT,CB_SETCURSEL,i,0);
+ }
+ initDlg=FALSE;
+ return TRUE;
+
+ case WM_NOTIFY: {
+ NMHDR* nmhdr = (NMHDR*)lParam;
+
+ switch (nmhdr->code){
+ case PSN_APPLY:
+ case PSN_KILLACTIVE:
+ db_set_b (NULL, SKYPE_PROTONAME, "EnableMenu", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_ENABLEMENU), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "UsePopup", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_USEPOPUP), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "UseGroupchat", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_GROUPCHAT), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "MarkGroupchatRead", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_GROUPCHATREAD), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "SuppressErrors", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_NOERRORS), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "KeepState", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_KEEPSTATE), BM_GETCHECK,0,0)));
+ db_set_dw(NULL, SKYPE_PROTONAME, "SkypeOutStatusMode", SendDlgItemMessage(hwndDlg,IDC_SKYPEOUTSTAT,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_SKYPEOUTSTAT,CB_GETCURSEL,0,0),0));
+ db_set_b (NULL, SKYPE_PROTONAME, "UseTimeZonePatch", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_TIMEZONE), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "IgnoreTimeZones", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_IGNTZ), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "ShowDefaultSkypeAvatar", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_SHOWDEFAULTAVATAR), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "SuppressCallSummaryMessage", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_SUPPRESSCALLSUMMARYMESSAGE), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "NoSkype3Stats", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_NOSKYPE3STATS), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "ShowFullname", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_SHOWFULLNAME), BM_GETCHECK,0,0)));
+ return TRUE;
+ }
+ break;
+ }
+ case WM_COMMAND: {
+ switch (LOWORD(wParam)) {
+ case IDC_CLEANUP:
+ pthread_create(( pThreadFunc )CleanupNicknames, NULL);
+ break;
+ }
+ if (!initDlg) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ return 0;
+}
+
+static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch (uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ // Set initial directory.
+#ifdef UNICODE
+ wchar_t* wszInitFolder = make_unicode_string((const unsigned char*)lpData);
+ SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)wszInitFolder);
+ free(wszInitFolder);
+#else
+ SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData);
+#endif
+ break;
+ }
+ }
+ return 0;
+}
+
+INT_PTR CALLBACK OptionsDefaultDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ static BOOL initDlg=FALSE;
+ static int skypeLaunchControls[]={IDC_NOSPLASH,IDC_MINIMIZED,IDC_NOTRAY,IDC_REMOVEABLE,IDC_SECONDARY,IDC_DATAPATHO,IDC_CUSTOMCOMMAND,IDC_STATIC_PATHINFO};
+
+ switch (uMsg){
+ case WM_INITDIALOG:
+ {
+ DBVARIANT dbv;
+ BOOL startSkype;
+ int i;
+
+ initDlg=TRUE;
+ TranslateDialogDefault(hwndDlg);
+
+ startSkype=db_get_b(NULL, SKYPE_PROTONAME, "StartSkype", 1);
+
+ CheckDlgButton(hwndDlg, IDC_STARTSKYPE, (BYTE)startSkype);
+ CheckDlgButton(hwndDlg, IDC_NOSPLASH, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "nosplash", 1));
+ CheckDlgButton(hwndDlg, IDC_MINIMIZED, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "minimized", 1));
+ CheckDlgButton(hwndDlg, IDC_NOTRAY, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "notray", 0));
+ CheckDlgButton(hwndDlg, IDC_REMOVEABLE, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "removable", 0));
+ CheckDlgButton(hwndDlg, IDC_SECONDARY, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "secondary", 0));
+ CheckDlgButton(hwndDlg, IDC_DATAPATHO, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "datapath:", 0));
+ CheckDlgButton(hwndDlg, IDC_SHUTDOWN, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "Shutdown", 0));
+ CheckDlgButton(hwndDlg, IDC_UNLOADOFFLINE, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UnloadOnOffline", 0));
+
+ CheckDlgButton(hwndDlg, IDC_CUSTOMCOMMAND, (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "UseCustomCommand", 0));
+ SendDlgItemMessage(hwndDlg, IDC_COMMANDLINE, EM_SETLIMITTEXT, MAX_PATH-1, 0L);
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"CommandLine",&dbv))
+ {
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_COMMANDLINE), dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_DATAPATH, EM_SETLIMITTEXT, MAX_PATH-1, 0L);
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"datapath",&dbv))
+ {
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_DATAPATH), dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ for(i=0; i < sizeof(skypeLaunchControls)/sizeof(skypeLaunchControls[0]); i++)
+ EnableWindow(GetDlgItem(hwndDlg, skypeLaunchControls[i]), startSkype);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSECMDL), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COMMANDLINE), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSEDP), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DATAPATH), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0));
+
+ // LoginUserName
+ if(!db_get_ts(NULL,SKYPE_PROTONAME,"LoginUserName",&dbv))
+ {
+ SetWindowText(GetDlgItem(hwndDlg, IDC_USERNAME), dbv.ptszVal);
+ db_free(&dbv);
+ }
+
+ // LoginPassword
+ if(!db_get_ts(NULL,SKYPE_PROTONAME,"LoginPassword",&dbv))
+ {
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PASSWORD), dbv.ptszVal);
+ db_free(&dbv);
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_CONNATTEMPTS, EM_SETLIMITTEXT, 3, 0L);
+ SetDlgItemInt (hwndDlg, IDC_CONNATTEMPTS, db_get_w(NULL, SKYPE_PROTONAME, "ConnectionAttempts", 10), FALSE);
+ SendMessage(hwndDlg, WM_COMMAND, IDC_STARTSKYPE, 0);
+ initDlg=FALSE;
+ return TRUE;
+ }
+ case WM_NOTIFY: {
+ NMHDR* nmhdr = (NMHDR*)lParam;
+
+ switch (nmhdr->code){
+ case PSN_APPLY:
+ case PSN_KILLACTIVE:
+ {
+ char text[500];
+ TCHAR wtext[500];
+ char szRelativePath[MAX_PATH];
+
+ db_set_b (NULL, SKYPE_PROTONAME, "StartSkype", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_STARTSKYPE), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "nosplash", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_NOSPLASH), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "minimized", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_MINIMIZED), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "notray", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_NOTRAY), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "Shutdown", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_SHUTDOWN), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "UnloadOnOffline", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_UNLOADOFFLINE), BM_GETCHECK,0,0)));
+ db_set_w (NULL, SKYPE_PROTONAME, "ConnectionAttempts", (unsigned short)GetDlgItemInt(hwndDlg, IDC_CONNATTEMPTS, NULL, FALSE));
+ db_set_b (NULL, SKYPE_PROTONAME, "UseCustomCommand", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "datapath:", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "removable", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_REMOVEABLE), BM_GETCHECK,0,0)));
+ db_set_b (NULL, SKYPE_PROTONAME, "secondary", (BYTE)(SendMessage(GetDlgItem(hwndDlg, IDC_SECONDARY), BM_GETCHECK,0,0)));
+
+ GetDlgItemTextA(hwndDlg,IDC_COMMANDLINE,text,sizeof(text));
+ strncpy(szRelativePath, text, sizeof(szRelativePath)-1);
+ CallService (MS_UTILS_PATHTORELATIVE, (WPARAM)text, (LPARAM)szRelativePath);
+ db_set_s(NULL, SKYPE_PROTONAME, "CommandLine", szRelativePath);
+
+ GetDlgItemTextA(hwndDlg,IDC_DATAPATH,text,sizeof(text));
+ strncpy(szRelativePath, text, sizeof(szRelativePath)-1);
+ CallService (MS_UTILS_PATHTORELATIVE, (WPARAM)text, (LPARAM)szRelativePath);
+ db_set_s(NULL, SKYPE_PROTONAME, "datapath", szRelativePath);
+
+ // LoginUserName
+ GetDlgItemText(hwndDlg,IDC_USERNAME,wtext,sizeof(wtext)/sizeof(TCHAR));
+ db_set_ts(NULL, SKYPE_PROTONAME, "LoginUserName", wtext);
+
+ // LoginPassword
+ GetDlgItemText(hwndDlg,IDC_PASSWORD,wtext,sizeof(wtext)/sizeof(TCHAR));
+ db_set_ts(NULL, SKYPE_PROTONAME, "LoginPassword", wtext);
+
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case WM_COMMAND: {
+ switch (LOWORD(wParam)) {
+ BOOL startSkype;
+ int i;
+ case IDC_STARTSKYPE:
+ startSkype=SendMessage(GetDlgItem(hwndDlg, IDC_STARTSKYPE), BM_GETCHECK,0,0);
+
+ for(i=0; i < sizeof(skypeLaunchControls)/sizeof(skypeLaunchControls[0]); i++)
+ EnableWindow(GetDlgItem(hwndDlg, skypeLaunchControls[i]), startSkype);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSECMDL), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COMMANDLINE), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSEDP), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DATAPATH), startSkype && SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0));
+ break;
+ case IDC_CLEANUP:
+ pthread_create(( pThreadFunc )CleanupNicknames, NULL);
+ break;
+ case IDC_DATAPATHO:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DATAPATH), SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSEDP), SendMessage(GetDlgItem(hwndDlg, IDC_DATAPATHO), BM_GETCHECK,0,0));
+ break;
+ case IDC_CUSTOMCOMMAND:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_COMMANDLINE), SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSECMDL), SendMessage(GetDlgItem(hwndDlg, IDC_CUSTOMCOMMAND), BM_GETCHECK,0,0));
+ break;
+ case IDC_BROWSECMDL:
+ {
+ OPENFILENAMEA ofn={0};
+ BOOL gofnResult;
+ char szFileName[MAX_PATH];
+ char szAbsolutePath[MAX_PATH];
+
+ ofn.lStructSize=sizeof(ofn);
+ ofn.hwndOwner=hwndDlg;
+ ofn.lpstrFilter="Executable files (*.exe)\0*.exe\0All files (*.*)\0*.*\0";
+ ofn.nMaxFile=sizeof(szFileName);
+ ofn.lpstrDefExt="exe";
+ ofn.lpstrFile=szFileName;
+ ofn.Flags=OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLESIZING;
+
+ GetDlgItemTextA(hwndDlg,IDC_COMMANDLINE,szFileName,sizeof(szFileName));
+ TranslateMirandaRelativePathToAbsolute(szFileName, szAbsolutePath, FALSE);
+ strcpy (szFileName, szAbsolutePath);
+
+ if (!(gofnResult = GetOpenFileNameA(&ofn)) && CommDlgExtendedError() == FNERR_INVALIDFILENAME){
+ strcpy(szFileName, ".\\Skype.exe");
+ TranslateMirandaRelativePathToAbsolute(szFileName, szAbsolutePath, FALSE);
+ strcpy (szFileName, szAbsolutePath);
+ gofnResult = GetOpenFileNameA(&ofn);
+ }
+
+ if(gofnResult)
+ SetWindowTextA(GetDlgItem(hwndDlg, IDC_COMMANDLINE), szFileName);
+
+ break;
+ }
+ case IDC_BROWSEDP:
+ {
+ BROWSEINFOA bi={0};
+ LPITEMIDLIST pidl;
+ char szFileName[MAX_PATH];
+ char szAbsolutePath[MAX_PATH];
+
+ GetDlgItemTextA (hwndDlg, IDC_DATAPATH, szFileName, MAX_PATH);
+
+ TranslateMirandaRelativePathToAbsolute(szFileName, szAbsolutePath, FALSE);
+ bi.hwndOwner = hwndDlg;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_SHAREABLE | BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON;
+ bi.lpfn = BrowseCallbackProc;
+ bi.lParam = (LPARAM)szAbsolutePath;
+
+ if ( (pidl = SHBrowseForFolderA (&bi)) ) {
+ if (SHGetPathFromIDListA (pidl, szFileName))
+ SetDlgItemTextA (hwndDlg, IDC_DATAPATH, szFileName);
+ CoTaskMemFree (pidl);
+ }
+ break;
+ }
+
+#ifdef SKYPE_AUTO_DETECTION
+ case IDC_AUTODETECTION:
+ DoAutoDetect(hwndDlg);
+ break;
+#endif
+ }
+ if (!initDlg) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnDetailsInit - initializes user info dialog pages.
+
+int OnDetailsInit( WPARAM wParam, LPARAM lParam )
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ HANDLE hContact = ( HANDLE )lParam;
+
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hInst;
+
+ if ( hContact == NULL ) {
+
+ char szTitle[256];
+
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 7, 0, 27) && !bIsImoproxy)
+ {
+ mir_snprintf( szTitle, sizeof( szTitle ), "%s %s", SKYPE_PROTONAME, Translate( "Avatar" ));
+
+ odp.pfnDlgProc = AvatarDlgProc;
+ odp.position = 1900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SETAVATAR);
+ odp.pszTitle = szTitle;
+ UserInfo_AddPage(wParam, &odp);
+ }
+
+ mir_snprintf( szTitle, sizeof( szTitle ), "%s %s", SKYPE_PROTONAME, Translate( "Details" ));
+
+ odp.pfnDlgProc = DetailsDlgProc;
+ odp.position = 1900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SETDETAILS);
+ odp.pszTitle = szTitle;
+ UserInfo_AddPage(wParam, &odp);
+ }
+
+ return 0;
+}
+
+/*AvatarDlgProc
+*
+* For setting the skype avatar
+*
+*/
+INT_PTR CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static RECT r;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+
+ hAvatar = NULL;
+ if(ServiceExists(MS_AV_GETMYAVATAR)){
+ struct avatarCacheEntry *ace = (struct avatarCacheEntry *)CallService(MS_AV_GETMYAVATAR, 0,(LPARAM) SKYPE_PROTONAME);
+ if (ace!=NULL) {
+ hAvatar = ( HBITMAP )CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )ace->szFilename);
+ if ( hAvatar != NULL )
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ }
+ }
+
+
+
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_SETAVATAR:
+ {
+ char szFileName[ MAX_PATH ];
+ if ( EnterBitmapFileName( szFileName ) != ERROR_SUCCESS )
+ return FALSE;
+
+ hAvatar = ( HBITMAP )CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szFileName);
+ if ( hAvatar != NULL ){
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ CallService(SKYPE_SETAVATAR, 0, ( LPARAM )szFileName);
+ }
+ break;
+ }
+ case IDC_DELETEAVATAR:
+ if ( hAvatar != NULL ) {
+ DeleteObject( hAvatar );
+ hAvatar = NULL;
+ CallService(SKYPE_SETAVATAR, 0, 0);
+ }
+ db_unset( NULL, SKYPE_PROTONAME, "AvatarFile" );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ break;
+ } }
+ break;
+
+ case WM_DESTROY:
+ if ( hAvatar != NULL )
+ DeleteObject( hAvatar );
+ break;
+ }
+
+ return 0;
+}
+
+/*DetailsDlgProc
+*
+* For setting the skype infos
+*
+*/
+INT_PTR CALLBACK DetailsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int sexM = 0,sexF = 0, sex;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+
+ ZeroMemory (&myProfile, sizeof(myProfile));
+ SkypeProfile_Load(&myProfile);
+ if(SkypeInitialized)
+ SkypeProfile_LoadFromSkype(&myProfile);
+
+ SendDlgItemMessage(hwndDlg,IDC_SEX,CB_ADDSTRING,0,(LPARAM)_T(""));
+ sexM = SendDlgItemMessage(hwndDlg,IDC_SEX,CB_ADDSTRING,0,(LPARAM)TranslateT("MALE"));
+ sexF = SendDlgItemMessage(hwndDlg,IDC_SEX,CB_ADDSTRING,0,(LPARAM)TranslateT("FEMALE"));
+
+ switch(myProfile.Sex) {
+ case 0x4D: SendDlgItemMessage(hwndDlg,IDC_SEX,CB_SETCURSEL, sexM, 0); break;
+ case 0x46: SendDlgItemMessage(hwndDlg,IDC_SEX,CB_SETCURSEL, sexF, 0); break;
+ }
+
+ SetDlgItemText(hwndDlg, IDC_FULLNAME, myProfile.FullName);
+ SetDlgItemTextA(hwndDlg, IDC_HOMEPAGE, myProfile.HomePage);
+ SetDlgItemTextA(hwndDlg, IDC_HOMEPHONE, myProfile.HomePhone);
+ SetDlgItemTextA(hwndDlg, IDC_OFFICEPHONE, myProfile.OfficePhone);
+ SetDlgItemText(hwndDlg, IDC_CITY, myProfile.City);
+ SetDlgItemText(hwndDlg, IDC_PROVINCE, myProfile.Province);
+ DateTime_SetSystemtime (GetDlgItem (hwndDlg, IDC_BIRTHDAY), GDT_VALID, &myProfile.Birthday);
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_SAVEDETAILS:
+ GetDlgItemText(hwndDlg,IDC_FULLNAME,myProfile.FullName,sizeof(myProfile.FullName)/sizeof(TCHAR));
+ GetDlgItemTextA(hwndDlg,IDC_HOMEPAGE,myProfile.HomePage,sizeof(myProfile.HomePage)/sizeof(TCHAR));
+ GetDlgItemTextA(hwndDlg,IDC_HOMEPHONE,myProfile.HomePhone,sizeof(myProfile.HomePhone)/sizeof(TCHAR));
+ GetDlgItemTextA(hwndDlg,IDC_OFFICEPHONE,myProfile.OfficePhone,sizeof(myProfile.OfficePhone)/sizeof(TCHAR));
+ GetDlgItemText(hwndDlg,IDC_CITY,myProfile.City,sizeof(myProfile.City)/sizeof(TCHAR));
+ GetDlgItemText(hwndDlg,IDC_PROVINCE,myProfile.Province,sizeof(myProfile.Province)/sizeof(TCHAR));
+ sex = SendMessage(GetDlgItem(hwndDlg,IDC_SEX),CB_GETCURSEL,0,0);
+
+ myProfile.Sex = 0;
+ if(sex == sexF) myProfile.Sex = 0x46; else
+ if(sex == sexM) myProfile.Sex = 0x4D;
+ DateTime_GetSystemtime (GetDlgItem (hwndDlg, IDC_BIRTHDAY), &myProfile.Birthday);
+
+ SkypeProfile_Save(&myProfile);
+ if(SkypeInitialized)
+ SkypeProfile_SaveToSkype(&myProfile);
+ break;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ if ( hAvatar != NULL )
+ DeleteObject( hAvatar );
+ break;
+ }
+
+ return 0;
+}
+
+#ifdef SKYPE_AUTO_DETECTION
+/**
+ * DoAutoDetect
+ * @param dlg The default option dialog handle
+ */
+void DoAutoDetect(HWND dlg)
+{
+ char basePath[MAX_PATH];
+ char fileName[MAX_PATH];
+ char tmpUser[255];
+ ezxml_t f1, acc;
+
+ if (FAILED(SHGetFolderPath(dlg,CSIDL_APPDATA,NULL,0,basePath)))
+ {
+ OUTPUT("Error in retrieving appdata path!");
+ return;
+ }
+
+ strcat(basePath,"\\Skype\\");
+ sprintf (fileName, "%s\\shared.xml", basePath);
+
+ if (f1 = ezxml_parse_file(fileName))
+ {
+ if (acc = ezxml_get(f1, "Lib", 0, "Account", 0, "Default", -1))
+ {
+ if (GetWindowTextA(GetDlgItem(dlg,IDC_USERNAME),tmpUser,sizeof(tmpUser)))
+ SetWindowTextA(GetDlgItem(dlg,IDC_USERNAME),acc->txt);
+ /* Can't find this stuff in current Skype verions??
+ sprintf (fileName, "%s\\%s\\config.xml", basePath, acc->txt);
+ if ((acc = ezxml_get(f1, "UI", 0, "Messages", 0, "OpenWindowInCompactMode", -1)) && *acc->txt!='0')
+ {
+ ezxml_set_txt (acc, "0");
+ // ezXML doesn't supprot saving yet
+ }
+ */
+ }
+ ezxml_free(f1);
+ }
+ else
+ {
+ OUTPUT("Failed to open skypes configuration files!");
+ return;
+ }
+}
+#endif
diff --git a/protocols/SkypeClassic/skypeopt.h b/protocols/SkypeClassic/skypeopt.h
new file mode 100644
index 0000000000..23aa7a5212
--- /dev/null
+++ b/protocols/SkypeClassic/skypeopt.h
@@ -0,0 +1,49 @@
+/*
+ * RegisterOptions
+ *
+ * This function tells Miranda to add the configuration section of this plugin in
+ * the Options-dialog.
+ */
+int RegisterOptions(WPARAM wParam, LPARAM lParam);
+/*
+ * OptionsDlgProc
+ *
+ * This callback function is called, when the options dialog in Miranda is shown
+ * The function contains all necessary stuff to process the options in the dialog
+ * and store them in the database, when changed, and fill out the settings-dialog
+ * correctly according to the current settings
+ */
+INT_PTR CALLBACK OptionsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+INT_PTR CALLBACK OptionsDefaultDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK OptionsAdvancedDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK OptionsProxyDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK OptPopupDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+/*
+* Procedure to call when the option page is asked
+*
+*/
+int OnDetailsInit( WPARAM wParam, LPARAM lParam );
+
+/*
+* Dialog to change avatar in user details.
+*
+*
+*/
+INT_PTR CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/*
+* Dialog to change infos in user details.
+*
+*
+*/
+INT_PTR CALLBACK DetailsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/*
+ * Helper functions
+ *
+ */
+void DoAutoDetect(HWND dlg);
+
+; \ No newline at end of file
diff --git a/protocols/SkypeClassic/skypeprofile.cpp b/protocols/SkypeClassic/skypeprofile.cpp
new file mode 100644
index 0000000000..168dbfa97c
--- /dev/null
+++ b/protocols/SkypeClassic/skypeprofile.cpp
@@ -0,0 +1,145 @@
+#pragma warning (disable: 4706) // assignment within conditional expression
+
+#include "skypeprofile.h"
+#include "skypeapi.h"
+#include "utf8.h"
+
+extern char g_szProtoName[];
+
+void SkypeProfile_Save(SkypeProfile *pstProf)
+{
+ db_set_b(NULL, SKYPE_PROTONAME, "Gender", pstProf->Sex);
+ db_set_s(NULL, SKYPE_PROTONAME, "HomePhone", pstProf->HomePhone);
+ db_set_s(NULL, SKYPE_PROTONAME, "OfficePhone", pstProf->OfficePhone);
+ db_set_s(NULL, SKYPE_PROTONAME, "HomePage", pstProf->HomePage);
+ db_set_ts(NULL, SKYPE_PROTONAME, "Nick", pstProf->FullName);
+ db_set_ts(NULL, SKYPE_PROTONAME, "City", pstProf->City);
+ db_set_ts(NULL, SKYPE_PROTONAME, "Province", pstProf->Province);
+ db_set_w(NULL, SKYPE_PROTONAME, "BirthYear", (WORD)pstProf->Birthday.wYear);
+ db_set_b(NULL, SKYPE_PROTONAME, "BirthMonth", (BYTE)pstProf->Birthday.wMonth);
+ db_set_b(NULL, SKYPE_PROTONAME, "BirthDay", (BYTE)pstProf->Birthday.wDay);
+}
+
+void SkypeProfile_Load(SkypeProfile *pstProf)
+{
+ DBVARIANT dbv;
+
+ pstProf->Sex = (BYTE)db_get_b(NULL, SKYPE_PROTONAME, "Gender", 0);
+ pstProf->Birthday.wYear = (WORD)db_get_w(NULL, SKYPE_PROTONAME, "BirthYear", 1900);
+ pstProf->Birthday.wMonth = (WORD)db_get_b(NULL, SKYPE_PROTONAME, "BirthMonth", 01);
+ pstProf->Birthday.wDay = (WORD)db_get_b(NULL, SKYPE_PROTONAME, "BirthDay", 01);
+ if(!db_get_ts(NULL,SKYPE_PROTONAME,"Nick",&dbv))
+ {
+ _tcsncpy (pstProf->FullName, dbv.ptszVal, sizeof(pstProf->FullName)/sizeof(TCHAR));
+ db_free(&dbv);
+ }
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"HomePage",&dbv))
+ {
+ strncpy (pstProf->HomePage, dbv.pszVal, sizeof(pstProf->HomePage));
+ db_free(&dbv);
+ }
+ if(!db_get_ts(NULL,SKYPE_PROTONAME,"Province",&dbv))
+ {
+ _tcsncpy (pstProf->Province, dbv.ptszVal, sizeof(pstProf->Province)/sizeof(TCHAR));
+ db_free(&dbv);
+ }
+ if(!db_get_ts(NULL,SKYPE_PROTONAME,"City",&dbv))
+ {
+ _tcsncpy (pstProf->City, dbv.ptszVal, sizeof(pstProf->City)/sizeof(TCHAR));
+ db_free(&dbv);
+ }
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"OfficePhone",&dbv))
+ {
+ strncpy (pstProf->OfficePhone, dbv.pszVal, sizeof(pstProf->OfficePhone));
+ db_free(&dbv);
+ }
+ if(!db_get_s(NULL,SKYPE_PROTONAME,"HomePhone",&dbv))
+ {
+ strncpy (pstProf->HomePhone, dbv.pszVal, sizeof(pstProf->HomePhone));
+ db_free(&dbv);
+ }
+}
+
+static void LoadSaveSkype(SkypeProfile *pstProf, BOOL bSet)
+{
+#pragma warning (push)
+#pragma warning (disable: 4204) // nonstandard extension used : non-constant aggregate initializer
+#define ENTRY(x,y) {x, pstProf->y, sizeof(pstProf->y)/sizeof(pstProf->y[0]), sizeof(pstProf->y[0])}
+ const struct {
+ char *pszSetting;
+ LPVOID lpDest;
+ int iSize;
+ char cType;
+ } astSettings[] = {
+ ENTRY("FULLNAME", FullName),
+ ENTRY("PHONE_HOME", HomePhone),
+ ENTRY("PHONE_OFFICE", OfficePhone),
+ ENTRY("HOMEPAGE", HomePage),
+ ENTRY("CITY", City),
+ ENTRY("PROVINCE", Province)
+ };
+#pragma warning (pop)
+#undef ENTRY
+ char *ptr;
+ int i;
+
+ if (bSet) {
+ char *pBuf, szBirthday[16];
+ for (i=0; i<sizeof(astSettings)/sizeof(astSettings[0]); i++) {
+ if ((astSettings[i].cType == sizeof(char) && utf8_encode((const char*)astSettings[i].lpDest, &pBuf) != -1) ||
+ (astSettings[i].cType == sizeof(WCHAR) && (pBuf = (char*)make_utf8_string((const WCHAR*)astSettings[i].lpDest)))) {
+ SkypeSetProfile (astSettings[i].pszSetting, pBuf);
+ free (pBuf);
+ }
+ }
+ switch (pstProf->Sex)
+ {
+ case 0x4D: SkypeSetProfile ("SEX", "MALE"); break;
+ case 0x46: SkypeSetProfile ("SEX", "FEMALE"); break;
+ }
+ sprintf (szBirthday, "%04d%02d%02d", pstProf->Birthday.wYear, pstProf->Birthday.wMonth, pstProf->Birthday.wDay);
+ SkypeSetProfile ("BIRTHDAY", szBirthday);
+ } else {
+ for (i=0; i<sizeof(astSettings)/sizeof(astSettings[0]); i++) {
+ if (ptr=SkypeGetProfile(astSettings[i].pszSetting)) {
+ if (astSettings[i].cType == sizeof(char)) {
+ char *pBuf;
+ if (utf8_decode (ptr, &pBuf) != -1) {
+ strncpy ((char*)astSettings[i].lpDest, pBuf, astSettings[i].iSize);
+ free (pBuf);
+ }
+ } else {
+ WCHAR *pBuf;
+ if (pBuf = make_unicode_string((const unsigned char*)ptr)) {
+ wcsncpy ((WCHAR*)astSettings[i].lpDest, pBuf, astSettings[i].iSize);
+ free (pBuf);
+ }
+ }
+ free (ptr);
+ }
+ }
+ if (ptr=SkypeGetProfile("SEX"))
+ {
+ if (!_stricmp(ptr, "MALE")) pstProf->Sex=0x4D; else
+ if (!_stricmp(ptr, "FEMALE")) pstProf->Sex=0x46;
+ free (ptr);
+ }
+ if (ptr=SkypeGetProfile("BIRTHDAY"))
+ {
+ if (*ptr != '0')
+ sscanf(ptr, "%04hd%02hd%02hd", &pstProf->Birthday.wYear, &pstProf->Birthday.wMonth,
+ &pstProf->Birthday.wDay);
+ free(ptr);
+ }
+ }
+}
+
+void SkypeProfile_LoadFromSkype(SkypeProfile *pstProf)
+{
+ LoadSaveSkype (pstProf, FALSE);
+}
+
+void SkypeProfile_SaveToSkype(SkypeProfile *pstProf)
+{
+ LoadSaveSkype (pstProf, TRUE);
+} \ No newline at end of file
diff --git a/protocols/SkypeClassic/skypeprofile.h b/protocols/SkypeClassic/skypeprofile.h
new file mode 100644
index 0000000000..5902f865c3
--- /dev/null
+++ b/protocols/SkypeClassic/skypeprofile.h
@@ -0,0 +1,33 @@
+// System includes
+#include <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <process.h>
+#include <time.h>
+#include "resource.h"
+#include "skype.h"
+
+#pragma warning (push)
+#pragma warning (disable: 4100) // unreferenced formal parameter
+// Miranda database access
+#include <newpluginapi.h>
+#include <m_database.h>
+#pragma warning (pop)
+
+typedef struct
+{
+ TCHAR FullName[256];
+ char HomePhone[256];
+ char OfficePhone[256];
+ char HomePage[256];
+ TCHAR City[256];
+ TCHAR Province[256];
+ BYTE Sex;
+ SYSTEMTIME Birthday;
+} SkypeProfile;
+
+void SkypeProfile_Load(SkypeProfile *pstProf);
+void SkypeProfile_Save(SkypeProfile *pstProf);
+void SkypeProfile_Free(SkypeProfile *pstProf);
+void SkypeProfile_LoadFromSkype(SkypeProfile *pstProf);
+void SkypeProfile_SaveToSkype(SkypeProfile *pstProf);
diff --git a/protocols/SkypeClassic/skypeproxy.h b/protocols/SkypeClassic/skypeproxy.h
new file mode 100644
index 0000000000..8e1490803e
--- /dev/null
+++ b/protocols/SkypeClassic/skypeproxy.h
@@ -0,0 +1,7 @@
+/* Commands for command mode of Skype proxy */
+
+#define AUTHENTICATE 0x01
+#define CAPABILITIES 0x02
+
+/* Capabilities flags of Skypeproxy */
+#define USE_AUTHENTICATION 0x01 \ No newline at end of file
diff --git a/protocols/SkypeClassic/skypeproxy/skypeproxy.c b/protocols/SkypeClassic/skypeproxy/skypeproxy.c
new file mode 100644
index 0000000000..fff9c1b916
--- /dev/null
+++ b/protocols/SkypeClassic/skypeproxy/skypeproxy.c
@@ -0,0 +1,651 @@
+/*
+
+Purpose
+=======
+This program opens a connection on a local TCP/IP port and sends/
+receives Skype-API calls on it so that you can remote-control
+Skype over a network.
+Note, that there are currently NO SECURITY mechanisms, so don't
+use this over an untrusted network!
+
+Author
+======
+This program was written by leecher in 2005 (mailto:leecher@dose.0wnz.at)
+Please give feedback at http://forum.skype.com/viewtopic.php?t=16187
+
+Protocol
+========
+Basic protocol structure
+------------------------
+Sender and receiver have the same protocol:
+
+ [(UINT)Length of message][(char[])Message]
+
+The Length is so that you can malloc() enough space for the data buffer
+to receive the next message.
+
+A special case is, if the [Length of message] is 0. In this case the
+client tells the server that he wants to switch to command mode.
+
+Command mode
+------------
+The server expects
+
+ [(char)Command]
+
+next. Currently the following commands are supported:
+
+ CAPABILITIES - returns the Server's capabilities
+ AUTHENTICATE - Starts the authentification process
+
+CAPABILITIES
+------------
+The server returns
+
+ [(char)Capabilities]
+
+where this currently can be the following:
+
+ USE_AUTHENTICATION - The server supports and requires authentication
+
+AUTHENTICATE
+------------
+The server returns
+
+ [(char)0x01]
+
+if authentication is supported AND needed (skypeproxy started with -k switch) or
+
+ [(char)0x00]
+
+if this is not the case.
+If 0x01 was returned the server next expects a normal message
+(see "Basic protocol structure) containing the password.
+If the authentication was successful, the server replies with
+
+ [(char)0x01]
+
+otherwise with
+
+ [(char)0x00]
+
+PLEASE NOTE THAT THE AUTHENTICATION CURRENTLY IS PLAIN TEXT. SO DON'T
+USE THIS PROGRAM OVER AN UNTRUSTED NETWORK, OTHERWISE THERE MAY BE THE
+POSSIBILITY THAT SOMEONE SNIFFS YOUR PASSWORD!
+
+Code example
+------------
+
+SOCKET MySocket;
+
+int SendPacket(char *szSkypeMessage) {
+ unsigned int length=strlen(szSkypeMsg);
+
+ if (send(MySocket, (char *)&length, sizeof(length), 0)==SOCKET_ERROR ||
+ send(MySocket, szSkypeMsg, length, 0)==SOCKET_ERROR)
+ return -1;
+ return 0;
+}
+
+// don't forget to free() the return value on my Heap!!
+char *ReceivePacket(void) {
+ unsigned int lenght, received;
+ char *buf;
+
+ if ((received=recv(MySocket, (char *)&length, sizeof(length), 0))==SOCKET_ERROR ||
+ received==0)
+ return NULL;
+ if (!(buf=calloc(1, length+1))) return NULL;
+ if (recv(MySocket, buf, length, 0)==SOCKET_ERROR) {
+ free(buf);
+ return NULL;
+ }
+ return buf;
+}
+
+
+License
+=======
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+History
+========
+V1.0alpha - First preview release
+V1.0 - Implemented killing & restarting Skype process when it dies
+ - BUGFIX: SendMessage() is a blocking call, if Skype hangs our app hangs too -> Fixed
+ - Added command line parsing.
+ - Renamed from Skype2Socket to skypeproxy
+ - Added authentication feature.
+*/
+
+#include <stdio.h>
+#include <process.h>
+#include <windows.h>
+#include <signal.h>
+#include "skypeproxy.h"
+
+UINT ControlAPIAttach, ControlAPIDiscover;
+HWND hSkypeWnd=NULL, hWnd;
+HANDLE SkypeReady, ServerThreadBye;
+LONG AttachStatus=-1;
+int exitcode=EXIT_SUCCESS;
+char skype_path[MAX_PATH], *password=NULL;
+BYTE WatchDog=1;
+BOOL WatchDogRunning=FALSE, Authenticated=FALSE;
+SOCKET ListenSocket, AcceptSocket;
+
+
+void bail_out(int i) {
+ OUTPUT("Got termination signal, bailing out.");
+ if (i==1) exitcode=EXIT_FAILURE;
+ PostMessage(hWnd, WM_QUIT, 0, 0);
+}
+
+BOOL CALLBACK TerminateAppEnum( HWND hwnd, LPARAM lParam ) {
+ DWORD dwID ;
+
+ GetWindowThreadProcessId(hwnd, &dwID) ;
+ if(dwID == (DWORD)lParam)
+ PostMessage(hwnd, WM_CLOSE, 0, 0) ; // May you be so kind to quit, please?
+
+ return TRUE ;
+}
+
+/* ConnectToSkypeAPI
+ *
+ * Purpose: Establish a connection to the Skype API
+ * Params : ForceRestart - Kill Skype if it's running before restarting
+ * Returns: 0 - Connecting succeeded
+ * -1 - Something went wrong
+ */
+void ConnectToSkypeAPI(void *ForceRestart) {
+ BOOL SkypeLaunched=FALSE;
+ int counter=0, i, j;
+ char *args[5];
+ char *SkypeOptions[]={"/notray", "/nosplash", "/minimized"};
+ char *szFuncName="ConnectToSkypeAPI";
+
+ ResetEvent(SkypeReady);
+ AttachStatus=-1;
+ if ((BOOL)ForceRestart) {
+ HANDLE hProc;
+ DWORD dwPID=0;
+
+ if (!hSkypeWnd) {
+ OUTPUT("I can't kill Skype, as I don't even have its window handle!");
+ return;
+ }
+ GetWindowThreadProcessId(hSkypeWnd, &dwPID);
+ LOG(("%s: Shutting down Skype as it was not behaving the way it should...", szFuncName));
+ if (hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID)) {
+
+ // Try to shutdown Skype the nice way by asking it to close
+ EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM) dwPID);
+
+ if(WaitForSingleObject(hProc, 10000)!=WAIT_OBJECT_0) {
+ // Try it the hard way by killing it
+ LOG(("%s: I tried it the nice way, but you were not listening! Now DIIIIEEE!", szFuncName));
+ if (!TerminateProcess(hProc,0)) {
+ OUTPUT("Argh, process refused to die, it's too mighty for me, I've given up");
+ CloseHandle(hProc);
+ return;
+ }
+ LOG(("%s: Process killed! >:)", szFuncName));
+ }
+ CloseHandle(hProc);
+ }
+ }
+ do {
+ /* To initiate communication, Client should broadcast windows message
+ ('SkypeControlAPIDiscover') to all windows in the system, specifying its own
+ window handle in wParam parameter.
+ */
+ LOG(("%s: Sending discover message..", szFuncName));
+ SendMessageTimeout(HWND_BROADCAST, ControlAPIDiscover, (WPARAM)hWnd, 0, SMTO_ABORTIFHUNG, 3000, NULL);
+ LOG(("%s: Discover message sent, waiting for Skype to become ready..", szFuncName));
+
+ /* In response, Skype responds with
+ message 'SkypeControlAPIAttach' to the handle specified, and indicates
+ connection status
+ SkypeReady is set if there is an answer by Skype other than API_AVAILABLE.
+ If there is no answer after 3 seconds, launch Skype as it's propably
+ not running.
+ */
+ if (WaitForSingleObject(SkypeReady, 3000)==WAIT_TIMEOUT &&
+ AttachStatus!=SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION)
+ {
+ if (hWnd==NULL) {
+ LOG(("%s: hWnd of SkypeDispatchWindow not yet set..", szFuncName));
+ continue;
+ }
+ if (!SkypeLaunched && skype_path) {
+ LOG(("%s: Starting Skype, as it's not running", szFuncName));
+ args[0]=skype_path;
+ j=1;
+ for (i=0; i<3; i++) {
+ args[j]=SkypeOptions[i];
+ LOG(("%s: Using Skype parameter: ", szFuncName, args[j]));
+ j++;
+ }
+ args[j]=NULL;
+ _spawnv(_P_NOWAIT, skype_path, args);
+ ResetEvent(SkypeReady);
+ SkypeLaunched=TRUE;
+ LOG(("%s: Skype process started.", szFuncName));
+ // Skype launching iniciated, keep sending Discover messages until it responds.
+ continue;
+ } else {
+ LOG(("%s: Check if Skype was launchable..", szFuncName));
+ if (!skype_path) {
+ OUTPUT("There was no correct path for Skype application");
+ bail_out(1);
+ return;
+ }
+ LOG("%s: Trying to attach: #%d", szFuncName, counter));
+ counter++;
+ if (counter==5) {
+ OUTPUT("ERROR: Skype not running / too old / working!");
+ bail_out(1);
+ return;
+ }
+ }
+ }
+ LOG(("%s: Attachstatus %d", szFuncName, AttachStatus));
+ } while (AttachStatus==SKYPECONTROLAPI_ATTACH_API_AVAILABLE || AttachStatus==-1);
+
+ while (AttachStatus==SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION) Sleep(1000);
+ LOG(("%s: Attachstatus %d", szFuncName, AttachStatus));
+ if (AttachStatus!=SKYPECONTROLAPI_ATTACH_SUCCESS) {
+ switch(AttachStatus) {
+ case SKYPECONTROLAPI_ATTACH_REFUSED:
+ OUTPUT("Skype refused the connection :(");
+ break;
+ case SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE:
+ OUTPUT("The Skype API is not available");
+ break;
+ default:
+ LOG(("%s: ERROR: AttachStatus: %d", szFuncName, AttachStatus));
+ OUTPUT("Wheee, Skype won't let me use the API. :(");
+ }
+ bail_out(1);
+ return;
+ }
+ OUTPUT("Attached to Skype successfully.");
+ if (!WatchDogRunning)
+ if (_beginthread(WatchDogTimer, 0, NULL)==-1) {
+ OUTPUT("Cannot start Watchdog.");
+ bail_out(1);
+ }
+ return;
+}
+
+void SkypeSend(char *szMsg) {
+ COPYDATASTRUCT CopyData;
+ int count=0;
+
+ if (!hSkypeWnd) {
+ LOG(("SkypeSend: DAMN! No Skype window handle! :("));
+ return;
+ }
+ if (strcmp(szMsg, "PING")) {LOG(("> %s", szMsg));}
+ CopyData.dwData=0;
+ CopyData.lpData=szMsg;
+ CopyData.cbData=strlen(szMsg)+1;
+ while (!SendMessageTimeout(hSkypeWnd, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&CopyData, SMTO_ABORTIFHUNG, 3000, NULL)) {
+ count++;
+ LOG(("SkypeSend: failed, try #%d", count));
+ if (count==5) {
+ OUTPUT("Sending message to Skype failed too often.");
+ OUTPUT("Skype may have died unexpectedly, I will try to restart it.");
+ ConnectToSkypeAPI((void *)TRUE);
+ OUTPUT("Restart complete. Trying to deliver message one more time.");
+ if (!SendMessageTimeout(hSkypeWnd, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&CopyData, SMTO_ABORTIFHUNG, 3000, NULL)) {
+ OUTPUT("It still failed. Skype seems to be completely f*cked up. I've given up. Bye..");
+ bail_out(1);
+ break;
+ } else {
+ OUTPUT("Now it worked! :)");
+ break;
+ }
+ }
+ Sleep(1000);
+ }
+}
+
+void ServerThread(char *dummy) {
+ unsigned int length, received;
+ char *buf, command, reply;
+
+ LOG(("ServerThread started"));
+ AcceptSocket=INVALID_SOCKET;
+ while( AcceptSocket == INVALID_SOCKET) {
+ if ((AcceptSocket = accept( ListenSocket, NULL, NULL ))==INVALID_SOCKET) {
+ LOG(("ServerThread: Byebye..."));
+ SetEvent(ServerThreadBye);
+ bail_out(1);
+ return;
+ }
+ OUTPUT("Connection by client");
+ while(1) {
+ if ((received=recv(AcceptSocket, (char *)&length, sizeof(length), 0))==SOCKET_ERROR ||
+ received==0)
+ {
+ OUTPUT("Connection was closed by client. See ya soon! :)");
+ break;
+ }
+ // Command mode
+ if (length==0) {
+ reply=0;
+ if (recv(AcceptSocket, (char *)&command, 1, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ break;
+ }
+#ifdef USE_AUTHENTICATION
+ if (command==AUTHENTICATE)
+ if (password) reply=0x01; // Ok, go ahead
+ else command=0;
+#endif
+ if (command==CAPABILITIES)
+ reply=password?USE_AUTHENTICATION:0;
+
+ if (send(AcceptSocket, (char *)&reply, 1, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ break;
+ }
+ continue;
+ }
+ // Normal Skype API-call
+ if (!(buf=calloc(1, length+1))) {
+ OUTPUT("Out of memory error while allocating buffer space.");
+ break;
+ }
+ if (recv(AcceptSocket, buf, length, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ free(buf);
+ break;
+ }
+ switch (command) {
+#ifdef USE_AUTHENTICATION
+ case 0x01: // Compare hash
+ if (password && !strcmp(password, buf)) Authenticated=TRUE;
+ else Authenticated=FALSE;
+ if (Authenticated) {
+ OUTPUT("User authenticated succesfully.");
+ reply=1;
+ } else {
+ OUTPUT("User authentication failed!! (Intruder?)");
+ reply=0;
+ }
+ if (send(AcceptSocket, (char *)&reply, 1, 0)==SOCKET_ERROR) {
+ OUTPUT("Connection to client was lost.");
+ break;
+ }
+ command=0;
+ break;
+#endif
+ default:
+#ifdef USE_AUTHENTICATION
+ if (password && !Authenticated) break;
+#endif
+ SkypeSend(buf);
+ }
+ command=0;
+ free(buf);
+ }
+ AcceptSocket=INVALID_SOCKET;
+#ifdef USE_AUTHENTICATION
+ Authenticated=FALSE;
+#endif
+ }
+}
+
+
+void WatchDogTimer(char *dummy) {
+ LOG(("WatchDogTimer started"));
+ WatchDogRunning=TRUE;
+ while (1) {
+ Sleep(PING_INTERVAL);
+ if (!WatchDog) {
+ OUTPUT("Ouch.. It seems that Skype has died unexpectedly. Trying to restart.");
+ ConnectToSkypeAPI((void *)TRUE);
+ }
+ WatchDog=0;
+ SkypeSend("PING");
+ }
+}
+
+LONG APIENTRY WndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
+{
+ PCOPYDATASTRUCT CopyData;
+ char *szSkypeMsg=NULL;
+
+ switch (message)
+ {
+ case WM_COPYDATA:
+// LOG("WM_COPYDATA", "start");
+ if(hSkypeWnd==(HWND)wParam) {
+ CopyData=(PCOPYDATASTRUCT)lParam;
+ szSkypeMsg=strdup(CopyData->lpData);
+ ReplyMessage(1);
+ if (!strcmp(szSkypeMsg, "PONG")) {
+ WatchDog=1;
+ break;
+ } // Hide PING-PONG
+ LOG(("< %s", szSkypeMsg));
+ if (!strcmp(szSkypeMsg, "USERSTATUS LOGGEDOUT")) {
+ OUTPUT("Skype shut down gracefully. I'll leave too, bye.. :)");
+ bail_out(1);
+ }
+#ifdef USE_AUTHENTICATION
+ if (password && !Authenticated) break;
+#endif
+ if (AcceptSocket!=INVALID_SOCKET) {
+ unsigned int length=strlen(szSkypeMsg);
+
+ if (send(AcceptSocket, (char *)&length, sizeof(length), 0)==SOCKET_ERROR ||
+ send(AcceptSocket, szSkypeMsg, length, 0)==SOCKET_ERROR)
+ OUTPUT("Cannot send to client :(");
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ if(message==ControlAPIAttach) {
+ // Skype responds with Attach to the discover-message
+ AttachStatus=lParam;
+ if (AttachStatus==SKYPECONTROLAPI_ATTACH_SUCCESS)
+ hSkypeWnd=(HWND)wParam; // Skype gave us the communication window handle
+ if (AttachStatus!=SKYPECONTROLAPI_ATTACH_API_AVAILABLE)
+ SetEvent(SkypeReady);
+ break;
+ }
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+ }
+// LOG("WM_COPYDATA", "exit");
+ if (szSkypeMsg) free(szSkypeMsg);
+ return 1;
+}
+
+
+void TellError(DWORD err) {
+ LPVOID lpMsgBuf;
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
+ MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
+ LocalFree( lpMsgBuf );
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ DWORD Buffsize;
+ HKEY MyKey;
+ BOOL SkypeInstalled=TRUE;
+ MSG Message;
+ WNDCLASS WndClass;
+ SOCKADDR_IN service;
+ WSADATA wsaData;
+ int ExitCode=STILL_ACTIVE;
+ unsigned short BindPort=1401;
+ char BindIP[16]="0.0.0.0";
+
+ printf("Skypeproxy V1.0, by leecher 2005 <leecher@dose.0wnz.at>\n\n");
+
+ if (argc>1) {
+ int i;
+
+ if (!stricmp(argv[1], "-h") || !stricmp(argv[1], "--help") || !stricmp(argv[1], "/?")) {
+ printf("Usage: %s [-i BindIP] [-p BindPort]", argv[0]);
+#ifdef USE_AUTHENTICATION
+ printf(" [-k Password]");
+#endif
+ printf("\n\n");
+ return EXIT_SUCCESS;
+ }
+ for (i=0;i<argc;i++) {
+ if (!stricmp(argv[i], "-i") && argc>i+1)
+ strncpy(BindIP, argv[i+1], sizeof(BindIP));
+ if (!stricmp(argv[i], "-p") && argc>i+1)
+ if (!(BindPort=atoi(argv[i+1]))) {
+ OUTPUT("ERROR: Cannot convert port to int. bye..");
+ return EXIT_FAILURE;
+ }
+#ifdef USE_AUTHENTICATION
+ if (!stricmp(argv[i], "-k") && argc>i+1)
+ password=strdup(argv[i+1]);
+#endif
+ }
+ }
+
+ if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Skype\\Phone", 0, KEY_READ, &MyKey)!=ERROR_SUCCESS ||
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Skype\\Phone", 0, KEY_READ, &MyKey)!=ERROR_SUCCESS)
+ SkypeInstalled=FALSE;
+ Buffsize=sizeof(skype_path);
+ if (SkypeInstalled==FALSE ||
+ RegQueryValueEx(MyKey, "SkypePath", NULL, NULL, skype_path, &Buffsize)!=ERROR_SUCCESS) {
+ OUTPUT("Skype was not found on this machine :(");
+ RegCloseKey(MyKey);
+ skype_path[0]=0;
+ return EXIT_FAILURE;
+ }
+ RegCloseKey(MyKey);
+
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR) {
+ OUTPUT("Error at loading windows sockets.");
+ return EXIT_FAILURE;
+ }
+
+ if ((ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
+ printf("* Error at creating socket(): Error %d", WSAGetLastError());
+ return EXIT_FAILURE;
+ }
+
+ service.sin_family = AF_INET;
+ service.sin_addr.s_addr = inet_addr(BindIP);
+ service.sin_port = htons(BindPort);
+
+ printf("* Binding to interface %s, Port %d..", BindIP, BindPort);
+ if (bind( ListenSocket, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR ||
+ listen( ListenSocket, 1 ) == SOCKET_ERROR)
+ {
+ OUTPUT("Failed.");
+ closesocket(ListenSocket);
+ return EXIT_FAILURE;
+ }
+ printf("OK\n");
+
+
+ if (!(ControlAPIAttach=RegisterWindowMessage("SkypeControlAPIAttach")) ||
+ !(ControlAPIDiscover=RegisterWindowMessage("SkypeControlAPIDiscover"))) {
+ OUTPUT("Cannot register Windows message.");
+ closesocket(ListenSocket);
+ return EXIT_FAILURE;
+ }
+
+ // Create window class
+ hSkypeWnd=NULL;
+ WndClass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
+ WndClass.lpfnWndProc = (WNDPROC)WndProc;
+ WndClass.cbClsExtra = 0;
+ WndClass.cbWndExtra = 0;
+ WndClass.hInstance = NULL;
+ WndClass.hIcon = NULL;
+ WndClass.hCursor = NULL;
+ WndClass.hbrBackground = NULL;
+ WndClass.lpszMenuName = NULL;
+ WndClass.lpszClassName = "SkypeApiDispatchWindow";
+ RegisterClass(&WndClass);
+ // Do not check the retval of RegisterClass, because on non-unicode
+ // win98 it will fail, as it is a stub that returns false() there
+
+ // Create main window
+ hWnd=CreateWindowEx( WS_EX_APPWINDOW|WS_EX_WINDOWEDGE,
+ "SkypeApiDispatchWindow", "", WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX,
+ CW_USEDEFAULT, CW_USEDEFAULT, 128, 128, NULL, 0, (HINSTANCE)WndClass.hInstance, 0);
+
+ if (!hWnd) {
+ OUTPUT("Cannot create window.");
+ TellError(GetLastError());
+ closesocket(ListenSocket);
+ CloseHandle(WndClass.hInstance);
+ return EXIT_FAILURE;
+ }
+ ShowWindow(hWnd, 0);
+ UpdateWindow(hWnd);
+
+ if (!(SkypeReady=CreateEvent(NULL, TRUE, FALSE, NULL)) ||
+ !(ServerThreadBye=CreateEvent(NULL, TRUE, FALSE, NULL))) {
+ OUTPUT("Unable to create Mutex!");
+ closesocket(ListenSocket);
+ CloseHandle(WndClass.hInstance);
+ return EXIT_FAILURE;
+ }
+
+ if (_beginthread(ConnectToSkypeAPI, 0, (void *)FALSE)==-1 ||
+ _beginthread(ServerThread, 0, NULL)==-1) {
+ OUTPUT("Cannot create thread. Bye..");
+ closesocket(ListenSocket);
+ CloseHandle(WndClass.hInstance);
+ CloseHandle(SkypeReady);
+ return EXIT_FAILURE;
+ }
+
+ signal(SIGINT, &bail_out);
+ LOG(("Startup: Messagepump started.\nPress CTRL+C to terminate\n"));
+
+ while (GetMessage(&Message, hWnd, 0, 0))
+ {
+ TranslateMessage(&Message);
+ DispatchMessage(&Message);
+ }
+
+ LOG(("Shutdown: Messagepump stopped"));
+
+ if (password) free(password);
+ if (AcceptSocket != INVALID_SOCKET) closesocket(AcceptSocket);
+ closesocket(ListenSocket);
+ LOG(("Shutdown: Waiting for serverthread to quit..."));
+ if (WaitForSingleObject(ServerThreadBye, 3000)==WAIT_TIMEOUT)
+ {OUTPUT("Serverthread didn't terminate correctly, shutting down anyway...");}
+ else
+ {LOG(("ServerThread terminated"));}
+ CloseHandle(WndClass.hInstance);
+ CloseHandle(SkypeReady);
+ return exitcode;
+} \ No newline at end of file
diff --git a/protocols/SkypeClassic/skypeproxy/skypeproxy.h b/protocols/SkypeClassic/skypeproxy/skypeproxy.h
new file mode 100644
index 0000000000..8ce122990b
--- /dev/null
+++ b/protocols/SkypeClassic/skypeproxy/skypeproxy.h
@@ -0,0 +1,36 @@
+/*** Skype API ***/
+//Messages
+#define SKYPECONTROLAPI_ATTACH_SUCCESS 0
+#define SKYPECONTROLAPI_ATTACH_PENDING_AUTHORIZATION 1
+#define SKYPECONTROLAPI_ATTACH_REFUSED 2
+#define SKYPECONTROLAPI_ATTACH_NOT_AVAILABLE 3
+#define SKYPECONTROLAPI_ATTACH_API_AVAILABLE 0x8001
+
+// Errors
+#define MISC_ERROR 1
+#define USER_NOT_FOUND 2
+#define USER_NOT_ONLINE 3
+#define USER_BLOCKED 4
+#define TYPE_UNSUPPORTED 5
+#define SENDER_NOT_FRIEND 6
+#define SENDER_NOT_AUTHORIZED 7
+
+
+/*** Debugging macros ***/
+#define OUTPUT(a) printf("* %s\n", a);
+#define LOG(a, b) printf("- %s: %s\n", a, b);
+#define LOGL(a, b) printf("- %s: %d\n", a, b);
+
+/*** Program settings ***/
+#define PING_INTERVAL 10000 // Ping every 10000 msec to see if Skype is still available
+#define USE_AUTHENTICATION 0x01 // Program supports authentication -> Comment to disable!
+
+/*** Commands ***/
+#define AUTHENTICATE 0x01
+#define CAPABILITIES 0x02
+
+/*** Sockets ***/
+#pragma comment(lib, "ws2_32")
+
+/*** Prototypes ***/
+void WatchDogTimer(char *); \ No newline at end of file
diff --git a/protocols/SkypeClassic/skypesvc.cpp b/protocols/SkypeClassic/skypesvc.cpp
new file mode 100644
index 0000000000..8641e5db67
--- /dev/null
+++ b/protocols/SkypeClassic/skypesvc.cpp
@@ -0,0 +1,188 @@
+#define __SKYPESVC_C__
+#include "skype.h"
+#include "skypesvc.h"
+#include "skypeapi.h"
+#include "skypeopt.h"
+#include "contacts.h"
+#include "m_toptoolbar.h"
+
+// Exports
+SKYPE_SVCNAMES g_svcNames;
+
+//From skype.c
+extern char protocol, g_szProtoName[];
+extern HINSTANCE hInst;
+extern DWORD mirandaVersion;
+static HANDLE m_hPrebuildCMenu=NULL, m_hStatusHookContact=NULL, m_hContactDeleted=NULL,
+ m_hHookModulesLoaded=NULL, m_hHookOkToExit=NULL, m_hOptHook=NULL, m_hHookMirandaExit=NULL,
+ m_hTTBModuleLoadedHook = NULL, m_hHookOnUserInfoInit = NULL;
+
+void CreateProtoService(const char* szService, MIRANDASERVICE svc)
+{
+ char str[MAXMODULELABELLENGTH];
+ _snprintf(str, sizeof(str), "%s%s", SKYPE_PROTONAME, szService);
+ CreateServiceFunction(str, svc);
+}
+
+#define CreateServiceName(srvce) _snprintf (g_svcNames.##srvce, sizeof(g_svcNames.##srvce), "%s/"#srvce, SKYPE_PROTONAME);
+
+void CreateServices(void)
+{
+ CreateServiceName(ChatNew);
+ CreateServiceName(SetAvatar);
+ CreateServiceName(SendFile);
+ CreateServiceName(HoldCall);
+ CreateServiceName(AnswerCall);
+ CreateServiceName(ImportHistory);
+ CreateServiceName(AddUser);
+ CreateServiceName(SkypeOutCallUser);
+ CreateServiceName(CallHangupUser);
+ CreateServiceName(CallUser);
+
+ CreateServiceFunction(SKYPE_CALL, SkypeCall);
+ CreateServiceFunction(SKYPE_CALLHANGUP, SkypeCallHangup);
+ CreateServiceFunction(SKYPEOUT_CALL, SkypeOutCall);
+ CreateServiceFunction(SKYPE_HOLDCALL, SkypeHoldCall);
+ CreateServiceFunction(SKYPE_ADDUSER, SkypeAdduserDlg);
+ CreateServiceFunction(SKYPE_IMPORTHISTORY, ImportHistory);
+ CreateServiceFunction(SKYPE_ANSWERCALL, SkypeAnswerCall);
+ CreateServiceFunction(SKYPE_SENDFILE, SkypeSendFile);
+ CreateServiceFunction(SKYPE_SETAVATAR, SkypeSetAvatar);
+
+ CreateProtoService(PS_GETCAPS, SkypeGetCaps);
+ CreateProtoService(PS_GETNAME, SkypeGetName);
+ CreateProtoService(PS_LOADICON, SkypeLoadIcon);
+ CreateProtoService(PS_SETSTATUS, SkypeSetStatus);
+ CreateProtoService(PS_GETSTATUS, SkypeGetStatus);
+ CreateProtoService(PS_ADDTOLIST, SkypeAddToList);
+ CreateProtoService(PS_ADDTOLISTBYEVENT, SkypeAddToListByEvent);
+ CreateProtoService(PS_BASICSEARCH, SkypeBasicSearch);
+
+ CreateProtoService(PSS_GETINFO, SkypeGetInfo);
+ CreateProtoService(PSS_MESSAGE, SkypeSendMessage);
+ CreateProtoService(PSR_MESSAGE, SkypeRecvMessage);
+ CreateProtoService(PSS_USERISTYPING, SkypeUserIsTyping);
+ CreateProtoService(PSS_AUTHREQUEST, SkypeSendAuthRequest);
+ CreateProtoService(PSR_AUTH, SkypeRecvAuth);
+ CreateProtoService(PS_AUTHALLOW, SkypeAuthAllow);
+ CreateProtoService(PS_AUTHDENY, SkypeAuthDeny);
+
+ CreateProtoService(PS_GETAVATARINFO, SkypeGetAvatarInfo);
+ CreateProtoService(PS_GETAVATARCAPS, SkypeGetAvatarCaps);
+ CreateProtoService(PS_GETMYAVATAR, SkypeGetAvatar);
+ CreateProtoService(PS_SETMYAVATAR, SkypeSetAvatar);
+
+ CreateProtoService(PS_SETAWAYMSG, SkypeSetAwayMessage);
+ CreateProtoService(PS_SETAWAYMSGW, SkypeSetAwayMessageW);
+ CreateProtoService(PSS_GETAWAYMSG, SkypeGetAwayMessage);
+ CreateProtoService(PS_SETMYNICKNAME, SkypeSetNick);
+
+ CreateProtoService(PSS_SKYPEAPIMSG, SkypeReceivedAPIMessage);
+ CreateProtoService(SKYPE_REGPROXY, SkypeRegisterProxy);
+}
+
+void HookEvents(void)
+{
+ m_hPrebuildCMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu);
+
+ //HookEvent(ME_CLIST_DOUBLECLICKED, ClistDblClick);
+ m_hOptHook = HookEvent(ME_OPT_INITIALISE, RegisterOptions);
+ m_hStatusHookContact = HookEvent(ME_DB_CONTACT_ADDED,HookContactAdded);
+ m_hContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, HookContactDeleted );
+ m_hHookModulesLoaded = HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+ m_hHookMirandaExit = HookEvent(ME_SYSTEM_OKTOEXIT, MirandaExit);
+ m_hHookOkToExit = HookEvent(ME_SYSTEM_PRESHUTDOWN, OkToExit);
+}
+
+void HookEventsLoaded(void)
+{
+ // We cannot check for the TTB-service before this event gets fired... :-/
+ m_hTTBModuleLoadedHook = HookEvent(ME_TTB_MODULELOADED, CreateTopToolbarButton);
+ m_hHookOnUserInfoInit = HookEvent( ME_USERINFO_INITIALISE, OnDetailsInit );
+}
+
+void UnhookEvents(void)
+{
+ UnhookEvent(m_hOptHook);
+ UnhookEvent(m_hTTBModuleLoadedHook);
+ UnhookEvent(m_hHookOnUserInfoInit);
+ UnhookEvent(m_hStatusHookContact);
+ UnhookEvent(m_hContactDeleted);
+ UnhookEvent(m_hHookModulesLoaded);
+ UnhookEvent(m_hPrebuildCMenu);
+ UnhookEvent(m_hHookOkToExit);
+ UnhookEvent(m_hHookMirandaExit);
+ //UnhookEvent(ClistDblClick);
+}
+
+INT_PTR SkypeGetCaps(WPARAM wParam, LPARAM lParam) {
+ int ret = 0;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch (wParam) {
+ case PFLAGNUM_1:
+ ret = PF1_BASICSEARCH | PF1_IM | PF1_MODEMSG; // | PF1_AUTHREQ;
+ if (protocol>=5) ret |= PF1_ADDSEARCHRES;
+ break;
+
+ case PFLAGNUM_2:
+ ret = PF2_ONLINE | PF2_SHORTAWAY | PF2_INVISIBLE | PF2_HEAVYDND;
+#ifdef MAPDND
+ ret |= PF2_LIGHTDND | PF2_HEAVYDND;
+#endif
+ if (!db_get_b(NULL, SKYPE_PROTONAME, "NoSkype3Stats", 0))
+ ret |= PF2_LONGAWAY | PF2_FREECHAT;
+ break;
+
+ case PFLAGNUM_3:
+ ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE | PF2_IDLE;
+ break;
+
+ case PFLAGNUM_4:
+ ret = PF4_FORCEAUTH | PF4_FORCEADDED | PF4_AVATARS | PF4_SUPPORTTYPING /* Not really, but libgaim compat. */;
+ if (mirandaVersion >= 0x070000) ret |= PF4_IMSENDUTF;
+ break;
+ case PFLAG_UNIQUEIDTEXT:
+ ret = (INT_PTR) "NAME";
+ break;
+ case PFLAG_UNIQUEIDSETTING:
+ ret = (INT_PTR) SKYPE_NAME;
+ break;
+ }
+ return ret;
+
+}
+
+INT_PTR SkypeGetName(WPARAM wParam, LPARAM lParam)
+{
+ if (lParam)
+ {
+ strncpy((char *)lParam, SKYPE_PROTONAME, wParam);
+ return 0; // Success
+ }
+ return 1; // Failure
+}
+
+
+INT_PTR SkypeLoadIcon(WPARAM wParam,LPARAM lParam)
+{
+ UINT id;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch(wParam&0xFFFF) {
+ case PLI_PROTOCOL: id=IDI_SKYPE; break; // IDI_MAIN is the main icon for the protocol
+ default: return (int)(HICON)NULL;
+ }
+ return (int)LoadImage(hInst,MAKEINTRESOURCE(id),IMAGE_ICON,GetSystemMetrics(wParam&PLIF_SMALL?SM_CXSMICON:SM_CXICON),GetSystemMetrics(wParam&PLIF_SMALL?SM_CYSMICON:SM_CYICON),0);
+}
+
+INT_PTR SkypeGetAvatar(WPARAM wParam,LPARAM lParam)
+{ DBVARIANT dbv;
+ if (!db_get_s(NULL,SKYPE_PROTONAME, "AvatarFile", &dbv)){
+ lstrcpynA((char*)wParam, dbv.pszVal, (int)lParam);
+ db_free(&dbv);
+ }
+ return 0;
+}
diff --git a/protocols/SkypeClassic/skypesvc.h b/protocols/SkypeClassic/skypesvc.h
new file mode 100644
index 0000000000..74c8cd37bf
--- /dev/null
+++ b/protocols/SkypeClassic/skypesvc.h
@@ -0,0 +1,24 @@
+#include <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <process.h>
+#include <time.h>
+#include "resource.h"
+
+void CreateProtoService(const char* szService, MIRANDASERVICE svc);
+void HookEvents(void);
+void HookEventsLoaded(void);
+void UnhookEvents(void);
+void CreateServices(void);
+INT_PTR SkypeLoadIcon(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeGetName(WPARAM wParam, LPARAM lParam);
+INT_PTR SkypeGetCaps(WPARAM wParam, LPARAM lParam);
+/* SkypeGetAvatar
+ *
+ * Purpose: Return the avatar file name
+ * Params : wParam=0
+ * lParam=0
+ * Returns: 0 - Success
+ * -1 - Failure
+ */
+INT_PTR SkypeGetAvatar(WPARAM wParam,LPARAM lParam); \ No newline at end of file
diff --git a/protocols/SkypeClassic/utf8.cpp b/protocols/SkypeClassic/utf8.cpp
new file mode 100644
index 0000000000..8ae746e871
--- /dev/null
+++ b/protocols/SkypeClassic/utf8.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+
+#ifdef _WIN32
+
+ /* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+ * code.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+ int size = 0, index = 0, out_index = 0;
+ unsigned char *out;
+ unsigned short c;
+
+ /* first calculate the size of the target string */
+ c = unicode[index++];
+ while(c) {
+ if(c < 0x0080) {
+ size += 1;
+ } else if(c < 0x0800) {
+ size += 2;
+ } else {
+ size += 3;
+ }
+ c = unicode[index++];
+ }
+
+ out = (unsigned char *) malloc(size + 1);
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = unicode[index++];
+ while(c)
+ {
+ if(c < 0x080) {
+ out[out_index++] = (unsigned char)c;
+ } else if(c < 0x800) {
+ #pragma warning (suppress: 4244) // conversion from 'int' to 'unsigned char', possible loss of data
+ out[out_index++] = 0xc0 | (c >> 6);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ } else {
+ out[out_index++] = 0xe0 | (c >> 12);
+ out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }
+ c = unicode[index++];
+ }
+ out[out_index] = 0x00;
+
+ return out;
+}
+
+wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+ int size = 0, index = 0, out_index = 0;
+ wchar_t *out;
+ unsigned char c;
+
+ /* first calculate the size of the target string */
+ c = utf8[index++];
+ while(c) {
+ if((c & 0x80) == 0) {
+ index += 0;
+ } else if((c & 0xe0) == 0xe0) {
+ index += 2;
+ } else {
+ index += 1;
+ }
+ size += 1;
+ c = utf8[index++];
+ }
+
+ out = (wchar_t *) malloc((size + 1) * sizeof(wchar_t));
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = utf8[index++];
+ while(c)
+ {
+ if((c & 0x80) == 0) {
+ out[out_index++] = c;
+ } else if((c & 0xe0) == 0xe0) {
+ out[out_index] = (c & 0x1F) << 12;
+ c = utf8[index++];
+ out[out_index] |= (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ } else {
+ out[out_index] = (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }
+ c = utf8[index++];
+ }
+ out[out_index] = 0;
+
+ return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int wchars, err;
+
+ wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), NULL, 0);
+
+ if(wchars == 0)
+ {
+// fprintf(stderr, "Unicode translation error %d\n"), GetLastError();
+ return -1;
+ }
+
+ unicode = (wchar_t *) calloc(wchars + 1, sizeof(unsigned short));
+ if(unicode == NULL)
+ {
+// fprintf(stderr, "Out of memory processing string to UTF8\n");
+ return -1;
+ }
+
+ err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, strlen(from), unicode, wchars);
+ if(err != wchars)
+ {
+ free(unicode);
+// fprintf(stderr, "Unicode translation error %d\n"), GetLastError();
+ return -1;
+ }
+
+ /* On NT-based windows systems, we could use WideCharToMultiByte(), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ *to = (char *) make_utf8_string(unicode);
+
+ free(unicode);
+ return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int chars, err;
+// LPCPINFO lpCPInfo;
+
+ /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ unicode = make_unicode_string( (const unsigned char *)from);
+ if(unicode == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+ return -1;
+ }
+
+ //if(GetCPInfo(CP_ACP,lpCPInfo))
+ {
+
+ chars = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+ }
+ /*else
+ {
+ chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
+ }*/
+
+ if(chars == 0)
+ {
+ fprintf(stderr, "Unicode translation error %ld\n", GetLastError());
+ free(unicode);
+ return -1;
+ }
+
+ *to = (char *) calloc(chars + 1, sizeof(unsigned char));
+ if(*to == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string to local charset\n");
+ free(unicode);
+ return -1;
+ }
+
+ //err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+ err = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
+ if(err != chars)
+ {
+ fprintf(stderr, "Unicode translation error %ld\n", GetLastError());
+ free(unicode);
+ free(*to);
+ *to = NULL;
+ return -1;
+ }
+
+ free(unicode);
+ return 0;
+}
+
+#ifndef _UNICODE
+char *make_tchar_string(const unsigned char *utf8) {
+ char *ret;
+ if (utf8_decode((const char*)utf8, &ret)==-1) return NULL;
+ return ret;
+}
+#endif
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+int iconvert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen);
+
+static char *current_charset = "BIG-5"; /* means "US-ASCII" */
+
+void convert_set_charset(const char *charset)
+{
+
+ if (!charset)
+ charset = getenv("CHARSET");
+
+#ifdef HAVE_LANGINFO_CODESET
+ if (!charset)
+ charset = nl_langinfo(CODESET);
+#endif
+
+ free(current_charset);
+ current_charset = 0;
+ if (charset && *charset)
+ current_charset = _strdup(charset);
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen)
+{
+ int ret = -1;
+
+#ifdef HAVE_ICONV
+ ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+ ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+ return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+ const char *from, char **to, char replace)
+{
+ int ret;
+ size_t fromlen;
+ char *s;
+
+ fromlen = lstrlen(from);
+ ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+ if (ret == -2)
+ return -1;
+ if (ret != -1)
+ return ret;
+
+ s = malloc(fromlen + 1);
+ if (!s)
+ return -1;
+ lstrcpy(s, from);
+ *to = s;
+ for (; *s; s++)
+ if (*s & ~0x7f)
+ *s = replace;
+ return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ char *charset;
+
+ if (!current_charset)
+ convert_set_charset(0);
+ charset = current_charset ? current_charset : "US-ASCII";
+ return convert_string(charset, "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ char *charset;
+
+ if(*from == 0) {
+ *to = malloc(1);
+ **to = 0;
+ return 1;
+ }
+
+ if (!current_charset)
+ convert_set_charset(0);
+ charset = current_charset ? current_charset : "US-ASCII";
+ return convert_string("UTF-8", charset, from, to, '?');
+}
+
+#endif
diff --git a/protocols/SkypeClassic/utf8.h b/protocols/SkypeClassic/utf8.h
new file mode 100644
index 0000000000..70c533deca
--- /dev/null
+++ b/protocols/SkypeClassic/utf8.h
@@ -0,0 +1,47 @@
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ * -1 : memory allocation failed
+ * 0 : data was converted exactly
+ * 1 : valid data was converted approximately (using '?')
+ * 2 : input was invalid (but still converted, using '#')
+ * 3 : unknown encoding (but still converted, using '?')
+ */
+
+#ifndef __UTF8_H
+#define __UTF8_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void convert_set_charset(const char *charset);
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+wchar_t *make_unicode_string(const unsigned char *utf8);
+unsigned char *make_utf8_string(const wchar_t *unicode);
+#ifdef _UNICODE
+#define make_tchar_string make_unicode_string
+// Helpers for strings that only can contain 7bit chars to not make unneccessary memory allocation
+#define make_nonutf_tchar_string(x) make_tchar_string(x)
+#define free_nonutf_tchar_string(x) if(x) free(x);
+#else
+char *make_tchar_string(const unsigned char *utf8);
+#define make_nonutf_tchar_string(x) (char*)x
+#define free_nonutf_tchar_string(x)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UTF8_H */
diff --git a/protocols/SkypeClassic/util.cpp b/protocols/SkypeClassic/util.cpp
new file mode 100644
index 0000000000..ce5ad9c756
--- /dev/null
+++ b/protocols/SkypeClassic/util.cpp
@@ -0,0 +1,57 @@
+#include <stdlib.h>
+
+char * __cdecl strtok_r (
+ char * string,
+ const char * control,
+ char **nextoken
+ )
+{
+ unsigned char *str;
+ const unsigned char *ctrl = (const unsigned char*)control;
+
+ unsigned char map[32];
+ int count;
+
+ /* Clear control map */
+ for (count = 0; count < 32; count++)
+ map[count] = 0;
+
+ /* Set bits in delimiter table */
+ do {
+ map[*ctrl >> 3] |= (1 << (*ctrl & 7));
+ } while (*ctrl++);
+
+ /* Initialize str. If string is NULL, set str to the saved
+ * pointer (i.e., continue breaking tokens out of the string
+ * from the last strtok call) */
+ if (string)
+ str = (unsigned char*)string;
+ else
+ str = (unsigned char*)(*nextoken);
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets str to point to the terminal
+ * null (*str == '\0') */
+ while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )
+ str++;
+
+ string = (char*)str;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there. */
+ for ( ; *str ; str++ )
+ if ( map[*str >> 3] & (1 << (*str & 7)) ) {
+ *str++ = '\0';
+ break;
+ }
+
+ /* Update nextoken (or the corresponding field in the per-thread data
+ * structure */
+ *nextoken = (char*)str;
+
+ /* Determine if a token has been found. */
+ if ( string == (char*)str )
+ return NULL;
+ else
+ return string;
+}
diff --git a/protocols/SkypeClassic/util.h b/protocols/SkypeClassic/util.h
new file mode 100644
index 0000000000..181f5d1878
--- /dev/null
+++ b/protocols/SkypeClassic/util.h
@@ -0,0 +1,7 @@
+char * __cdecl strtok_r (
+ char * string,
+ const char * control,
+ char **nextoken
+ );
+
+void TranslateMirandaRelativePathToAbsolute(LPCSTR cszPath, LPSTR szAbsolutePath, BOOL fQuoteSpaces);
diff --git a/protocols/SkypeClassic/voiceservice.cpp b/protocols/SkypeClassic/voiceservice.cpp
new file mode 100644
index 0000000000..2a22bbe86c
--- /dev/null
+++ b/protocols/SkypeClassic/voiceservice.cpp
@@ -0,0 +1,156 @@
+#include "skype.h"
+#include "skypeapi.h"
+#include "skypesvc.h"
+#include "voiceservice.h"
+#include <m_voiceservice.h>
+
+#pragma warning (push)
+#pragma warning (disable: 4100) // unreferenced formal parameter
+#include <m_utils.h>
+#pragma warning (pop)
+
+HANDLE hVoiceNotify = NULL;
+BOOL has_voice_service = FALSE;
+
+extern char g_szProtoName[];
+
+
+BOOL HasVoiceService()
+{
+ return has_voice_service;
+}
+
+void NofifyVoiceService(HANDLE hContact, char *callId, int state)
+{
+ VOICE_CALL vc = {0};
+ vc.cbSize = sizeof(vc);
+ vc.szModule = SKYPE_PROTONAME;
+ vc.id = callId;
+ vc.flags = VOICE_CALL_CONTACT;
+ vc.state = state;
+ vc.hContact = hContact;
+ NotifyEventHooks(hVoiceNotify, (WPARAM) &vc, 0);
+}
+
+static INT_PTR VoiceGetInfo(WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(wParam);
+ UNREFERENCED_PARAMETER(lParam);
+
+ return VOICE_SUPPORTED | VOICE_CALL_CONTACT | VOICE_CAN_HOLD;
+}
+
+static HANDLE FindContactByCallId(char *callId)
+{
+ HANDLE hContact;
+ int iCmpRes;
+ for (hContact = db_find_first();
+ hContact != NULL;
+ hContact = db_find_next(hContact))
+ {
+ char *szProto = (char*) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+
+ DBVARIANT dbv;
+ if (szProto != NULL
+ && !strcmp(szProto, SKYPE_PROTONAME)
+ && db_get_b(hContact, SKYPE_PROTONAME, "ChatRoom", 0) == 0
+ && !db_get_s(hContact, SKYPE_PROTONAME, "CallId", &dbv))
+ {
+ iCmpRes = strcmp(callId, dbv.pszVal);
+ db_free(&dbv);
+ if (iCmpRes == 0) return hContact;
+ }
+ }
+
+ return NULL;
+}
+
+static INT_PTR VoiceCall(WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!wParam) return -1;
+
+ if (db_get_s((HANDLE)wParam, SKYPE_PROTONAME, SKYPE_NAME, &dbv))
+ return -1;
+
+ SkypeSend("CALL %s", dbv.pszVal);
+ db_free (&dbv);
+
+ return 0;
+}
+
+static INT_PTR VoiceAnswer(WPARAM wParam, LPARAM lParam)
+{
+ char *callId = (char *) wParam;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!wParam) return -1;
+
+ if (FindContactByCallId(callId) == NULL)
+ return -1;
+
+ SkypeSend("SET %s STATUS INPROGRESS", callId);
+ testfor("ERROR", 200);
+
+ return 0;
+}
+
+static INT_PTR VoiceDrop(WPARAM wParam, LPARAM lParam)
+{
+ char *callId = (char *) wParam;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!wParam) return -1;
+
+ if (FindContactByCallId(callId) == NULL)
+ return -1;
+
+ SkypeSend("SET %s STATUS FINISHED", callId);
+
+ return 0;
+}
+
+static INT_PTR VoiceHold(WPARAM wParam, LPARAM lParam)
+{
+ char *callId = (char *) wParam;
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ if (!wParam) return -1;
+
+ if (FindContactByCallId(callId) == NULL)
+ return -1;
+
+ SkypeSend("SET %s STATUS ONHOLD", callId);
+
+ return 0;
+}
+
+void VoiceServiceInit()
+{
+ // leecher, 26.03.2011: Did this ever work in the old versions??
+ char szEvent[MAXMODULELABELLENGTH];
+
+ _snprintf (szEvent, sizeof(szEvent), "%s%s", SKYPE_PROTONAME, PE_VOICE_CALL_STATE);
+ hVoiceNotify = CreateHookableEvent( szEvent );
+ CreateProtoService( PS_VOICE_GETINFO, VoiceGetInfo );
+ CreateProtoService( PS_VOICE_CALL, VoiceCall );
+ CreateProtoService( PS_VOICE_ANSWERCALL, VoiceAnswer );
+ CreateProtoService( PS_VOICE_DROPCALL, VoiceDrop );
+ CreateProtoService( PS_VOICE_HOLDCALL, VoiceHold );
+}
+
+void VoiceServiceExit()
+{
+ DestroyHookableEvent(hVoiceNotify);
+}
+
+void VoiceServiceModulesLoaded()
+{
+ has_voice_service = ServiceExists(MS_VOICESERVICE_REGISTER);
+} \ No newline at end of file
diff --git a/protocols/SkypeClassic/voiceservice.h b/protocols/SkypeClassic/voiceservice.h
new file mode 100644
index 0000000000..0ffbd6d9ca
--- /dev/null
+++ b/protocols/SkypeClassic/voiceservice.h
@@ -0,0 +1,18 @@
+#ifndef _VOICESERVICE_H_
+#define _VOICESERVICE_H_
+
+#pragma warning (push)
+#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
+#include <m_voice.h>
+#pragma warning (pop)
+
+BOOL HasVoiceService();
+void VoiceServiceInit();
+void VoiceServiceExit();
+void VoiceServiceModulesLoaded();
+void NofifyVoiceService(HANDLE hContact, char *callId, int state) ;
+
+
+
+#endif // _VOICESERVICE_H_
+