summaryrefslogtreecommitdiff
path: root/miranda-wine/protocols/MSN
diff options
context:
space:
mode:
authorwatcherhd <watcherhd@e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb>2011-04-21 14:14:52 +0000
committerwatcherhd <watcherhd@e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb>2011-04-21 14:14:52 +0000
commitcb4a46e7fbe62d788e66ed6121c717a2d22a4d7c (patch)
tree30df260fdc5a1b5a7049c2f8cac8b7ef17513d6d /miranda-wine/protocols/MSN
parent19b6f534d2e784a1e120bf52c4aa07004798f473 (diff)
svn.miranda.im is moving to a new home!
git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb
Diffstat (limited to 'miranda-wine/protocols/MSN')
-rw-r--r--miranda-wine/protocols/MSN/Icos/avatar.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/inbox.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/invite.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_al.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_bl.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_fl.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/list_rl.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/msn.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/msnblock.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/netmeeting.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/nudge.icobin0 -> 1406 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/profile.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/Icos/services.icobin0 -> 2550 bytes
-rw-r--r--miranda-wine/protocols/MSN/SDK/m_chat.h424
-rw-r--r--miranda-wine/protocols/MSN/mmdecsjis.cpp489
-rw-r--r--miranda-wine/protocols/MSN/msn.cpp407
-rw-r--r--miranda-wine/protocols/MSN/msn.rc348
-rw-r--r--miranda-wine/protocols/MSN/msn_bitmap.cpp213
-rw-r--r--miranda-wine/protocols/MSN/msn_block.cpp33
-rw-r--r--miranda-wine/protocols/MSN/msn_chat.cpp335
-rw-r--r--miranda-wine/protocols/MSN/msn_commands.cpp1841
-rw-r--r--miranda-wine/protocols/MSN/msn_contact.cpp74
-rw-r--r--miranda-wine/protocols/MSN/msn_errors.cpp95
-rw-r--r--miranda-wine/protocols/MSN/msn_ftold.cpp347
-rw-r--r--miranda-wine/protocols/MSN/msn_global.h641
-rw-r--r--miranda-wine/protocols/MSN/msn_http.cpp97
-rw-r--r--miranda-wine/protocols/MSN/msn_libstr.cpp54
-rw-r--r--miranda-wine/protocols/MSN/msn_lists.cpp346
-rw-r--r--miranda-wine/protocols/MSN/msn_md5.h59
-rw-r--r--miranda-wine/protocols/MSN/msn_md5c.cpp287
-rw-r--r--miranda-wine/protocols/MSN/msn_mime.cpp162
-rw-r--r--miranda-wine/protocols/MSN/msn_misc.cpp1069
-rw-r--r--miranda-wine/protocols/MSN/msn_msgqueue.cpp162
-rw-r--r--miranda-wine/protocols/MSN/msn_opts.cpp866
-rw-r--r--miranda-wine/protocols/MSN/msn_p2p.cpp1433
-rw-r--r--miranda-wine/protocols/MSN/msn_p2ps.cpp248
-rw-r--r--miranda-wine/protocols/MSN/msn_srv.cpp184
-rw-r--r--miranda-wine/protocols/MSN/msn_ssl.cpp667
-rw-r--r--miranda-wine/protocols/MSN/msn_std.cpp158
-rw-r--r--miranda-wine/protocols/MSN/msn_svcs.cpp1404
-rw-r--r--miranda-wine/protocols/MSN/msn_switchboard.cpp53
-rw-r--r--miranda-wine/protocols/MSN/msn_threads.cpp723
-rw-r--r--miranda-wine/protocols/MSN/msn_useropts.cpp287
-rw-r--r--miranda-wine/protocols/MSN/msn_ws.cpp324
-rw-r--r--miranda-wine/protocols/MSN/resource.h111
-rw-r--r--miranda-wine/protocols/MSN/resource.rc2
-rw-r--r--miranda-wine/protocols/MSN/sha1.c419
-rw-r--r--miranda-wine/protocols/MSN/sha1.h114
-rw-r--r--miranda-wine/protocols/MSN/version.h3
-rw-r--r--miranda-wine/protocols/MSN/version.rc36
50 files changed, 14515 insertions, 0 deletions
diff --git a/miranda-wine/protocols/MSN/Icos/avatar.ico b/miranda-wine/protocols/MSN/Icos/avatar.ico
new file mode 100644
index 0000000..ec321e6
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/avatar.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/inbox.ico b/miranda-wine/protocols/MSN/Icos/inbox.ico
new file mode 100644
index 0000000..55097a1
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/inbox.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/invite.ico b/miranda-wine/protocols/MSN/Icos/invite.ico
new file mode 100644
index 0000000..2efc4dc
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/invite.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_al.ico b/miranda-wine/protocols/MSN/Icos/list_al.ico
new file mode 100644
index 0000000..d71446d
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_al.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_bl.ico b/miranda-wine/protocols/MSN/Icos/list_bl.ico
new file mode 100644
index 0000000..c3fd47d
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_bl.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_fl.ico b/miranda-wine/protocols/MSN/Icos/list_fl.ico
new file mode 100644
index 0000000..d85c54b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_fl.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/list_rl.ico b/miranda-wine/protocols/MSN/Icos/list_rl.ico
new file mode 100644
index 0000000..b921290
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/list_rl.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/msn.ico b/miranda-wine/protocols/MSN/Icos/msn.ico
new file mode 100644
index 0000000..966acba
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/msn.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/msnblock.ico b/miranda-wine/protocols/MSN/Icos/msnblock.ico
new file mode 100644
index 0000000..db4af0c
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/msnblock.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/netmeeting.ico b/miranda-wine/protocols/MSN/Icos/netmeeting.ico
new file mode 100644
index 0000000..169f799
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/netmeeting.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/nudge.ico b/miranda-wine/protocols/MSN/Icos/nudge.ico
new file mode 100644
index 0000000..73613d2
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/nudge.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/profile.ico b/miranda-wine/protocols/MSN/Icos/profile.ico
new file mode 100644
index 0000000..a2c16ae
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/profile.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/Icos/services.ico b/miranda-wine/protocols/MSN/Icos/services.ico
new file mode 100644
index 0000000..5b0db43
--- /dev/null
+++ b/miranda-wine/protocols/MSN/Icos/services.ico
Binary files differ
diff --git a/miranda-wine/protocols/MSN/SDK/m_chat.h b/miranda-wine/protocols/MSN/SDK/m_chat.h
new file mode 100644
index 0000000..28f8e68
--- /dev/null
+++ b/miranda-wine/protocols/MSN/SDK/m_chat.h
@@ -0,0 +1,424 @@
+/*
+Chat module plugin for Miranda IM
+
+Copyright (C) 2003 Jörgen Persson
+
+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.
+*/
+
+
+#if 0
+
+/*
+ This plugin provides event driven chat rooms for protocols that wish to use it.
+ It is built for IRC, which I also develop and is naturally biased towards IRC,
+ but it should work very well with other protocols too. I will try to explain as
+ careful as possible in this document how to use chat.dll
+
+ -- General guidelines --
+
+ There is one rule a protocol MUST follow to use this:
+
+ 1. Do not touch contacts that has a byte "ChatRoom" set to ANYTHING other than 0! (Could be 1, 2, 3, ...)
+ This is because chat.dll adds contacts to the clist using the protocol name
+ supplied by the protocol. But this will naturally not work well if the
+ protocol also tampers with the contacts. The value of the BYTE indicates which type of
+ window/contact it is (see the GCW_* flags below). There is two exceptions to this rule:
+
+ * You should continue to handle the right click menu items of these
+ contacts as usual, by hooking the menu prebuild hook etc. Chat.dll can not
+ handle this in an efficient manner!
+
+ * You should also handle when the user deletes the contact/room from the
+ contact list, as the protocol will then most likely have to send some message
+ to the server that the user has left the room.
+
+ 2. The chat.dll plugin keeps its own copies of strings passed.
+
+*/
+
+
+// Example of implementing point 1:
+
+// This is a code snippet that is common in protocols:
+
+
+
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ szProto = (char *) MSN_CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !lstrcmpiA(szProto, PROTONAME))
+ {
+// ... do something with the hContact here;
+ }
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+
+
+// You should do this instead:
+
+
+
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ szProto = (char *) MSN_CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !lstrcmpiA(szProto, PROTONAME))
+ {
+ if(DBGetContactSettingByte(hContact, PROTONAME, "ChatRoom", 0) == 0)
+ {
+// ... do something with the hContact here;
+ }
+ }
+ hContact = (HANDLE) MSN_CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+
+// There is not more to it than that. To recapitulate: do not touch contacts where the
+// BYTE "ChatRoom" is set to 1, apart from the two exceptions mentioned!
+
+// ... now onto how to use this thing!
+
+
+#endif
+
+
+
+//------------------------- SERVICES ------------------------
+/*
+ -- Register with the chat module --
+
+ The first thing that a protocol need to do is register with chat.dll. This is best done
+ after ALL modules has loaded naturally. The registration is needed to make sure that
+ the protocol obey rule 1 mentioned above, but equally important to set protocol specific
+ settings.
+
+ wParam= NULL
+ lParam= (LPARAM)(GCREGISTER *)gcr
+ returns 0 on success or nonzero on failure
+*/
+
+#define GC_BOLD 0x0001 //enable the 'bold' button
+#define GC_ITALICS 0x0002 //enable the 'italics' button
+#define GC_UNDERLINE 0x0004 //enable the 'underline' button
+#define GC_COLOR 0x0008 //enable the 'foreground color' button
+#define GC_BKGCOLOR 0x0010 //enable the 'background color' button
+#define GC_ACKMSG 0x0020 //the protocol must ack. messages sent
+#define GC_TYPNOTIF 0x0040 //enable typing notifications
+#define GC_CHANMGR 0x0080 //enable the 'channel settings' button
+
+typedef struct {
+ int cbSize; //Set to sizeof();
+ DWORD dwFlags; //Use GC_* flags above
+ const char *pszModule; //This MUST be the protocol name as registered with Miranda IM
+ const char *pszModuleDispName; //This is the protocol name as it will be displayed to the user
+ int iMaxText; //Max message length the protocol supports. Will limit the typing area
+ int nColors; //Number of colors in the colorchooser menu for the color buttons. Max = 100
+ COLORREF* pColors; //pointer to the first static COLORREF array. ie: COLORREF crCols[nColors]; pColors = &crCols[0];
+ } GCREGISTER;
+#define MS_GC_REGISTER "GChat/Register"
+
+
+
+/*
+ -- Tell the chat module to create a new window --
+
+ Create a new chat room and set various settings related to it. This is not
+ the same as actually joining the chat room. The chat room will not be visible
+ to the user until the 'set up' phase is completed. See the MS_GC_EVENT for that.
+
+ wParam=0
+ lParam=(LPARAM)(GCWINDOW*)gcw
+
+ returns 0 on success or nonzero on failure
+*/
+#define GCW_CHATROOM 1
+#define GCW_SERVER 2
+#define GCW_PRIVMESS 3
+
+typedef struct {
+ int cbSize; //Set to sizeof();
+ int iType; //Use one of the GCW_* flags above to set the general type of usage for the window
+ const char *pszModule; //The name of the protocol owning the window (the same as pszModule when you register)
+ const char *pszName; //The name of the chat room as it will be displayed to the user
+ const char *pszID; //The unique identifier for the chat room
+ const char *pszStatusbarText; //Optional text to set in the statusbar, or NULL.
+ BOOL bDisableNickList; //Disable the nicklist
+ DWORD dwItemData; //Set user defined data for this chat room. Retrieve it by using the service below
+ } GCWINDOW;
+#define MS_GC_NEWCHAT "GChat/NewChat"
+
+
+
+/*
+ -- Show an event --
+
+ Events is what drives chat.dll! After having created the chat room with
+ MS_GC_NEWCHAT it is time to make it work for real. Start off by telling chat.dll
+ what statuses a user can have by sending GC_EVENT_ADDGROUP as many times as needed.
+ Then send join events
+ (GC_EVENT_JOIN) to populate the user list. You will need to send one event
+ per user that should be added. When you are done with filling the user list
+ it is a good time to end the 'set up' phase and make the window visible by
+ calling a GC_EVENT_VISIBILITY event. A nice tip is to make sure the bAddToLog
+ member of GCEVENT is set to FALSE during the initial filling of the user list.
+
+ The GCDEST structure and its members are always used, but what members of
+ GCEVENT to use is determined by what event is sent to chat.dll. bAddToLog and
+ time is valid (at least where it makes sense). See the description of each event
+ for more information of what members that are valid.
+
+ It is possible to send formatted text (bold, italics, underlined, foreground color
+ and background color) by using the following keywords in pszText:
+ %cRRRGGGBBB - set the foreground color
+ %C - set foreground color to default
+ %fRRRGGGBBB - set the background color
+ %F - set the background color to default
+ %b - enable bold
+ %B - disable bold
+ %u - enable underlined
+ %U - disable underlined
+ %i - enable italics
+ %I - disable italics
+ %r - reset all to default
+ %% - escape the formatting. Translates to %
+
+ wParam=0
+ lParam=(LPARAM)(GCEVENT *) gce
+
+ returns 0 on success or nonzero on failure
+*/
+
+
+// GC_EVENT_JOIN <pszNick> has joined
+// A user is joining the channel, set bIsMe to indicate who is the user
+// pszNick - Display name
+// pszUID - Unique identifier
+// pszStatus - Which group (status) to add the user to
+// bIsMe - Is this the user? Used to indicate that the user has joined the channel
+#define GC_EVENT_JOIN 0x0001
+
+// GC_EVENT_PART <pszNick> has left[: pszText]
+// A user left the chat room
+// pszUID - Unique identifier
+// pszText - part message
+#define GC_EVENT_PART 0x0002
+
+// GC_EVENT_QUIT <pszNick> disconnected[: pszText]
+// A user disconnected, use pszID = NULL (of GCDEST) to broadcast to all windows.
+// pszUID - Unique identifier
+// pszText - part message
+#define GC_EVENT_QUIT 0x0004
+
+// GC_EVENT_KICK <pszStatus> kicked <pszNick>
+// A user is kicking another user from the room
+// pszUID - Unique identifier of the one being kicked
+// pszStatus - Name of user doing the kick
+#define GC_EVENT_KICK 0x0008
+
+// GC_EVENT_NICK <pszNick> is now known as <pszText>
+// A user changed his name
+// NOTE, see GC_EVENT_CHID also
+// pszUID - Unique identifier of the one changing name
+// pszText - New name of the user
+#define GC_EVENT_NICK 0x0010
+
+// GC_EVENT_NOTICE Notice from <pszNick>: <pszText>
+// An IRC type notice, will be sent to the active window
+// pszUID - Unique identifier
+// pszText - Notice text
+#define GC_EVENT_NOTICE 0x0020
+
+// GC_EVENT_MESSAGE
+// A regular chat room message
+// is outgoing or incoming
+// pszUID - Unique identifier
+// pszText - Message text, use the formatting variables above.
+// NOTE make sure % is translated to %% to avoid accidental formatting
+#define GC_EVENT_MESSAGE 0x0040
+
+// GC_EVENT_TOPIC Topic is <pszText>
+// pszUID - Unique identifier
+// pszText - Topic text
+#define GC_EVENT_TOPIC 0x0080
+
+// GC_EVENT_INFORMATION
+// Informational style text
+// pszText - Information text
+#define GC_EVENT_INFORMATION 0x0100
+
+// GC_EVENT_ACTION
+// An IRC Style action event. Same as GC_EVENT_MESSAGE otherwise
+#define GC_EVENT_ACTION 0x0200
+
+// GC_EVENT_ADDSTATUS <pszText> enables '<pszStatus>' for <pszNick>
+// pszUID - Unique identifier
+// pszText - The one enabling the status for another user
+// pszStatus - The status given
+#define GC_EVENT_ADDSTATUS 0x0400
+
+// GC_EVENT_REMOVESTATUS <pszText> disables '<pszStatus>' for <pszNick>
+// pszUID - Unique identifier
+// pszText - The one disabling the status for another user
+// pszStatus - The status taken
+#define GC_EVENT_REMOVESTATUS 0x0800
+
+// GC_EVENT_CHID - not shown in the log
+// Change the unique identifier of a contact
+// pszUID - Unique identifier
+// pszText - The new unique identifier
+#define GC_EVENT_CHID 0x1000
+
+// GC_EVENT_CHID - not shown in the log
+// Change the name of a window
+// pszText - The new name
+#define GC_EVENT_CHWINNAME 0x1001
+
+// GC_EVENT_ADDGROUP - not shown in the log
+// Add a new status group to the user list
+// pszStatus - The new group name
+#define GC_EVENT_ADDGROUP 0x1002
+
+// GC_EVENT_SETITEMDATA GC_EVENT_SETITEMDATA - not shown in the log
+// Get or set the user defined data of a window
+// dwItemData - The itemdata to set or get
+#define GC_EVENT_SETITEMDATA 0x1003
+#define GC_EVENT_GETITEMDATA 0x1004
+
+// GC_EVENT_CONTROL - not shown in the log
+// Call WINDOW_INITDONE after the initial setup is done.
+// Also use it to control aspects of a window if needed .
+// No members of GCEVENT used, send one of the below flags in wParam instead
+#define WINDOW_INITDONE 1 //send when the window is joined and all users have ben added to the nicklist
+#define WINDOW_VISIBLE 2 //make the room visible (most likely you will never use this)
+#define WINDOW_HIDDEN 3 //make the room hidden (most likely you will never use this)
+#define WINDOW_MAXIMIZE 4 //make the room maximized (most likely you will never use this)
+#define WINDOW_MINIMIZE 5 //make the room minimized (most likely you will never use this)
+#define WINDOW_CLEARLOG 6 //clear the log of the room
+#define WINDOW_TERMINATE 7 //send to remove a window from chat.dll,
+#define WINDOW_OFFLINE 8 //send when the user leave the room
+#define WINDOW_ONLINE 9 //send when the user join the room
+
+#define GC_EVENT_CONTROL 0x1005
+
+// GC_EVENT_SETSBTEXT - not shown in the log
+// Set the text of the statusbar
+// pszText - text
+#define GC_EVENT_SETSBTEXT 0x1006
+
+// GC_EVENT_ACK - not shown in the log
+// Used to ack a outgoing message, when GC_ACKMSG is set
+// dwItemData - The itemdata
+#define GC_EVENT_ACK 0x1007
+
+// GC_EVENT_SENDMESSAGE - not shown in the log
+// Send a message from the window as if the user had typed it.
+// Used by IRC to broadcast /AME and /AMSG messages
+// pszText - The text
+#define GC_EVENT_SENDMESSAGE 0x1008
+
+typedef struct {
+ char *pszModule; //Name of the protocol (same as you registered with)
+ char *pszID; //Unique identifier of the room corresponding to the event, or NULL to broadcast to all rooms.
+ int iType; //Use GC_EVENT_* as defined above. Only one event per service call.
+} GCDEST;
+
+typedef struct {
+ int cbSize; // Set to sizeof();
+ GCDEST* pDest; // pointer to a GCDEST structure
+ const char *pszText; // Text, usage depends on type of event (see above), max 2048 characters
+ const char *pszNick; // Nick, usage depends on type of event (see above)
+ const char *pszUID; // Unique identifier, usage depends on type of event (see above)
+ const char *pszStatus; // Status, usage depends on type of event (see above)
+ const char *pszUserInfo; // Additional user information that is displayed in the log only for join, part, quit and nick
+ BOOL bIsMe; // Is this event related to the user?
+ BOOL bAddToLog; // Should this event be added to the message log
+ DWORD dwItemData; // User specified data
+ time_t time; // Time of the event
+ } GCEVENT;
+#define MS_GC_EVENT "GChat/NewEvent"
+
+
+
+
+//------------------------- HOOKS ------------------------
+/*
+ -- user interaction --
+ Hook this to receive notifications about user commands. The below flags will tell what sort of
+ user interaction is taking place and is set in iType of the GCDEST pointer member. The other
+ members of GCDEST will tell what protocol and chat room name it is.
+
+ wParam=0
+ lParam=(LPARAM)(GCEVENT *)pgch
+
+ Returning nonzero from your hook will stop other hooks from being called.
+*/
+#define GC_USER_MESSAGE 1 // user typed a message, with \n delimiting lines, valid members: pszText
+#define GC_USER_CHANMGR 2 // user clicked the chat room settings button
+#define GC_USER_LOGMENU 3 // user has chosen a message log menu item, valid members: dwData
+#define GC_USER_NICKLISTMENU 4 // user has chosen a user list menu item, valid members: dwData
+#define GC_USER_TYPNOTIFY 5 // user is typing
+#define GC_USER_PRIVMESS 6 // user wants to talk privately to user, valid members: pszText, pszUID
+#define GC_USER_TERMINATE 7 // a chat window is about to be closed, useful for freeing the Item data which is passed in dwData, valid members: dwData
+#define ME_GC_EVENT "GChat/OutgoingEvent"
+
+typedef struct {
+ GCDEST* pDest; // Same meaning as for MS_GC_EVENT
+ char * pszText; // Text
+ char * pszUID; // Unique identifier
+ DWORD dwData; // user data
+ } GCHOOK;
+
+
+/*
+ -- Build the pop up menus --
+ The user is activating a right click menu and the protocol should tell what
+ Items should be added to the menu. You should have a static array of struct gc_item's.
+ When the hook is fired the protocol should set nItems to the number of gc_item's
+ it want to add and then set Item to point to that array.
+
+ wParam=0
+ lParam=(LPARAM)(GCMENUITEM *)gcmi
+
+ Returning nonzero from your hook will stop other hooks from being called.
+
+*/
+
+#define MENU_NEWPOPUP 1 // add submenu
+#define MENU_POPUPITEM 2 // add item to current submenu
+#define MENU_POPUPSEPARATOR 3 // add separator to current submenu
+#define MENU_SEPARATOR 4 // add separator to menu
+#define MENU_ITEM 5 // add item
+struct gc_item {
+ char * pszDesc; // Textual description of the menu item to add
+ DWORD dwID; // must not be 0, must be unique. Will be returned via the above hook when the user click the item
+ int uType; // What kind of item is it?
+ BOOL bDisabled; // should the item be disabled
+ };
+
+#define MENU_ON_LOG 1 // pop up menu on the log
+#define MENU_ON_NICKLIST 2 // pop up menu on the user list
+typedef struct {
+ char * pszModule; // Set by chat.dll to the protocol name, do not change.
+ char * pszID; // The unique identifier of the window
+ char * pszUID; // The unique identifier of the user, if clicked in the user list
+ int Type; // MENU_ON_LOG or MENU_ON_USERLIST, what menu type is it?
+ int nItems; // set to number of items
+ struct gc_item* Item; // pointer to the first in the array of gc_item's
+ } GCMENUITEMS;
+#define ME_GC_BUILDMENU "GChat/BuildMenu"
+
diff --git a/miranda-wine/protocols/MSN/mmdecsjis.cpp b/miranda-wine/protocols/MSN/mmdecsjis.cpp
new file mode 100644
index 0000000..507c3b6
--- /dev/null
+++ b/miranda-wine/protocols/MSN/mmdecsjis.cpp
@@ -0,0 +1,489 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 <stdio.h>
+#include <string.h>
+
+#include "msn_global.h"
+
+int maybekanji(int c1, int c2);
+int rjis(char *t, char *s);
+unsigned short Jis2Sjis( unsigned short jis );
+void JIS2SJIS( char* text );
+//void JIStoSJIS( unsigned char knj1, unsigned char knj2 );
+void JIStoSJIS( unsigned char *knj1, unsigned char *knj2 );
+void jiskarasjis(char *trg, char *str);
+
+/*
+ * MIME decoding routines
+ *
+ * Written by S. Ichikawa,
+ * partially inspired by encdec.c of <jh@efd.lth.se>.
+ */
+#define BUFLEN 1024
+#define ESC (0x1b)
+
+
+#define ASCII 0x00
+#define EUC 0x01
+#define SJIS 0x02
+#define JIS 0x04
+#define JAPANESE 0xff
+
+
+static char mm64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" ;
+static char mmquote[] = "0123456789ABCDEF";
+static int mmcont = 0;
+
+void mmdec_base64( char *t, char *s)
+{
+ int d, count, j, val;
+ char buf[BUFLEN], *bp, nw[4], *p;
+
+ for (bp = buf; *s; s += 4)
+ {
+ val = 0;
+ if (s[2] == '=') count = 1;
+ else if (s[3] == '=') count = 2;
+ else count = 3;
+
+ for (j = 0; j <= count; j++)
+ {
+ if (!(p = strchr(mm64, s[j])))
+ return;
+
+ d = p - mm64;
+ d <<= (3-j)*6;
+ val += d;
+ }
+
+ for (j = 2; j >= 0; j--)
+ {
+ nw[j] = val & 255;
+ val >>= 8;
+ }
+ if (count--) *bp++ = nw[0];
+ if (count--) *bp++ = nw[1];
+ if (count) *bp++ = nw[2];
+ }
+ *bp = '\0';
+ strcpy(t, buf);
+}
+
+void mmdec_quote( char *t, char *s )
+{
+ char buf[BUFLEN], cval, *bp, *p;
+
+ for ( bp = buf; *s; )
+ {
+ if (*s == '=')
+ {
+ cval = 0;
+ if (s[1] && (p = strchr(mmquote, s[1])))
+ cval += (p - mmquote);
+ else
+ { *bp++ = *s++;
+ continue;
+ }
+
+ if (s[2] && (p = strchr(mmquote, s[2])))
+ {
+ cval <<= 4;
+ cval += (p - mmquote);
+ *bp++ = cval;
+ s += 3;
+ }
+ else *bp++ = *s++;
+ }
+ else if (*s == '_')
+ {
+ *bp++ = 0x20;
+ s++;
+ }
+ else *bp++ = *s++;
+ }
+
+ *bp = '\0';
+ strcpy( t, buf );
+}
+
+void mmdecode( char *trg, char *str )
+{
+ char buf[BUFLEN], mmbuf[BUFLEN];
+ char *s, *t, *u;
+ int base64, quote;
+ int jis = 0;
+ char *c;
+
+ buf[0] = '\0';
+
+ for (s = str, u = buf; *s; )
+ {
+ // if (!strnicmp(s, "=?ISO-2022-JP?B?", 16) || !strnicmp(s, "=?iso-2022-jp?B?", 16)) {
+ // if (!strncasecmp(s, "=?ISO-2022-JP?B?", 16)) {
+ if ( strstr(s, "=?") && strstr(s, "?B?" ))
+ base64 = 1;
+ else
+ base64 = 0;
+
+ // if (!strncasecmp(s, "=?ISO-2022-JP?Q?", 16)) {
+ // if (!strnicmp(s, "=?ISO-2022-JP?Q?", 16) || !strnicmp(s, "=?iso-2022-jp?Q?", 16)){
+ if ( strstr( s, "=?" ) && strstr( s, "?Q?" ))
+ quote = 1;
+ else
+ quote = 0;
+
+ if ( strstr(s, "ISO-2022-JP") || strstr( s, "iso-2022-jp" ))
+ jis = 1;
+ else
+ jis = 0;
+
+ if ( base64 || quote )
+ {
+ if ( mmcont )
+ {
+ for ( t = s - 1; t >= str && (*t == ' ' || *t == '\t'); t--)
+ u--;
+ }
+ if(quote) c = strstr(s,"?Q?");
+ if(base64) c = strstr(s,"?B?");
+
+ for (s = c+3, t = mmbuf; *s; )
+ {
+ if (s[0] == '?' && s[1] == '=')
+ break;
+
+ *t++ = *s++;
+ }
+
+ if ( s[0] != '?' || s[1] != '=' )
+ goto end;
+
+ s += 2;
+ *t = '\0';
+
+ if (base64) mmdec_base64(mmbuf, mmbuf);
+ if (quote) mmdec_quote(mmbuf, mmbuf);
+ for ( t = mmbuf; *t; )
+ *u++ = *t++;
+
+ mmcont = 1;
+ /* if (*s == ' ' || *s == '\t') *u++ = *s; */
+ /* for ( ; *s == ' ' || *s == '\t'; s++) ; */
+ }
+ else
+ {
+ if (*s != ' ' && *s != '\t') mmcont = 0;
+ *u++ = *s++;
+ } }
+
+ *u = '\0';
+end:
+ if ( jis )
+ jiskarasjis( buf, buf ); // japanese jis code to shift-jis code
+ strcpy( trg, buf );
+}
+
+void jiskarasjis( char *trg, char *str )
+{
+ char buf[BUFLEN];
+
+ strcpy(buf,str);
+ rjis(buf, buf);
+
+ JIS2SJIS(buf);
+
+ strcpy(trg, buf);
+}
+
+/*
+ * Insert ESC where it seems lost.
+ * (The author of this function "rjis" is S. Ichikawa.)
+ */
+
+int rjis( char *t, char *s )
+{
+ char *p, buf[BUFLEN];
+ int kanji = 0;
+
+ if (strchr(s, ESC) || !strchr(s, '$'))
+ {
+ if (s != t) strcpy(t, s);
+ return 1;
+ }
+
+ for (p = buf; *s; )
+ {
+ if (!kanji && s[0] == '$' && (s[1] == '@' || s[1] == 'B'))
+ {
+ if (maybekanji((int)s[2], (int)s[3]))
+ {
+ kanji = 1;
+ *p++ = ESC;
+ *p++ = *s++;
+ *p++ = *s++;
+ *p++ = *s++;
+ *p++ = *s++;
+ continue;
+ }
+ *p++ = *s++;
+ continue;
+ }
+ if (kanji && s[0] == '(' && (s[1] == 'J' || s[1] == 'B'))
+ {
+ kanji = 0;
+ *p++ = ESC;
+ *p++ = *s++;
+ *p++ = *s++;
+ continue;
+ }
+ *p++ = *s++;
+ }
+ *p = *s; /* terminate string */
+
+ strcpy(t, buf);
+ return 0;
+}
+
+/*
+ * The following function "maybekanji" is derived from
+ * RJIS-1.0 by Mr. Hironobu Takahashi.
+ * Maybekanji() is included here under the courtesy of the author.
+ * The original comment of rjis.c is also included here.
+ */
+
+/*
+ * RJIS ( Recover JIS code from broken file )
+ * Copyright (C) 1992 1994
+ * Hironobu Takahashi (takahasi@tiny.or.jp)
+ *
+ * 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 versions 2, 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 SKK, see the file COPYING. If not, write to the Free
+ * Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+int maybekanji( int c1, int c2 )
+{
+ if ((c2 < 33) || (c2 > 126)) return 0;
+ if ((c1 < 33) || ((40 < c1) && (c1 < 48)) || (116 < c1)) return 0;
+ c2 -= 32;
+ switch(c1-32) {
+ case 2:
+ if ((14 < c2) && ( c2 < 26)) return 0;
+ if ((33 < c2) && ( c2 < 42)) return 0;
+ if ((48 < c2) && ( c2 < 60)) return 0;
+ if ((74 < c2) && ( c2 < 82)) return 0;
+ if ((89 < c2) && ( c2 < 94)) return 0;
+ break;
+ case 3:
+ if (c2 < 16) return 0;
+ if ((25 < c2) && ( c2 < 33)) return 0;
+ if ((58 < c2) && ( c2 < 65)) return 0;
+ if (90 < c2) return 0;
+ break;
+ case 4:
+ if (83 < c2) return 0;
+ break;
+ case 5:
+ if (86 < c2) return 0;
+ break;
+ case 6:
+ if ((24 < c2) && ( c2 < 33)) return 0;
+ if (56 < c2) return 0;
+ break;
+ case 7:
+ if ((33 < c2) && ( c2 < 49)) return 0;
+ if (81 < c2) return 0;
+ break;
+ case 8:
+ if (32 < c2) return 0;
+ break;
+ case 47:
+ if (51 < c2) return 0;
+ break;
+ case 84:
+ if (6 < c2) return 0;
+ break;
+ }
+ return 1;
+}
+
+unsigned int jis2sjis(unsigned int jis)
+{
+ unsigned int hib, lob;
+
+ hib = (jis >> 8) & 0xff;
+ lob = jis & 0xff;
+ lob += (hib & 1) ? 0x1f : 0x7d;
+ if (lob >= 0x7f) lob++;
+ hib = ((hib - 0x21) >> 1) + 0x81;
+ if (hib > 0x9f) hib += 0x40;
+
+ return (hib << 8) | lob;
+}
+
+static void rint2hexsz(char *str, int num, int *off)
+{
+ int k, n;
+
+ if ((k = num >> 4) != 0)
+ rint2hexsz(str, k, off);
+
+ n = num & 0xf;
+ *(str + *off) = n <= 9 ? n + '0' : n - 10 + 'A';
+ (*off)++;
+}
+
+void int2hexsz(char *str, int num)
+{
+ int i;
+
+ i = 0;
+ if (num < 0) {
+ num = -num;
+ *str = '-';
+ i++;
+ }
+ rint2hexsz(str, num, &i);
+ *(str + i) = '\0';
+}
+
+int hexsz2int(char *str)
+{
+ int val;
+ int sign;
+
+ while (*str == ' ' || *str == '\t') str++;
+ sign = 1;
+ if (*str == '+') str++;
+ else if (*str == '-') {
+ sign = -1;
+ str++;
+ }
+ val = 0;
+ while (*str >= '0' && *str <= '9' ||
+ *str >= 'A' && *str <= 'F' ||
+ *str >= 'a' && *str <= 'f') {
+ val <<= 4;
+ if (*str >= '0' && *str <= '9') val += *str - '0';
+ else if (*str >= 'A' && *str <= 'F') val += *str - 'A' + 10;
+ else val += *str - 'a' + 10;
+ str++;
+ }
+
+ return sign == 1 ? val : -val;
+}
+
+unsigned short Jis2Sjis( unsigned short jis )
+{
+ unsigned short ubyte, lbyte;
+
+ ubyte = jis >> 8;
+ lbyte = jis & 0x00ff;
+
+ lbyte += 0x1f;
+ if ( lbyte >= 0x7f ) lbyte++;
+ if ( lbyte <= 0x3f ) return 0;
+
+ if ( (ubyte & 0x0001) == 0 )
+ {
+ lbyte = jis & 0x00ff;
+ lbyte += 0x7e;
+ ubyte--;
+ if ( lbyte > 0xfd ) return 0;
+ }
+
+ ubyte -= 0x1f;
+ ubyte = ubyte >> 1;
+ ubyte += 0x80;
+ if ( ubyte >= 0xa0 ) ubyte += 0x40;
+
+ if ( ((ubyte >= 0x81) && (ubyte <= 0x9f)) || ((ubyte >= 0xe0) && (ubyte <= 0xef)) )
+ return (ubyte << 8) + lbyte;
+
+ return 0;
+}
+
+//---- JISʸ»ú¤òSJISʸ»ú¤ËÊÑ´¹¤¹¤ë´Ø¿ô
+//inline
+void JIStoSJIS(unsigned char *knj1, unsigned char *knj2 )
+{
+ if( *knj1 & 0x01 ){
+ *knj1 >>= 1;
+ if( *knj1 < 0x2F ) *knj1 += 0x71; else *knj1 -= 0x4F;
+ if( *knj2 > 0x5F ) *knj2 += 0x20; else *knj2 += 0x1F;
+ }else{
+ *knj1 >>= 1;
+ if( *knj1 < 0x2F ) *knj1 += 0x70; else *knj1 -= 0x50;
+ *knj2 += 0x7E;
+ }
+}
+
+
+
+void JIS2SJIS( char* text ) {
+ int mode = ASCII;
+
+ unsigned char *wr, *re;
+ for( wr=re=(unsigned char*)text; *re; re++ ){
+ if( (re[0]=='\x1b' && re[1]=='$' && re[2] == 'B' ) ||
+ (re[0]=='\x1b' && re[1]=='$' && re[2] == '@' ) ){
+ re+=2;
+ mode = JAPANESE;
+ continue;
+ }else if( (re[0]=='\x0f') ||
+ (re[0]=='\x1b' && re[1]=='(' && re[2] == 'B' ) ||
+ (re[0]=='\x1b' && re[1]=='(' && re[2] == 'J' ) ){
+ re+=2;
+ mode = ASCII;
+ continue;
+ }else if( (re[0]=='\x0e') ||
+ (re[0]=='\x1b' && re[1]=='(' && re[2] == 'I' ) ){
+ re+=2;
+ mode = ASCII; // hankaku IGNORE
+ continue;
+ }
+
+ if( mode == ASCII ){
+ *wr++ = *re;
+ continue;
+ }
+ *wr++ = *re;
+ if( !(*wr = *++re) ) break;
+// JIStoSJIS( *(wr-1), *wr );
+ JIStoSJIS( (wr-1), wr );
+ wr++;
+ }
+ *wr='\0';
+}
diff --git a/miranda-wine/protocols/MSN/msn.cpp b/miranda-wine/protocols/MSN/msn.cpp
new file mode 100644
index 0000000..1281add
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn.cpp
@@ -0,0 +1,407 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+#include "version.h"
+
+#pragma comment( lib, "shlwapi.lib" )
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+struct MM_INTERFACE memoryManagerInterface;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Initialization routines
+int MsnOnDetailsInit( WPARAM, LPARAM );
+
+int LoadMsnServices( void );
+void UnloadMsnServices( void );
+void MsgQueue_Init( void );
+void MsgQueue_Uninit( void );
+void Lists_Init( void );
+void Lists_Uninit( void );
+void P2pSessions_Uninit( void );
+void P2pSessions_Init( void );
+void Threads_Uninit( void );
+int MsnOptInit( WPARAM wParam, LPARAM lParam );
+void UninitSsl( void );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+int uniqueEventId = 0;
+int msnSearchID = -1;
+char* msnExternalIP = NULL;
+char* msnPreviousUUX = NULL;
+HANDLE msnMainThread;
+int msnOtherContactsBlocked = 0;
+HANDLE hHookOnUserInfoInit = NULL;
+HANDLE hGroupAddEvent = NULL;
+HANDLE hMSNNudge = NULL;
+bool msnHaveChatDll = false;
+
+MYOPTIONS MyOptions;
+
+MSN_StatusMessage msnModeMsgs[ MSN_NUM_MODES ] = {
+ { ID_STATUS_ONLINE, NULL },
+ { ID_STATUS_AWAY, NULL },
+ { ID_STATUS_NA, NULL },
+ { ID_STATUS_DND, NULL },
+ { ID_STATUS_OCCUPIED, NULL },
+ { ID_STATUS_ONTHEPHONE, NULL },
+ { ID_STATUS_OUTTOLUNCH, NULL } };
+
+char* msnProtocolName = NULL;
+char* msnProtChallenge = NULL;
+char* msnProductID = NULL;
+
+char* mailsoundname;
+char* ModuleName;
+
+PLUGININFO pluginInfo =
+{
+ sizeof(PLUGININFO),
+ #if defined( _UNICODE )
+ "MSN Protocol (Unicode)",
+ #else
+ "MSN Protocol",
+ #endif
+ __VERSION_DWORD,
+ "Adds support for communicating with users of the MSN Messenger network",
+ "George Hazan",
+ "george_hazan@hotmail.com",
+ "© 2001-5 Richard Hughes, George Hazan",
+ "http://miranda-im.org/download/details.php?action=viewfile&id=702",
+ 0, 0
+};
+
+bool volatile msnLoggedIn = false;
+ThreadData* volatile msnNsThread = NULL;
+
+int msnStatusMode,
+ msnDesiredStatus;
+HANDLE msnMenuItems[ MENU_ITEMS_COUNT ];
+HANDLE hNetlibUser = NULL;
+HANDLE hInitChat = NULL;
+HANDLE hEvInitChat = NULL;
+bool msnUseExtendedPopups;
+
+int MsnOnDetailsInit( WPARAM wParam, LPARAM lParam );
+
+int MSN_GCEventHook( WPARAM wParam, LPARAM lParam );
+int MSN_GCMenuHook( WPARAM wParam, LPARAM lParam );
+int MSN_ChatInit( WPARAM wParam, LPARAM lParam );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Main DLL function
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
+{
+ hInst = hinstDLL;
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnModulesLoaded - finalizes plugin's configuration on load
+
+int msn_httpGatewayInit(HANDLE hConn,NETLIBOPENCONNECTION *nloc,NETLIBHTTPREQUEST *nlhr);
+int msn_httpGatewayBegin(HANDLE hConn,NETLIBOPENCONNECTION *nloc);
+int msn_httpGatewayWrapSend(HANDLE hConn,PBYTE buf,int len,int flags,MIRANDASERVICE pfnNetlibSend);
+PBYTE msn_httpGatewayUnwrapRecv(NETLIBHTTPREQUEST *nlhr,PBYTE buf,int len,int *outBufLen,void *(*NetlibRealloc)(void*,size_t));
+
+static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+static HANDLE hChatEvent = NULL, hChatMenu = NULL;
+
+static int OnModulesLoaded( WPARAM wParam, LPARAM lParam )
+{
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( NULL, TranslateT( "This plugin requires db3x plugin version 0.5.1.0 or later" ), _T("MSN"), MB_OK );
+ return 1;
+ }
+
+ char szBuffer[ MAX_PATH ];
+
+ if ( MSN_GetStaticString( "MsnPassportHost", NULL, szBuffer, sizeof szBuffer ))
+ MSN_SetString( NULL, "MsnPassportHost", "https://loginnet.passport.com/login2.srf" );
+
+ WORD wPort = MSN_GetWord( NULL, "YourPort", 0xFFFF );
+ if ( wPort != 0xFFFF ) {
+ MSN_SetByte( "NLSpecifyIncomingPorts", 1 );
+
+ ltoa( wPort, szBuffer, 10 );
+ MSN_SetString( NULL, "NLIncomingPorts", szBuffer );
+
+ DBDeleteContactSetting( NULL, msnProtocolName, "YourPort" );
+ }
+
+ mir_snprintf( szBuffer, sizeof szBuffer, "%s plugin connections", msnProtocolName );
+
+ NETLIBUSER nlu = {0};
+ nlu.cbSize = sizeof( nlu );
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.szSettingsModule = msnProtocolName;
+ nlu.szDescriptiveName = MSN_Translate( szBuffer );
+
+ if ( MyOptions.UseGateway ) {
+ nlu.flags |= NUF_HTTPGATEWAY;
+ nlu.szHttpGatewayUserAgent = MSN_USER_AGENT;
+ nlu.pfnHttpGatewayInit = msn_httpGatewayInit;
+ nlu.pfnHttpGatewayWrapSend = msn_httpGatewayWrapSend;
+ nlu.pfnHttpGatewayUnwrapRecv = msn_httpGatewayUnwrapRecv;
+ }
+
+ hNetlibUser = ( HANDLE )MSN_CallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu );
+
+ if ( MSN_GetByte( "UseIeProxy", 0 )) {
+ NETLIBUSERSETTINGS nls = { 0 };
+ nls.cbSize = sizeof( nls );
+ MSN_CallService(MS_NETLIB_GETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+
+ HKEY hSettings;
+ if ( RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &hSettings ))
+ return 0;
+
+ char tValue[ 256 ];
+ DWORD tType = REG_SZ, tValueLen = sizeof( tValue );
+ int tResult = RegQueryValueExA( hSettings, "ProxyServer", NULL, &tType, ( BYTE* )tValue, &tValueLen );
+ RegCloseKey( hSettings );
+
+ if ( !tResult )
+ {
+ char* tDelim = strstr( tValue, "http=" );
+ if ( tDelim != 0 ) {
+ strdel( tValue, int( tDelim - tValue )+5 );
+
+ tDelim = strchr( tValue, ';' );
+ if ( tDelim != NULL )
+ *tDelim = '\0';
+ }
+
+ tDelim = strchr( tValue, ':' );
+ if ( tDelim != NULL ) {
+ *tDelim = 0;
+ nls.wProxyPort = atol( tDelim+1 );
+ }
+
+ rtrim( tValue );
+ nls.szProxyServer = tValue;
+ MyOptions.UseProxy = nls.useProxy = tValue[0] != 0;
+ nls.proxyType = PROXYTYPE_HTTP;
+ nls.szIncomingPorts = NEWSTR_ALLOCA(nls.szIncomingPorts);
+ nls.szOutgoingPorts = NEWSTR_ALLOCA(nls.szOutgoingPorts);
+ nls.szProxyAuthPassword = NEWSTR_ALLOCA(nls.szProxyAuthPassword);
+ nls.szProxyAuthUser = NEWSTR_ALLOCA(nls.szProxyAuthUser);
+ MSN_CallService(MS_NETLIB_SETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ } }
+
+ if ( ServiceExists( MS_GC_REGISTER )) {
+ msnHaveChatDll = true;
+
+ GCREGISTER gcr = {0};
+ gcr.cbSize = sizeof( GCREGISTER );
+ gcr.dwFlags = GC_TYPNOTIF|GC_CHANMGR;
+ gcr.iMaxText = 0;
+ gcr.nColors = 16;
+ gcr.pColors = &crCols[0];
+ gcr.pszModuleDispName = msnProtocolName;
+ gcr.pszModule = msnProtocolName;
+ MSN_CallService( MS_GC_REGISTER, NULL, ( LPARAM )&gcr );
+
+ hChatEvent = HookEvent( ME_GC_EVENT, MSN_GCEventHook );
+ hChatMenu = HookEvent( ME_GC_BUILDMENU, MSN_GCMenuHook );
+
+ char szEvent[ 200 ];
+ mir_snprintf( szEvent, sizeof szEvent, "%s\\ChatInit", msnProtocolName );
+ hInitChat = CreateHookableEvent( szEvent );
+ hEvInitChat = HookEvent( szEvent, MSN_ChatInit );
+ }
+
+ msnUseExtendedPopups = ServiceExists( MS_POPUP_ADDPOPUPEX ) != 0;
+ hHookOnUserInfoInit = HookEvent( ME_USERINFO_INITIALISE, MsnOnDetailsInit );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnPreShutdown - prepare a global Miranda shutdown
+
+extern HANDLE hKeepAliveThreadEvt;
+
+static int OnPreShutdown( WPARAM wParam, LPARAM lParam )
+{
+ if ( hKeepAliveThreadEvt != NULL )
+ SetEvent( hKeepAliveThreadEvt );
+
+ MSN_CloseThreads();
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Performs a primary set of actions upon plugin loading
+
+extern "C" int __declspec(dllexport) Load( PLUGINLINK* link )
+{
+ pluginLink = link;
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &msnMainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+
+ // get the internal malloc/free()
+ memset(&memoryManagerInterface, 0, sizeof(memoryManagerInterface));
+ memoryManagerInterface.cbSize = sizeof(memoryManagerInterface);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM) &memoryManagerInterface);
+
+ char path[MAX_PATH];
+ char* protocolname;
+ char* fend;
+
+ GetModuleFileNameA( hInst, path, sizeof( path ));
+
+ protocolname = strrchr(path,'\\');
+ protocolname++;
+ fend = strrchr(path,'.');
+ *fend = '\0';
+ CharUpperA( protocolname );
+ msnProtocolName = strdup( protocolname );
+
+ mir_snprintf( path, sizeof( path ), "%s:HotmailNotify", protocolname );
+ ModuleName = strdup( path );
+
+ mir_snprintf( path, sizeof( path ), "%s/Status", protocolname );
+ MSN_CallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )path );
+
+// Uninstalling purposes
+// if (ServiceExists("PluginSweeper/Add"))
+// MSN_CallService("PluginSweeper/Add",(WPARAM)MSN_Translate(ModuleName),(LPARAM)ModuleName);
+
+ HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded );
+
+ srand(( unsigned int )time( NULL ));
+
+ LoadOptions();
+ HookEvent( ME_OPT_INITIALISE, MsnOptInit );
+ HookEvent( ME_SYSTEM_PRESHUTDOWN, OnPreShutdown );
+
+ char nudge[250];
+ sprintf(nudge,"%s/Nudge",protocolname);
+ hMSNNudge = CreateHookableEvent(nudge);
+
+ MSN_InitThreads();
+
+ PROTOCOLDESCRIPTOR pd;
+ memset( &pd, 0, sizeof( pd ));
+ pd.cbSize = sizeof( pd );
+ pd.szName = msnProtocolName;
+ pd.type = PROTOTYPE_PROTOCOL;
+ MSN_CallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd );
+
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA( msnProtocolName, ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 )))
+ MSN_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+ char mailsoundtemp[ 64 ];
+ strcpy( mailsoundtemp, protocolname );
+ strcat( mailsoundtemp, ": " );
+ strcat( mailsoundtemp, MSN_Translate( "Hotmail" ));
+ mailsoundname = strdup( mailsoundtemp );
+ SkinAddNewSound( mailsoundtemp, mailsoundtemp, "hotmail.wav" );
+
+ msnStatusMode = msnDesiredStatus = ID_STATUS_OFFLINE;
+ msnLoggedIn = false;
+ LoadMsnServices();
+ Lists_Init();
+ MsgQueue_Init();
+ P2pSessions_Init();
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unload a plugin
+
+extern char* rru;
+extern char* profileURL;
+
+extern "C" int __declspec( dllexport ) Unload( void )
+{
+ if ( msnLoggedIn )
+ msnNsThread->sendPacket( "OUT", NULL );
+
+ if ( hHookOnUserInfoInit )
+ UnhookEvent( hHookOnUserInfoInit );
+
+ if ( hChatEvent ) UnhookEvent( hChatEvent );
+ if ( hChatMenu ) UnhookEvent( hChatMenu );
+ if ( hEvInitChat ) UnhookEvent( hEvInitChat );
+
+ if ( hInitChat )
+ DestroyHookableEvent( hInitChat );
+
+ if ( hMSNNudge )
+ DestroyHookableEvent( hMSNNudge );
+
+ UninitSsl();
+ MSN_FreeGroups();
+ Threads_Uninit();
+ MsgQueue_Uninit();
+ Lists_Uninit();
+ P2pSessions_Uninit();
+ Netlib_CloseHandle( hNetlibUser );
+
+ UnloadMsnServices();
+
+ free( mailsoundname );
+ free( msnProtocolName );
+ free( ModuleName );
+
+ CloseHandle( msnMainThread );
+
+ for ( int i=0; i < MSN_NUM_MODES; i++ )
+ if ( msnModeMsgs[ i ].m_msg )
+ free( msnModeMsgs[ i ].m_msg );
+
+ if ( kv ) free( kv );
+ if ( sid ) free( sid );
+ if ( passport ) free( passport );
+ if ( MSPAuth ) free( MSPAuth );
+ if ( rru ) free( rru );
+ if ( profileURL ) free( profileURL );
+
+ if ( msnPreviousUUX ) free( msnPreviousUUX );
+ if ( msnExternalIP ) free( msnExternalIP );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MirandaPluginInfo - returns an information about a plugin
+
+extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
+{
+ if ( mirandaVersion < PLUGIN_MAKE_VERSION( 0, 6, 0, 0 )) {
+ MessageBox( NULL, _T("The MSN protocol plugin cannot be loaded. It requires Miranda IM 0.6.0 or later."), _T("MSN Protocol Plugin"), MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST );
+ return NULL;
+ }
+
+ return &pluginInfo;
+}
diff --git a/miranda-wine/protocols/MSN/msn.rc b/miranda-wine/protocols/MSN/msn.rc
new file mode 100644
index 0000000..06d391b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn.rc
@@ -0,0 +1,348 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_MSNMAIN DIALOGEX 0, 0, 312, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_OPTIONSTAB,"SysTabControl32",WS_TABSTOP,1,1,310,245,WS_EX_ACCEPTFILES
+END
+
+IDD_SETAVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN,9,11,96,96
+ PUSHBUTTON "Set",IDC_SETAVATAR,9,112,45,13
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,61,112,41,13
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_SETAVATAR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 107
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_MSN DIALOGEX 0, 0, 304, 207
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "MSN",IDC_STMSNGROUP,4,0,298,84,WS_GROUP
+ RTEXT "Full e-mail:",IDC_STATIC,16,20,52,8
+ EDITTEXT IDC_HANDLE,72,18,100,12,ES_AUTOHSCROLL
+ RTEXT "Password:",IDC_STATIC,16,36,52,8
+ EDITTEXT IDC_PASSWORD,72,34,100,12,ES_PASSWORD | ES_AUTOHSCROLL
+ RTEXT "Nickname:",IDC_STATIC,16,52,52,8
+ EDITTEXT IDC_HANDLE2,72,50,100,12,ES_AUTOHSCROLL
+ CONTROL "Create a new MSN messenger account using the MSN website",IDC_NEWMSNACCOUNTLINK,
+ "Hyperlink",WS_TABSTOP,21,68,208,8
+ GROUPBOX "Expert",IDC_STATIC,4,84,298,119,WS_GROUP
+ CONTROL "Disable main menu",IDC_DISABLE_MAIN_MENU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,96,288,10
+ CONTROL "Send message font color/size info inside messages",IDC_SENDFONTINFO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,107,288,10
+ CONTROL "Disable all contacts not included into my contact list",IDC_DISABLE_ANOTHER_CONTACTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,118,288,10
+ CONTROL "Never update your nickname from server",IDC_USE_OWN_NICKNAME,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,129,288,10
+ CONTROL "Treat Away status as 'Be Right Back'",IDC_AWAY_AS_BRB,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,140,288,10
+ CONTROL "Manage server groups",IDC_MANAGEGROUPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,151,288,10
+ CONTROL "Run the following application when new Hotmail is arrived",IDC_RUN_APP_ON_HOTMAIL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,173,288,10
+ EDITTEXT IDC_MAILER_APP,23,184,161,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_ENTER_MAILER_APP,189,184,15,12
+ CONTROL "Enable avatars",IDC_ENABLE_AVATARS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,162,288,10
+END
+
+IDD_OPT_MSN_CONN DIALOGEX 0, 0, 304, 175
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Connection settings",IDC_STATIC,4,0,298,120
+ LTEXT "Login server:",IDC_STATIC,16,18,44,8
+ EDITTEXT IDC_LOGINSERVER,68,16,168,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC,16,32,48,8
+ EDITTEXT IDC_MSNPORT,68,30,44,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Use HTTP gateway mode (incompatible with MSN Gateway plugin)",IDC_USEGATEWAY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,46,264,8
+ CONTROL "Use IE proxy settings",IDC_USEIEPROXY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,58,264,8
+ CONTROL "Keep connection alive (send a ping packet every minute)",IDC_KEEPALIVE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,70,264,8
+ CONTROL "Notify me when a message delivery has failed",IDC_SLOWSEND,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,82,263,8
+ CONTROL "Use MSN Messenger 7 protocol",IDC_USEMSNP11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,94,262,8
+ CONTROL "Use OpenSSL encryption (requires LIBSSL32.DLL)",IDC_USEOPENSSL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,106,263,8
+ GROUPBOX "Incoming file transfers",IDC_STATIC,4,124,298,48
+ CONTROL "Automatically obtain host/port for incoming file transfers",IDC_AUTOGETHOST,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,136,264,10
+ LTEXT "Your host (or router):",IDC_STATIC,12,152,72,8
+ EDITTEXT IDC_YOURHOST,90,151,184,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Reset",IDC_RESETSERVER,244,16,34,12
+END
+
+IDD_LISTSMGR DIALOGEX 0, 0, 304, 228
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Server List Manager",IDC_STATIC,4,0,298,224
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x190,9,12,287,180,WS_EX_CLIENTEDGE
+ ICON IDI_LIST_FL,IDC_ICON_FL,10,196,21,20,SS_REALSIZEIMAGE
+ LTEXT "Contact is included into your server list",IDC_STATIC,28,196,144,8
+ ICON IDI_LIST_AL,IDC_ICON_AL,187,196,21,20,SS_REALSIZEIMAGE
+ LTEXT "Somebody included you in his/her server list",IDC_STATIC,28,208,144,8
+ ICON IDI_LIST_BL,IDC_ICON_BL,187,208,21,20,SS_REALSIZEIMAGE
+ LTEXT "Allowed (active) contact",IDC_STATIC,204,196,82,8
+ ICON IDI_LIST_RL,IDC_ICON_RL,10,208,21,20,SS_REALSIZEIMAGE
+ LTEXT "Blocked contact",IDC_STATIC,204,208,82,8
+END
+
+IDD_HOTMAIL_OPT_POPUP DIALOGEX 0, 0, 238, 220
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Colours",IDC_STATIC,4,0,232,59
+ CONTROL "",IDC_BGCOLOUR,"ColourPicker",WS_TABSTOP,12,12,39,12
+ LTEXT "Background colour",IDC_STATIC,56,14,176,8,SS_CENTERIMAGE
+ CONTROL "",IDC_TEXTCOLOUR,"ColourPicker",WS_TABSTOP,12,28,39,12
+ LTEXT "Text colour",IDC_STATIC,56,30,176,8,SS_CENTERIMAGE
+ CONTROL "&Use Windows colours",IDC_USEWINCOLORS,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | BS_FLAT | WS_TABSTOP,12,44,220,8
+ GROUPBOX "Hotmail",IDC_STATIC,4,61,232,59
+ CONTROL "Disable receiving Hotmail notifications",IDC_DISABLEHOTMAIL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,72,220,10
+ CONTROL "Ignore new messages in 'Junk Mail' folder only (at startup)",IDC_DISABLEHOTJUNK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,84,202,10
+ LTEXT "Timeout (*)",IDC_STATIC,12,102,52,8
+ EDITTEXT IDC_POPUP_TIMEOUT,72,100,24,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "sec.",IDC_STATIC,100,102,30,8
+ DEFPUSHBUTTON "Previe&w",IDC_PREVIEW,176,100,52,12
+ GROUPBOX "Other",IDC_STATIC,3,122,232,81
+ CONTROL "Display popups when user is typing",IDC_NOTIFY_USERTYPE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,135,216,10
+ CONTROL "Display errors using popups",IDC_ERRORS_USING_POPUPS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,147,216,10
+ CONTROL "Enable 'First message delivered' popup",IDC_NOTIFY_FIRSTMSG,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,159,216,10
+ LTEXT "Timeout (*)",IDC_STATIC,10,186,60,8
+ EDITTEXT IDC_POPUP_TIMEOUT2,70,183,24,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "sec.",IDC_STATIC,98,186,30,8
+ DEFPUSHBUTTON "Previe&w",IDC_PREVIEW2,174,183,52,12
+ LTEXT "(*) Timeouts require Popup v. 1.0.1.9 or later",IDC_STATIC,4,207,232,8
+ CONTROL "Enable 'User left channel' popup",IDC_NOTIFY_ENDSESSION,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,172,218,8
+END
+
+IDD_SETNICKNAME DIALOGEX 0, 0, 187, 42
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Set Nickname"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_NICKNAME,5,5,177,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,36,23,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,23,50,14
+END
+
+IDD_USEROPTS DIALOGEX 0, 0, 224, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Avatar",IDC_STATIC,8,8,100,10
+ CONTROL "",IDC_MSN_PICT,"Static",SS_BITMAP,8,18,64,64
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME | SS_SUNKEN,8,18,64,60
+ LTEXT "Running on a mobile device",IDC_STATIC,8,82,100,8
+ LTEXT "",IDC_MOBILE,108,82,10,8
+ LTEXT "Running on a MSN mobile device",IDC_STATIC,8,92,100,8
+ LTEXT "",IDC_MSN_MOBILE,108,92,10,8
+ LTEXT "Using MSN Webmessenger",IDC_STATIC,8,102,100,8
+ LTEXT "",IDC_WEBMESSENGER,108,102,10,8
+END
+
+IDD_GET_PNG2DIB DIALOGEX 0, 0, 276, 101
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "png2lib download"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "To enable the avatar support, you must obtain the valid copy of the png2dib.dll. Choose one of the following:",IDC_STATIC,8,8,256,16
+ LTEXT "[Install] - install a png2lib plugin using Miranda Installer",IDC_STATIC,16,32,248,8
+ LTEXT "[Download] - manually download a zipped DLL and then unzip it to the plugins folder",IDC_STATIC,16,44,248,16
+ LTEXT "[Cancel] - disable the avatar support",IDC_STATIC,16,64,248,8
+ PUSHBUTTON "Install",IDC_BTN_INSTALL,37,80,68,16
+ PUSHBUTTON "Download",IDC_BTN_DOWNLOAD,113,80,60,16
+ PUSHBUTTON "Cancel",IDC_BTN_CANCEL,181,80,56,16
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT_MSN, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 304
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 202
+ END
+
+ IDD_OPT_MSN_CONN, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 163
+ END
+
+ IDD_HOTMAIL_OPT_POPUP, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 236
+ END
+
+ IDD_SETNICKNAME, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 37
+ END
+
+ IDD_LISTSMGR, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 308
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 240
+ END
+
+ IDD_OPT_MSN_EXTRAS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 303
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 202
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MSN ICON "Icos\\msn.ico"
+IDI_LIST_FL ICON "Icos\\list_fl.ico"
+IDI_LIST_AL ICON "Icos\\list_al.ico"
+IDI_LIST_BL ICON "Icos\\list_bl.ico"
+IDI_LIST_RL ICON "Icos\\list_rl.ico"
+IDI_MSNBLOCK ICON "Icos\\msnblock.ico"
+IDI_INBOX ICON "Icos\\inbox.ico"
+IDI_INVITE ICON "Icos\\invite.ico"
+IDI_PROFILE ICON "Icos\\profile.ico"
+IDI_NETMEETING ICON "Icos\\netmeeting.ico"
+IDI_SERVICES ICON "Icos\\services.ico"
+IDI_AVATAR ICON "Icos\\avatar.ico"
+IDI_NUDGE ICON "Icos\\nudge.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <windows.h>\r\n"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/protocols/MSN/msn_bitmap.cpp b/miranda-wine/protocols/MSN/msn_bitmap.cpp
new file mode 100644
index 0000000..fccb6c6
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_bitmap.cpp
@@ -0,0 +1,213 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include "sha1.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_BitmapToAvatarDibBits - rescales a bitmap to 96x96 pixels and creates a DIB from it
+
+HBITMAP __stdcall MSN_StretchBitmap( HBITMAP hBitmap )
+{
+ BITMAPINFO bmStretch = { 0 };
+ bmStretch.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmStretch.bmiHeader.biWidth = 96;
+ bmStretch.bmiHeader.biHeight = 96;
+ bmStretch.bmiHeader.biPlanes = 1;
+ bmStretch.bmiHeader.biBitCount = 32;
+
+ UINT* ptPixels;
+ HBITMAP hStretchedBitmap = CreateDIBSection( NULL, &bmStretch, DIB_RGB_COLORS, ( void** )&ptPixels, NULL, 0);
+ if ( hStretchedBitmap == NULL ) {
+ MSN_DebugLog( "Bitmap creation failed with error %d", GetLastError() );
+ return NULL;
+ }
+
+ BITMAP bmp;
+ HDC hDC = CreateCompatibleDC( NULL );
+ HBITMAP hOldBitmap1 = ( HBITMAP )SelectObject( hDC, hBitmap );
+ GetObject( hBitmap, sizeof( BITMAP ), &bmp );
+
+ HDC hBmpDC = CreateCompatibleDC( hDC );
+ HBITMAP hOldBitmap2 = ( HBITMAP )SelectObject( hBmpDC, hStretchedBitmap );
+ int side, dx, dy;
+
+ if ( bmp.bmWidth > bmp.bmHeight ) {
+ side = bmp.bmHeight;
+ dx = ( bmp.bmWidth - bmp.bmHeight )/2;
+ dy = 0;
+ }
+ else {
+ side = bmp.bmWidth;
+ dx = 0;
+ dy = ( bmp.bmHeight - bmp.bmWidth )/2;
+ }
+
+ SetStretchBltMode( hBmpDC, HALFTONE );
+ StretchBlt( hBmpDC, 0, 0, 96, 96, hDC, dx, dy, side, side, SRCCOPY );
+
+ SelectObject( hDC, hOldBitmap1 );
+ DeleteObject( hBitmap );
+ DeleteDC( hDC );
+
+ SelectObject( hBmpDC, hOldBitmap2 );
+ DeleteDC( hBmpDC );
+ return hStretchedBitmap;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SaveBitmapAsAvatar - updates the avatar database settins and file from a bitmap
+
+int __stdcall MSN_SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName )
+{
+ if ( !MSN_LoadPngModule())
+ return 1;
+
+ HDC hdc = CreateCompatibleDC( NULL );
+ HBITMAP hOldBitmap = ( HBITMAP )SelectObject( hdc, hBitmap );
+
+ BITMAPINFO* bmi = ( BITMAPINFO* )alloca( sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 );
+ memset( bmi, 0, sizeof( BITMAPINFO ));
+ bmi->bmiHeader.biSize = 0x28;
+ if ( GetDIBits( hdc, hBitmap, 0, 96, NULL, bmi, DIB_RGB_COLORS ) == 0 ) {
+ TWinErrorCode errCode;
+ MSN_ShowError( "Unable to get the bitmap: error %d (%s)", errCode.mErrorCode, errCode.getText() );
+ return 2;
+ }
+
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+ pDib = ( BITMAPINFOHEADER* )GlobalAlloc( LPTR, sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 + bmi->bmiHeader.biSizeImage );
+ if ( pDib == NULL )
+ return 3;
+
+ memcpy( pDib, bmi, sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256 );
+ pDibBits = (( BYTE* )pDib ) + sizeof( BITMAPINFO ) + sizeof( RGBQUAD )*256;
+
+ GetDIBits( hdc, hBitmap, 0, pDib->biHeight, pDibBits, ( BITMAPINFO* )pDib, DIB_RGB_COLORS );
+ SelectObject( hdc, hOldBitmap );
+ DeleteDC( hdc );
+
+ long dwPngSize = 0;
+ DIB2PNG convertor;
+ convertor.pbmi = ( BITMAPINFO* )pDib;
+ convertor.pDiData = pDibBits;
+ convertor.pResult = NULL;
+ convertor.pResultLen = &dwPngSize;
+ if ( !CallService( MS_DIB2PNG, 0, (LPARAM)&convertor )) {
+ GlobalFree( pDib );
+ return 2;
+ }
+
+ convertor.pResult = new BYTE[ dwPngSize ];
+ CallService( MS_DIB2PNG, 0, (LPARAM)&convertor );
+ GlobalFree( pDib );
+
+ SHA1Context sha1ctx;
+ BYTE sha1c[ SHA1HashSize ], sha1d[ SHA1HashSize ];
+ char szSha1c[ 40 ], szSha1d[ 40 ];
+ SHA1Reset( &sha1ctx );
+ SHA1Input( &sha1ctx, convertor.pResult, dwPngSize );
+ SHA1Result( &sha1ctx, sha1d );
+ { NETLIBBASE64 nlb = { szSha1d, sizeof szSha1d, ( PBYTE )sha1d, sizeof sha1d };
+ MSN_CallService( MS_NETLIB_BASE64ENCODE, 0, LPARAM( &nlb ));
+ }
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ _splitpath(szFileName, drive, dir, fname, ext );
+ SHA1Reset( &sha1ctx );
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, szEmail, sizeof szEmail );
+ SHA1Input( &sha1ctx, ( PBYTE )"Creator", 7 );
+ SHA1Input( &sha1ctx, ( PBYTE )szEmail, strlen( szEmail ));
+
+ char szFileSize[ 20 ];
+ ltoa( dwPngSize, szFileSize, 10 );
+ SHA1Input( &sha1ctx, ( PBYTE )"Size", 4 );
+ SHA1Input( &sha1ctx, ( PBYTE )szFileSize, strlen( szFileSize ));
+
+ SHA1Input( &sha1ctx, ( PBYTE )"Type", 4 );
+ SHA1Input( &sha1ctx, ( PBYTE )"3", 1 );
+
+ SHA1Input( &sha1ctx, ( PBYTE )"Location", 8 );
+ SHA1Input( &sha1ctx, ( PBYTE )fname, sizeof(fname));
+
+ SHA1Input( &sha1ctx, ( PBYTE )"Friendly", 8 );
+ SHA1Input( &sha1ctx, ( PBYTE )"AAA=", 4 );
+
+ SHA1Input( &sha1ctx, ( PBYTE )"SHA1D", 5 );
+ SHA1Input( &sha1ctx, ( PBYTE )szSha1d, strlen( szSha1d ));
+ SHA1Result( &sha1ctx, sha1c );
+ { NETLIBBASE64 nlb = { szSha1c, sizeof szSha1c, ( PBYTE )sha1c, sizeof sha1c };
+ MSN_CallService( MS_NETLIB_BASE64ENCODE, 0, LPARAM( &nlb ));
+ }
+ {
+ char* szBuffer = ( char* )alloca( 1000 );
+ mir_snprintf( szBuffer, 1000,
+ "<msnobj Creator=\"%s\" Size=\"%ld\" Type=\"3\" Location=\"%s\" Friendly=\"AAA=\" SHA1D=\"%s\" SHA1C=\"%s\"/>",
+ szEmail, dwPngSize,fname, szSha1d, szSha1c );
+
+ char* szEncodedBuffer = ( char* )alloca( 1000 );
+ UrlEncode( szBuffer, szEncodedBuffer, 1000 );
+
+ MSN_SetString( NULL, "PictObject", szEncodedBuffer );
+ }
+ { char tFileName[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, tFileName, sizeof tFileName );
+ FILE* out = fopen( tFileName, "wb" );
+ if ( out != NULL ) {
+ fwrite( convertor.pResult, dwPngSize, 1, out );
+ fclose( out );
+ } }
+ delete convertor.pResult;
+ return ERROR_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_EnterBitmapFileName - enters a bitmap filename
+
+int __stdcall MSN_EnterBitmapFileName( char* szDest )
+{
+ *szDest = 0;
+
+ char szFilter[ 512 ];
+ MSN_CallService( MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof szFilter, ( LPARAM )szFilter );
+
+ char str[ MAX_PATH ]; str[0] = 0;
+ OPENFILENAMEA ofn = {0};
+ 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;
+}
diff --git a/miranda-wine/protocols/MSN/msn_block.cpp b/miranda-wine/protocols/MSN/msn_block.cpp
new file mode 100644
index 0000000..12199f0
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_block.cpp
@@ -0,0 +1,33 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 <windows.h>
+#include <stdio.h>
+
+#include "msn_global.h"
+
+#pragma hdrstop
+
+#include "resource.h"
+
+extern HINSTANCE hInst;
diff --git a/miranda-wine/protocols/MSN/msn_chat.cpp b/miranda-wine/protocols/MSN/msn_chat.cpp
new file mode 100644
index 0000000..fae3574
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_chat.cpp
@@ -0,0 +1,335 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+#include "../../include/m_history.h"
+
+static LONG sttChatID = 0;
+extern HANDLE hInitChat;
+
+int MSN_ChatInit( WPARAM wParam, LPARAM lParam )
+{
+ ThreadData *info = (ThreadData*)wParam;
+ GCWINDOW gcw = {0};
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ InterlockedIncrement( &sttChatID );
+ ltoa( sttChatID, info->mChatID, 10 );
+
+ info->mJoinedContacts = ( HANDLE* )realloc(info->mJoinedContacts, sizeof(HANDLE)*(++info->mJoinedCount));
+ info->mJoinedContacts[info->mJoinedCount - 1] = info->mJoinedContacts[0];
+ info->mJoinedContacts[0] = ( HANDLE )-sttChatID;
+
+ char szName[ 512 ];
+ char tEmail[ MSN_MAX_EMAIL_LEN ], tNick[ 1024 ];
+ mir_snprintf( szName, sizeof( szName ), "%s%s", Translate("MSN Chat #"), info->mChatID );
+
+ gcw.cbSize = sizeof(GCWINDOW);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = msnProtocolName;
+ gcw.pszName = szName;
+ gcw.pszID = info->mChatID;
+ gcw.pszStatusbarText = NULL;
+ gcw.bDisableNickList = FALSE;
+ MSN_CallService(MS_GC_NEWCHAT, NULL, (LPARAM)&gcw);
+
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.pDest = &gcd;
+ gce.pszStatus = Translate("Me");
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_JOIN;
+ gce.pszStatus, Translate("Me");
+ MSN_GetStaticString( "Nick", NULL, tNick, sizeof tNick );
+ gce.pszNick = tNick;
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail );
+ gce.pszUID = tEmail;
+ gce.time = 0;
+ gce.bIsMe = TRUE;
+ gce.bAddToLog = FALSE;
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ gcd.iType = GC_EVENT_ADDGROUP;
+ gce.pDest = &gcd;
+ gce.pszStatus = Translate("Others");
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ gce.cbSize = sizeof(GCEVENT);
+ gcd.iType = GC_EVENT_CONTROL;
+ gce.pDest = &gcd;
+ MSN_CallService(MS_GC_EVENT, WINDOW_INITDONE, (LPARAM)&gce);
+ MSN_CallService(MS_GC_EVENT, WINDOW_ONLINE, (LPARAM)&gce);
+ MSN_CallService(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce);
+ return 0;
+}
+
+void MSN_ChatStart(ThreadData* info) {
+ if ( info->mChatID[0] == 0 ) {
+ NotifyEventHooks( hInitChat, (WPARAM)info, 0 );
+
+ // add all participants onto the list
+ GCDEST gcd = {0};
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_JOIN;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszStatus = Translate("Others");
+ gce.time = time(NULL);
+ gce.bIsMe = FALSE;
+ gce.bAddToLog = TRUE;
+
+ for ( int j=0; j < info->mJoinedCount; j++ ) {
+ if (( long )info->mJoinedContacts[j] > 0 ) {
+ gce.pszNick = MSN_GetContactName( info->mJoinedContacts[j] );
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", info->mJoinedContacts[j], tEmail, sizeof tEmail )) {
+ gce.pszUID = tEmail;
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ } } } }
+}
+
+void KillChatSession(char* id, GCHOOK* gch) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gcd.pszModule = gch->pDest->pszModule;
+ gcd.pszID = gch->pDest->pszID;
+ gcd.iType = GC_EVENT_CONTROL;
+ MSN_CallService(MS_GC_EVENT, WINDOW_OFFLINE, (LPARAM)&gce);
+ MSN_CallService(MS_GC_EVENT, WINDOW_TERMINATE, (LPARAM)&gce);
+}
+
+void InviteUser(ThreadData* info) {
+ HMENU tMenu = ::CreatePopupMenu();
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+
+ // 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 != NULL ) {
+ if ( !lstrcmpA( msnProtocolName, ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 ))) {
+ if (DBGetContactSettingByte(hContact, msnProtocolName, "ChatRoom", 0) == 0) {
+ if (MSN_GetWord(hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) {
+ BOOL alreadyInSession = FALSE;
+ for ( int j=0; j < info->mJoinedCount; j++ ) {
+ if (info->mJoinedContacts[j] == hContact) {
+ alreadyInSession = TRUE;
+ break;
+ }
+ }
+ if (!alreadyInSession)
+ ::AppendMenu(tMenu, MF_STRING, (UINT_PTR)hContact, MSN_GetContactNameT(hContact));
+ }
+ } }
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+ }
+
+ HWND tWindow = CreateWindow(_T("EDIT"),_T(""),0,1,1,1,1,NULL,NULL,hInst,NULL);
+
+ POINT pt;
+ ::GetCursorPos ( &pt );
+ HANDLE 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 )
+ return;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )hInvitedUser, tEmail, sizeof( tEmail ))) {
+ info->sendPacket( "CAL", tEmail );
+ MSN_ChatStart(info);
+} }
+
+int MSN_GCEventHook(WPARAM wParam,LPARAM lParam) {
+ GCHOOK *gch = (GCHOOK*) lParam;
+ char S[512] = "";
+
+ if(gch) {
+ if (!lstrcmpiA(gch->pDest->pszModule, msnProtocolName)) {
+ char *p = new char[lstrlenA(gch->pDest->pszID)+1];
+ lstrcpyA(p, gch->pDest->pszID);
+ switch (gch->pDest->iType) {
+ case GC_USER_TERMINATE: {
+ int chatID = atoi( p );
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ if ( thread != NULL ) {
+ // open up srmm dialog when quit while 1 person left
+ if ( thread->mJoinedCount == 1 ) {
+ // switch back to normal session
+ thread->mJoinedContacts[0] = thread->mJoinedContacts[1];
+ thread->mJoinedContacts = ( HANDLE* )realloc( thread->mJoinedContacts, sizeof( HANDLE ) );
+ MSN_CallService(MS_MSG_SENDMESSAGE, (WPARAM)thread->mJoinedContacts[0], 0);
+ thread->mChatID[0] = 0;
+ }
+ else thread->sendPacket( "OUT", NULL );
+ }
+ break;
+ }
+ case GC_USER_MESSAGE:
+ if ( gch && gch->pszText && lstrlenA( gch->pszText ) > 0 ) {
+ rtrim( gch->pszText ); // remove the ending linebreak
+
+ { char* pszMsg = UnEscapeChatTags( NEWSTR_ALLOCA( gch->pszText ));
+
+ CCSDATA ccs = {0};
+ ccs.hContact = (HANDLE)-atoi(p);
+ ccs.wParam = 0;
+ ccs.lParam = (LPARAM)pszMsg;
+ CallProtoService(msnProtocolName, PSS_MESSAGE, (WPARAM)0, (LPARAM)&ccs);
+ }
+
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = p;
+ gcd.iType = GC_EVENT_MESSAGE;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ], tNick[ 1024 ];
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ MSN_GetStaticString( "Nick", NULL, tNick, sizeof tNick );
+ gce.pszNick = tNick;
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail );
+ gce.pszUID = tEmail;
+ gce.time = time(NULL);
+ gce.pszText = gch->pszText;
+ gce.bAddToLog = TRUE;
+ gce.bIsMe = TRUE;
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+ }
+ break;
+ case GC_USER_CHANMGR: {
+ int chatID = atoi(p);
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ if ( thread != NULL ) {
+ InviteUser(thread);
+ }
+ break;
+ }
+ case GC_USER_PRIVMESS: {
+ HANDLE hContact = MSN_HContactFromEmail((char*)gch->pszUID, NULL, 0, 0);
+ MSN_CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0);
+ break;
+ }
+ case GC_USER_LOGMENU:
+ switch(gch->dwData) {
+ case 10: {
+ int chatID = atoi(p);
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ if ( thread != NULL ) {
+ InviteUser(thread);
+ }
+ break;
+ }
+ case 20:
+ KillChatSession(p, gch);
+ break;
+ }
+ break;
+ case GC_USER_NICKLISTMENU: {
+ HANDLE hContact = MSN_HContactFromEmail((char*)gch->pszUID, NULL, 0, 0);
+
+ switch(gch->dwData) {
+ case 10:
+ MSN_CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0);
+ break;
+ case 20:
+ MSN_CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)hContact, 0);
+ break;
+ case 110:
+ KillChatSession(p, gch);
+ break;
+ }
+ break;
+ }
+/* haven't implemented in chat.dll
+ case GC_USER_TYPNOTIFY: {
+ int chatID = atoi(p);
+ ThreadData* thread = MSN_GetThreadByContact((HANDLE)-chatID);
+ for ( int j=0; j < thread->mJoinedCount; j++ ) {
+ if (( long )thread->mJoinedContacts[j] > 0 )
+ CallService(MS_PROTO_SELFISTYPING, (WPARAM) thread->mJoinedContacts[j], (LPARAM) PROTOTYPE_SELFTYPING_ON);
+ }
+ break;
+ }
+*/
+ default:
+ break;
+ }
+ delete[]p;
+ }
+
+ }
+ return 0;
+}
+
+int MSN_GCMenuHook(WPARAM wParam,LPARAM lParam) {
+ GCMENUITEMS *gcmi= (GCMENUITEMS*) lParam;
+
+ if ( gcmi ) {
+ if (!lstrcmpiA(gcmi->pszModule, msnProtocolName)) {
+ if(gcmi->Type == MENU_ON_LOG) {
+ static struct gc_item Item[] = {
+ {Translate("&Invite user..."), 10, MENU_ITEM, FALSE},
+ {Translate("&Leave chat session"), 20, MENU_ITEM, FALSE}
+ };
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ }
+ if(gcmi->Type == MENU_ON_NICKLIST) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail );
+ if (!lstrcmpA(tEmail, (char *)gcmi->pszUID)) {
+ static struct gc_item Item[] = {
+ {Translate("User &details"), 10, MENU_ITEM, FALSE},
+ {Translate("User &history"), 20, MENU_ITEM, FALSE},
+ {Translate(""), 100, MENU_SEPARATOR, FALSE},
+ {Translate("&Leave chat session"), 110, MENU_ITEM, FALSE}
+ };
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ }
+ else {
+ static struct gc_item Item[] = {
+ {Translate("User &details"), 10, MENU_ITEM, FALSE},
+ {Translate("User &history"), 20, MENU_ITEM, FALSE}
+ };
+ gcmi->nItems = sizeof(Item)/sizeof(Item[0]);
+ gcmi->Item = &Item[0];
+ } } } }
+
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_commands.cpp b/miranda-wine/protocols/MSN/msn_commands.cpp
new file mode 100644
index 0000000..4e84931
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_commands.cpp
@@ -0,0 +1,1841 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <io.h>
+#include <direct.h>
+#include <process.h>
+#include <time.h>
+
+#include "resource.h"
+
+#include "msn_md5.h"
+
+void __cdecl MSNNudgeThread( ThreadData* info );
+void __cdecl MSNServerThread( ThreadData* info );
+void __cdecl MSNSendfileThread( ThreadData* info );
+
+int MSN_GetPassportAuth( char* authChallengeInfo, char*& parResult );
+
+void mmdecode(char *trg, char *str);
+
+void MSN_ChatStart(ThreadData* info);
+
+ int tridUrlInbox = -1, tridUrlEdit = -1;
+
+char* sid = NULL;
+char* kv = NULL;
+char* MSPAuth = NULL;
+char* passport = NULL;
+char* profileURL = NULL;
+char* rru = NULL;
+extern HANDLE hMSNNudge;
+
+extern int msnPingTimeout, msnPingTimeoutCurrent;
+
+unsigned long sl;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_ReceiveMessage - receives message or a file from the server
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int sttDivideWords( char* parBuffer, int parMinItems, char** parDest )
+{
+ int i;
+ for ( i=0; i < parMinItems; i++ ) {
+ parDest[ i ] = parBuffer;
+
+ int tWordLen = strcspn( parBuffer, " \t" );
+ if ( tWordLen == 0 )
+ return i;
+
+ parBuffer += tWordLen;
+ if ( *parBuffer != '\0' ) {
+ int tSpaceLen = strspn( parBuffer, " \t" );
+ memset( parBuffer, 0, tSpaceLen );
+ parBuffer += tSpaceLen;
+ } }
+
+ return i;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetMyHostAsString - retrieves a host address as a string
+
+int __stdcall MSN_GetMyHostAsString( char* parBuf, int parBufSize )
+{
+ IN_ADDR in;
+ hostent* myhost;
+
+ if ( msnExternalIP != NULL )
+ strncpy( parBuf, msnExternalIP, parBufSize );
+ else
+ gethostname( parBuf, parBufSize );
+
+ if ( MSN_GetByte( "AutoGetHost", 1 ))
+ MSN_SetString( NULL, "YourHost", parBuf );
+ else
+ MSN_GetStaticString( "YourHost", NULL, parBuf, parBufSize );
+
+ long ipaddrlong = inet_addr( parBuf );
+ if ( ipaddrlong != INADDR_NONE )
+ in.S_un.S_addr = ipaddrlong;
+ else
+ { myhost = gethostbyname( parBuf );
+ if ( myhost == NULL ) {
+ { TWinErrorCode tError;
+ MSN_ShowError( "Unknown or invalid host name was specified (%s). Error %d: %s.",
+ parBuf, tError.mErrorCode, tError.getText());
+ }
+
+ return 1;
+ }
+ memcpy( &in, myhost->h_addr, 4 );
+ }
+
+ strncpy( parBuf, inet_ntoa( in ), parBufSize );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Starts a file sending thread
+
+void MSN_ConnectionProc( HANDLE hNewConnection, DWORD dwRemoteIP, void* )
+{
+ MSN_DebugLog( "File transfer connection accepted" );
+
+ WORD localPort = 0;
+ SOCKET s = MSN_CallService( MS_NETLIB_GETSOCKET, ( WPARAM )hNewConnection, 0 );
+ if ( s != INVALID_SOCKET) {
+ SOCKADDR_IN saddr;
+ int len = sizeof( saddr );
+ if ( getsockname( s, ( SOCKADDR* )&saddr, &len ) != SOCKET_ERROR )
+ localPort = ntohs( saddr.sin_port );
+ }
+
+ if ( localPort != 0 ) {
+ ThreadData* T = MSN_GetThreadByPort( localPort );
+ if ( T != NULL ) {
+ T->s = hNewConnection;
+ if ( T->mMsnFtp != NULL ) {
+ T->mMsnFtp->mIncomingPort = 0;
+ SetEvent( T->mMsnFtp->hWaitEvent );
+ }
+ else {
+ T->mP2pSession->mIncomingPort = 0;
+ SetEvent( T->mP2pSession->hWaitEvent );
+ }
+ return;
+ }
+ MSN_DebugLog( "There's no registered file transfers for incoming port #%d, connection closed", localPort );
+ }
+ else MSN_DebugLog( "Unable to determine the local port, file server connection closed." );
+
+ Netlib_CloseHandle( hNewConnection );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Processes e-mail notification
+
+static void sttNotificationMessage( const char* msgBody, bool isInitial )
+{
+ char tBuffer[512];
+ char tBuffer2[512];
+ bool tIsPopup = ServiceExists( MS_POPUP_ADDPOPUP ) != 0;
+ int UnreadMessages = 0, UnreadJunkEmails = 0;
+
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msgBody );
+
+ const char* From = tFileInfo[ "From" ];
+ const char* Subject = tFileInfo[ "Subject" ];
+ const char* Fromaddr = tFileInfo[ "From-Addr" ];
+ {
+ const char* p;
+ if (( p = tFileInfo[ "Inbox-Unread" ] ) != NULL )
+ UnreadMessages = atoi( p );
+ if (( p = tFileInfo[ "Folders-Unread" ] ) != NULL )
+ UnreadJunkEmails = atoi( p );
+ }
+
+ if ( From != NULL && Subject != NULL && Fromaddr != NULL ) {
+ const char* SrcFolder = tFileInfo[ "Src-Folder" ];
+ const char* DestFolder = tFileInfo[ "Dest-Folder" ];
+ if ( DestFolder != NULL && SrcFolder == NULL ) {
+ UnreadMessages = strcmp( DestFolder, "ACTIVE" ) == 0;
+ UnreadJunkEmails = strcmp( DestFolder, "HM_BuLkMail_" ) == 0;
+ }
+
+ // nothing to do, a fake notification
+ if ( UnreadMessages == 0 && UnreadJunkEmails == 0 )
+ return;
+
+ char mimeFrom[ 1024 ], mimeSubject[ 1024 ];
+ mmdecode( mimeFrom, ( char* )From );
+ mmdecode( mimeSubject, ( char* )Subject );
+
+ if ( !strcmpi( From, Fromaddr )) {
+ if ( tIsPopup ) {
+ mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate( "Hotmail from %s" ), mimeFrom );
+ mir_snprintf( tBuffer2, sizeof( tBuffer2 ), MSN_Translate( "Subject: %s" ), mimeSubject );
+ }
+ else mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate("A new mail has come from %s (title: %s)."), mimeFrom, mimeSubject );
+ }
+ else {
+ if ( tIsPopup ) {
+ mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate("Hotmail from %s (%s)"),mimeFrom, Fromaddr );
+ mir_snprintf( tBuffer2, sizeof( tBuffer2 ), MSN_Translate("Subject: %s"), mimeSubject );
+ }
+ else mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate("A new mail has come from %s (%s) (title: %s)."),mimeFrom, Fromaddr, mimeSubject );
+ } }
+ else {
+ const char* MailData = tFileInfo[ "Mail-Data" ];
+ if ( MailData != NULL ) {
+ const char* p = strstr( MailData, "<IU>" );
+ if ( p != NULL )
+ UnreadMessages = atoi( p+4 );
+ if (( p = strstr( MailData, "<OU>" )) != NULL )
+ UnreadJunkEmails = atoi( p+4 );
+ }
+
+ // nothing to do, a fake notification
+ if ( UnreadMessages == 0 && UnreadJunkEmails == 0 )
+ return;
+
+ char* dest;
+ if ( tIsPopup ) {
+ mir_snprintf( tBuffer, sizeof( tBuffer ), MSN_Translate( "Hotmail" ));
+ dest = tBuffer2;
+ }
+ else dest = tBuffer;
+ mir_snprintf( dest, sizeof( tBuffer ), MSN_Translate( "Unread mail is available: %d messages (%d junk e-mails)." ),
+ UnreadMessages, UnreadJunkEmails );
+ }
+
+ // Disable to notify receiving hotmail
+ if ( !MSN_GetByte( "DisableHotmail", 1 )) {
+ if ( UnreadMessages != 0 || !MSN_GetByte( "DisableHotmailJunk", 0 )) {
+ SkinPlaySound( mailsoundname );
+ if ( tIsPopup )
+ MSN_ShowPopup( tBuffer, tBuffer2, MSN_ALLOW_ENTER + MSN_ALLOW_MSGBOX + MSN_HOTMAIL_POPUP );
+ else
+ MessageBoxA( NULL, tBuffer, "MSN Protocol", MB_OK | MB_ICONINFORMATION );
+ } }
+
+ if ( !MSN_GetByte( "RunMailerOnHotmail", 0 ))
+ return;
+
+ if ( !MSN_GetStaticString( "MailerPath", NULL, tBuffer, sizeof( tBuffer ))) {
+ if ( tBuffer[0] ) {
+ char* tParams = "";
+ char* p = tBuffer;
+
+ if ( *p == '\"' ) {
+ char* tEndPtr = strchr( p+1, '\"' );
+ if ( tEndPtr != NULL ) {
+ *tEndPtr = 0;
+ strdel( p, 1 );
+ tParams = tEndPtr+1;
+ goto LBL_Run;
+ } }
+
+ p = strchr( p+1, ' ' );
+ if ( p != NULL ) {
+ *p = 0;
+ tParams = p+1;
+ }
+LBL_Run:
+ while ( *tParams == ' ' )
+ tParams++;
+
+ MSN_DebugLog( "Running mailer \"%s\" with params \"%s\"", tBuffer, tParams );
+ ShellExecuteA( NULL, "open", tBuffer, tParams, NULL, TRUE );
+} } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Processes various invitations
+
+static void sttInviteMessage( ThreadData* info, const char* msgBody, char* email, char* nick )
+{
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msgBody );
+
+ const char* Appname = tFileInfo[ "Application-Name" ];
+ const char* AppGUID = tFileInfo[ "Application-GUID" ];
+ const char* Invcommand = tFileInfo[ "Invitation-Command" ];
+ const char* Invcookie = tFileInfo[ "Invitation-Cookie" ];
+ const char* Appfile = tFileInfo[ "Application-File" ];
+ const char* Appfilesize = tFileInfo[ "Application-FileSize" ];
+ const char* IPAddress = tFileInfo[ "IP-Address" ];
+ const char* Port = tFileInfo[ "Port" ];
+ const char* AuthCookie = tFileInfo[ "AuthCookie" ];
+ const char* SessionID = tFileInfo[ "Session-ID" ];
+ const char* SessionProtocol = tFileInfo[ "Session-Protocol" ];
+
+ if ( AppGUID != NULL ) {
+ if ( !strcmp( AppGUID, "{02D3C01F-BF30-4825-A83A-DE7AF41648AA}" )) {
+ MSN_ShowPopup( MSN_GetContactName( info->mJoinedContacts[0] ),
+ MSN_Translate( "Contact tried to open an audio conference (currently not supported)" ), MSN_ALLOW_MSGBOX );
+ return;
+ } }
+
+ if ( Invcommand && ( strcmp( Invcommand, "CANCEL" ) == 0 )) {
+ delete info->mMsnFtp;
+ info->mMsnFtp = NULL;
+ }
+
+ if ( Appname != NULL && Appfile != NULL && Appfilesize != NULL ) { // receive first
+ filetransfer* ft = info->mMsnFtp = new filetransfer();
+
+ ft->mThreadId = info->mUniqueID;
+ ft->std.hContact = MSN_HContactFromEmail( email, nick, 1, 1 );
+ replaceStr( ft->std.currentFile, Appfile );
+ Utf8Decode( ft->std.currentFile, &ft->wszFileName );
+ ft->fileId = -1;
+ ft->std.currentFileSize = atol( Appfilesize );
+ ft->std.totalBytes = atol( Appfilesize );
+ ft->std.totalFiles = 1;
+ ft->szInvcookie = strdup( Invcookie );
+
+ int tFileNameLen = strlen( ft->std.currentFile );
+ char tComment[ 40 ];
+ int tCommentLen = mir_snprintf( tComment, sizeof( tComment ), "%lu bytes", ft->std.currentFileSize );
+ char* szBlob = ( char* )malloc( sizeof( DWORD ) + tFileNameLen + tCommentLen + 2 );
+ *( PDWORD )szBlob = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), ft->std.currentFile );
+ strcpy( szBlob + sizeof( DWORD ) + tFileNameLen + 1, tComment );
+
+ PROTORECVEVENT pre;
+ pre.flags = 0;
+ pre.timestamp = ( DWORD )time( NULL );
+ pre.szMessage = ( char* )szBlob;
+ pre.lParam = ( LPARAM )( char* )Invcookie;
+
+ CCSDATA ccs;
+ ccs.hContact = MSN_HContactFromEmail( email, nick, 1, 1 );
+ ccs.szProtoService = PSR_FILE;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ MSN_CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ return;
+ }
+
+ if ( IPAddress != NULL && Port != NULL && AuthCookie != NULL ) { // receive Second
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, IPAddress );
+ strcat( newThread->mServer, ":" );
+ strcat( newThread->mServer, Port );
+ newThread->mType = SERVER_FILETRANS;
+
+ if ( info->mMsnFtp == NULL )
+ {
+ ThreadData* otherThread = MSN_GetOtherContactThread( info );
+ if ( otherThread )
+ {
+ info->mMsnFtp = otherThread->mMsnFtp;
+ otherThread->mMsnFtp = NULL;
+ }
+ }
+
+ newThread->mMsnFtp = info->mMsnFtp; info->mMsnFtp = NULL;
+ strcpy( newThread->mCookie, AuthCookie );
+
+ MSN_DebugLog( "Connecting to '%s'...", newThread->mServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ return;
+ }
+
+ if ( Invcommand != NULL && Invcookie != NULL && Port == NULL && AuthCookie == NULL && SessionID == NULL ) { // send 1
+ ft_startFileSend( info, Invcommand, Invcookie );
+ return;
+ }
+
+ if ( Appname == NULL && SessionID != NULL && SessionProtocol != NULL ) { // netmeeting send 1
+ if ( !strcmpi( Invcommand,"ACCEPT" )) {
+ char ipaddr[256];
+ MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ));
+
+ ShellExecuteA(NULL, "open", "conf.exe", NULL, NULL, SW_SHOW);
+ Sleep(3000);
+
+ char command[ 1024 ];
+ int nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Session-ID: {1A879604-D1B8-11D7-9066-0003FF431510}\r\n"
+ "Launch-Application: TRUE\r\n"
+ "IP-Address: %s\r\n\r\n",
+ Invcookie, ipaddr);
+ info->sendPacket( "MSG", "N %d\r\n%s", nBytes, command );
+ }
+ return;
+ }
+
+ if ( Appname != NULL && !strcmpi( Appname,"NetMeeting" )) { // netmeeting receive 1
+ char command[ 1024 ];
+ int nBytes;
+
+ mir_snprintf( command, sizeof( command ), "Accept NetMeeting request from %s?", email );
+
+ if ( MessageBoxA( NULL, command, "MSN Protocol", MB_YESNO | MB_ICONQUESTION ) == IDYES ) {
+ char ipaddr[256];
+ MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ));
+
+ nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Session-ID: {A2ED5ACF-F784-4B47-A7D4-997CD8F643CC}\r\n"
+ "Session-Protocol: SM1\r\n"
+ "Launch-Application: TRUE\r\n"
+ "Request-Data: IP-Address:\r\n"
+ "IP-Address: %s\r\n\r\n",
+ Invcookie, ipaddr);
+ }
+ else {
+ nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: CANCEL\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Cancel-Code: REJECT\r\n\r\n",
+ Invcookie);
+ }
+ info->sendPacket( "MSG", "N %d\r\n%s", nBytes, command );
+ return;
+ }
+
+ if ( IPAddress != NULL && Port == NULL && SessionID != NULL && SessionProtocol == NULL ) { // netmeeting receive 2
+ char ipaddr[256];
+ mir_snprintf( ipaddr, sizeof( ipaddr ), "callto://%s", IPAddress);
+ ShellExecuteA(NULL, "open", ipaddr, NULL, NULL, SW_SHOW);
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Processes any received MSG
+
+void MSN_ReceiveMessage( ThreadData* info, char* cmdString, char* params )
+{
+ union {
+ char* tWords[ 3 ];
+ struct { char *fromEmail, *fromNick, *strMsgBytes; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 ) {
+ MSN_DebugLog( "Invalid %.3s command, ignoring", cmdString );
+ return;
+ }
+
+ int msgBytes = atol( data.strMsgBytes );
+
+ UrlDecode( data.fromEmail ); UrlDecode( data.fromNick );
+
+ char* msg = ( char* )alloca( msgBytes+1 );
+
+ int bytesFromData = min( info->mBytesInData, msgBytes );
+ memcpy( msg, info->mData, bytesFromData );
+ info->mBytesInData -= bytesFromData;
+ memmove( info->mData, info->mData + bytesFromData, info->mBytesInData );
+
+ while ( bytesFromData < msgBytes ) {
+ int recvResult;
+ recvResult = info->recv( msg + bytesFromData, msgBytes - bytesFromData );
+ if ( recvResult <= 0 )
+ return;
+
+ bytesFromData += recvResult;
+ }
+
+ msg[ msgBytes ] = 0;
+ MSN_DebugLog( "Message:\n%s", msg );
+
+ MimeHeaders tHeader;
+ const char* msgBody = tHeader.readFromBuffer( msg );
+
+ // message from the server (probably)
+ if (( strchr( data.fromEmail, '@' ) == NULL ) && strcmpi( data.fromEmail, "Hotmail" ))
+ return;
+
+ const char* tContentType = tHeader[ "Content-Type" ];
+ if ( tContentType == NULL )
+ return;
+
+ if ( !strnicmp( tContentType, "text/plain", 10 )) {
+ CCSDATA ccs;
+ HANDLE tContact = MSN_HContactFromEmail( data.fromEmail, data.fromNick, 1, 1 );
+
+ int isRtl = FALSE;
+ { const char* p = tHeader[ "X-MMS-IM-Format" ];
+ if ( p != NULL )
+ if ( strstr( p, "RL=1" ) != NULL )
+ isRtl = TRUE;
+ }
+
+ wchar_t* tRealBody = NULL;
+ int tRealBodyLen = 0;
+ if ( strstr( tContentType, "charset=UTF-8" ))
+ { Utf8Decode(( char* )msgBody, &tRealBody );
+ tRealBodyLen = wcslen( tRealBody );
+ }
+ int tMsgBodyLen = strlen( msgBody );
+
+ char* tPrefix = NULL;
+ int tPrefixLen = 0;
+
+ if ( info->mJoinedCount > 1 && info->mJoinedContacts != NULL ) {
+ if ( msnHaveChatDll )
+ MSN_ChatStart( info );
+ else if ( info->mJoinedContacts[0] != tContact ) {
+ for ( int j=1; j < info->mJoinedCount; j++ ) {
+ if ( info->mJoinedContacts[j] == tContact ) {
+ char* tNickName = MSN_GetContactName( info->mJoinedContacts[j] );
+ tPrefixLen = strlen( tNickName )+2;
+ tPrefix = ( char* )alloca( tPrefixLen+1 );
+ strcpy( tPrefix, "<" );
+ strcat( tPrefix, tNickName );
+ strcat( tPrefix, "> " );
+ ccs.hContact = info->mJoinedContacts[ 0 ];
+ break;
+ } } }
+ }
+ else ccs.hContact = tContact;
+
+ int tMsgBufLen = tMsgBodyLen+1 + (tRealBodyLen+1)*sizeof( wchar_t ) + tPrefixLen*(sizeof( wchar_t )+1);
+ char* tMsgBuf = ( char* )alloca( tMsgBufLen );
+ char* p = tMsgBuf;
+
+ if ( tPrefixLen != 0 ) {
+ memcpy( p, tPrefix, tPrefixLen );
+ p += tPrefixLen;
+ }
+ strcpy( p, msgBody );
+ p += tMsgBodyLen+1;
+
+ if ( tPrefixLen != 0 ) {
+ MultiByteToWideChar( CP_ACP, 0, tPrefix, tPrefixLen, ( wchar_t* )p, tPrefixLen );
+ p += tPrefixLen*sizeof( wchar_t );
+ }
+ if ( tRealBodyLen != 0 ) {
+ memcpy( p, tRealBody, sizeof( wchar_t )*( tRealBodyLen+1 ));
+ free( tRealBody );
+ }
+
+ if ( info->mChatID[0] ) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_MESSAGE;
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszUID = data.fromEmail;
+ gce.pszNick = MSN_GetContactName(MSN_HContactFromEmail(data.fromEmail, NULL, 1, 1));
+ gce.time = time(NULL);
+ gce.bIsMe = FALSE;
+ gce.pszText = (char*)EscapeChatTags(tMsgBuf);
+ //gce.pszText = tMsgBuf;
+ gce.bAddToLog = TRUE;
+ MSN_CallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+ free(( void* )gce.pszText);
+ }
+ else {
+ PROTORECVEVENT pre;
+ pre.szMessage = ( char* )tMsgBuf;
+ pre.flags = PREF_UNICODE + (( isRtl ) ? PREF_RTL : 0);
+ pre.timestamp = ( DWORD )time(NULL);
+ pre.lParam = 0;
+
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ MSN_CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ }
+ return;
+ }
+
+ if ( !strnicmp( tContentType, "text/x-msmsgsprofile", 20 )) {
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msg );
+ replaceStr( sid, tFileInfo[ "sid" ] );
+ replaceStr( kv, tFileInfo[ "kv" ] );
+ replaceStr( MSPAuth, tFileInfo[ "MSPAuth" ] );
+ replaceStr( msnExternalIP, tFileInfo[ "ClientIP" ] );
+
+ if ( msnExternalIP != NULL && MSN_GetByte( "AutoGetHost", 1 ))
+ MSN_SetString( NULL, "YourHost", msnExternalIP );
+
+ return;
+ }
+
+ if ( !strnicmp( tContentType, "text/x-msmsgscontrol", 20 )) {
+ MimeHeaders tFileInfo;
+ tFileInfo.readFromBuffer( msg );
+
+ char* tTypingUser = NULL;
+
+ for ( int j=0; j < tFileInfo.mCount; j++ )
+ if ( !strcmpi( tFileInfo.mVals[ j ].name, "TypingUser" ))
+ tTypingUser = tFileInfo.mVals[ j ].value;
+
+ if ( tTypingUser != NULL && info->mChatID[0] == 0 ) {
+ char userNick[ 388 ];
+ strcpy( userNick, tTypingUser );
+
+ HANDLE hContact = MSN_HContactFromEmail( tTypingUser, userNick, 1, 0 );
+ if ( hContact != NULL )
+ strcpy( userNick, MSN_GetContactName( hContact ));
+
+ MSN_CallService( MS_PROTO_CONTACTISTYPING, WPARAM( hContact ), 5 );
+
+ if ( MSN_GetByte( "DisplayTyping", 0 ))
+ MSN_ShowPopup( userNick, MSN_Translate( "typing..." ), 0 );
+ }
+
+ return;
+ }
+
+ //WIZZ
+ if ( !strnicmp( tContentType, "text/x-msnmsgr-datacast", 23 )) {
+ CCSDATA ccs;
+ HANDLE tContact = MSN_HContactFromEmail( data.fromEmail, data.fromNick, 1, 1 );
+
+ wchar_t* tRealBody = NULL;
+ int tRealBodyLen = 0;
+ if ( strstr( tContentType, "charset=UTF-8" ))
+ { Utf8Decode(( char* )msgBody, &tRealBody );
+ tRealBodyLen = wcslen( tRealBody );
+ }
+ int tMsgBodyLen = strlen( msgBody );
+
+ char* tPrefix = NULL;
+ int tPrefixLen = 0;
+
+ if ( info->mJoinedCount > 1 && info->mJoinedContacts != NULL ) {
+ if ( msnHaveChatDll )
+ MSN_ChatStart( info );
+ else if ( info->mJoinedContacts[0] != tContact ) {
+ for ( int j=1; j < info->mJoinedCount; j++ ) {
+ if ( info->mJoinedContacts[j] == tContact ) {
+ char* tNickName = MSN_GetContactName( info->mJoinedContacts[j] );
+ tPrefixLen = strlen( tNickName )+2;
+ tPrefix = ( char* )alloca( tPrefixLen+1 );
+ strcpy( tPrefix, "<" );
+ strcat( tPrefix, tNickName );
+ strcat( tPrefix, "> " );
+ ccs.hContact = info->mJoinedContacts[ 0 ];
+ break;
+ } } }
+ }
+ else ccs.hContact = tContact;
+
+ int tMsgBufLen = tMsgBodyLen+1 + (tRealBodyLen+1)*sizeof( wchar_t ) + tPrefixLen*(sizeof( wchar_t )+1);
+ char* tMsgBuf = ( char* )alloca( tMsgBufLen );
+ char* p = tMsgBuf;
+
+ if ( tPrefixLen != 0 ) {
+ memcpy( p, tPrefix, tPrefixLen );
+ p += tPrefixLen;
+ }
+ strcpy( p, msgBody );
+ p += tMsgBodyLen+1;
+
+ if ( tPrefixLen != 0 ) {
+ MultiByteToWideChar( CP_ACP, 0, tPrefix, tPrefixLen, ( wchar_t* )p, tPrefixLen );
+ p += tPrefixLen*sizeof( wchar_t );
+ }
+ if ( tRealBodyLen != 0 ) {
+ memcpy( p, tRealBody, sizeof( wchar_t )*( tRealBodyLen+1 ));
+ free( tRealBody );
+ }
+
+ if( !strnicmp(tMsgBuf,"ID: 1",5))
+ NotifyEventHooks(hMSNNudge,(WPARAM) tContact,0);
+ return;
+ }
+
+ if ( !strnicmp( tContentType,"text/x-msmsgsemailnotification", 30 ))
+ sttNotificationMessage( msgBody, false );
+ else if ( !strnicmp( tContentType, "text/x-msmsgsinitialemailnotification", 37 ))
+ sttNotificationMessage( msgBody, true );
+ else if ( !strnicmp( tContentType, "text/x-msmsgsinitialmdatanotification", 37 ))
+ sttNotificationMessage( msgBody, true );
+ else if ( !strnicmp( tContentType, "text/x-msmsgsinvite", 19 ))
+ sttInviteMessage( info, msgBody, data.fromEmail, data.fromNick );
+ else if ( !strnicmp( tContentType, "application/x-msnmsgrp2p", 24 ))
+ p2p_processMsg( info, msgBody );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Process user addition
+
+HANDLE sttProcessAdd( int trid, int listId, char* userEmail, char* userNick )
+{
+ if ( trid == msnSearchID ) {
+ msnNsThread->sendPacket( "REM", "BL %s", userEmail );
+
+ PROTOSEARCHRESULT isr;
+ memset( &isr, 0, sizeof( isr ));
+ isr.cbSize = sizeof( isr );
+ isr.nick = userNick;
+ isr.email = userEmail;
+ MSN_SendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE )msnSearchID, ( LPARAM )&isr );
+ MSN_SendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE )msnSearchID, 0 );
+
+ msnSearchID = -1;
+ return NULL;
+ }
+
+ UrlDecode( userEmail ); UrlDecode( userNick );
+ if ( !IsValidListCode( listId ))
+ return NULL;
+
+ HANDLE hContact = MSN_HContactFromEmail( userEmail, userNick, 1, 1 );
+ Utf8Decode( userNick );
+ int mask = Lists_Add( listId, userEmail, userNick );
+
+ if ( listId == LIST_RL && ( mask & ( LIST_FL+LIST_AL+LIST_BL )) == 0 )
+ MSN_AddAuthRequest( hContact, userEmail, userNick );
+
+ return hContact;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_HandleCommands - process commands from the server
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool sttIsSync = false;
+static int sttListNumber = 0;
+static HANDLE sttListedContact = NULL;
+static long sttListedContactMask;
+
+static void sttDeleteUnusedSetting( long mask, const char* settingName )
+{ if (( sttListedContactMask & mask ) == 0 )
+ DBDeleteContactSetting( sttListedContact, msnProtocolName, settingName );
+}
+
+static void sttProcessListedContactMask()
+{
+ if ( sttListedContact == NULL )
+ return;
+
+ sttDeleteUnusedSetting( 0x0001, "Phone" );
+ sttDeleteUnusedSetting( 0x0002, "CompanyPhone" );
+ sttDeleteUnusedSetting( 0x0004, "Cellular" );
+ sttDeleteUnusedSetting( 0x0008, "OnMobile" );
+ sttDeleteUnusedSetting( 0x0010, "OnMsnMobile" );
+}
+
+static bool sttAddGroup( char* params, bool isFromBoot )
+{
+ union {
+ char* tWords[ 2 ];
+ struct { char *grpName, *grpId; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ return false;
+
+ UrlDecode( data.grpName );
+ MSN_AddGroup( data.grpName, data.grpId );
+ if ( hGroupAddEvent != NULL )
+ SetEvent( hGroupAddEvent );
+
+ int i;
+ char str[ 10 ];
+
+ for ( i=0; true; i++ ) {
+ ltoa( i, str, 10 );
+
+ DBVARIANT dbv;
+ if ( DBGetContactSettingStringUtf( NULL, "CListGroups", str, &dbv ))
+ break;
+
+ bool result = !stricmp( dbv.pszVal+1, data.grpName );
+ MSN_FreeVariant( &dbv );
+ if ( result ) {
+ MSN_SetGroupNumber( data.grpId, i );
+ return true;
+ } }
+
+ if ( isFromBoot ) {
+ MSN_SetGroupNumber( data.grpId, i );
+
+ if ( MyOptions.ManageServer ) {
+ char szNewName[ 128 ];
+ mir_snprintf( szNewName, sizeof szNewName, "%c%s", 1 | GROUPF_EXPANDED, data.grpName );
+ DBWriteContactSettingStringUtf( NULL, "CListGroups", str, szNewName );
+ CallService( MS_CLUI_GROUPADDED, i, 0 );
+ } }
+ return true;
+}
+
+static void sttSwapInt64( LONGLONG* parValue )
+{
+ BYTE* p = ( BYTE* )parValue;
+ for ( int i=0; i < 4; i++ ) {
+ BYTE temp = p[i];
+ p[i] = p[7-i];
+ p[7-i] = temp;
+} }
+
+int MSN_HandleCommands( ThreadData* info, char* cmdString )
+{
+ char* params = "";
+ int trid = -1;
+ sttIsSync = false;
+
+ if ( cmdString[3] ) {
+ if ( isdigit(( BYTE )cmdString[ 4 ] )) {
+ trid = strtol( cmdString+4, &params, 10 );
+ switch ( *params ) {
+ case ' ': case '\0': case '\t': case '\n':
+ while ( *params == ' ' || *params == '\t' )
+ params++;
+ break;
+
+ default: params = cmdString+4;
+ } }
+ else params = cmdString+4;
+ }
+ MSN_DebugLog("%S", cmdString);
+
+ if ( info->mType == SERVER_NOTIFICATION )
+ msnPingTimeout = msnPingTimeoutCurrent;
+
+ switch(( *( PDWORD )cmdString & 0x00FFFFFF ) | 0x20000000 )
+ {
+ case ' KCA': //********* ACK: section 8.7 Instant Messages
+ if ( info->mP2PInitTrid == trid ) {
+ info->mP2PInitTrid = 0;
+ p2p_sendFeedStart( info->mP2pSession, info );
+ info->mP2pSession = NULL;
+ }
+ else if ( info->mJoinedCount > 0 && MyOptions.SlowSend )
+ MSN_SendBroadcast( info->mJoinedContacts[0], ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )trid, 0 );
+ break;
+
+ case ' CDA': // ADC - MSN v10 addition command
+ {
+ char* tWords[ 10 ];
+ char *userNick = NULL, *userEmail = NULL, *userId = NULL, *groupId = NULL;
+ int nTerms = sttDivideWords( params, 10, tWords );
+ if ( nTerms < 2 )
+ goto LBL_InvalidCommand;
+
+ for ( int i=1; i < nTerms; i++ ) {
+ char* p = tWords[ i ];
+ if ( *p == 'F' && p[1] == '=' )
+ userNick = p+2;
+ else if ( *p == 'N' && p[1] == '=' )
+ userEmail = p+2;
+ else if ( *p == 'C' && p[1] == '=' )
+ userId = p+2;
+ else
+ groupId = p;
+ }
+
+ HANDLE hContact;
+ if ( userEmail == NULL ) {
+ if ( userId == NULL || groupId == NULL )
+ goto LBL_InvalidCommand;
+ hContact = MSN_HContactById( userId );
+ }
+ else {
+ if ( userNick == NULL )
+ userNick = userEmail;
+
+ int listId = Lists_NameToCode( tWords[0] );
+ hContact = sttProcessAdd( trid, listId, userEmail, userNick );
+ }
+
+ if ( hContact != NULL ) {
+ if ( userId != NULL ) MSN_SetString( hContact, "ID", userId );
+ if ( groupId != NULL ) MSN_SetString( hContact, "GroupID", groupId );
+ }
+ break;
+ }
+ case ' DDA': //********* ADD: section 7.8 List Modifications
+ {
+ union {
+ char* tWords[ 4 ];
+ struct { char *list, *serial, *userEmail, *userNick; } data;
+ };
+
+ if ( sttDivideWords( params, 4, tWords ) != 4 ) {
+LBL_InvalidCommand:
+ MSN_DebugLog( "Invalid %.3s command, ignoring", cmdString );
+ break;
+ }
+
+ sttProcessAdd( trid, Lists_NameToCode( data.list ), data.userEmail, data.userNick );
+ break;
+ }
+ case ' GDA': //********* ADG: group addition
+ if ( !sttAddGroup( params, false ))
+ goto LBL_InvalidCommand;
+ break;
+
+ case ' SNA': //********* ANS: section 8.4 Getting Invited to a Switchboard Session
+ if ( info->mJoinedCount == 1 ) {
+ MsgQueueEntry E;
+ HANDLE hContact = info->mJoinedContacts[0];
+ if ( MsgQueue_GetNext( hContact, E ) != 0 ) {
+ do {
+ if ( E.msgSize == 0 ) {
+ info->sendMessage( E.msgType, E.message, E.flags );
+ MSN_SendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )E.seq, 0 );
+ }
+ else info->sendRawMessage( E.msgType, E.message, E.msgSize );
+
+ free( E.message );
+
+ if ( E.ft != NULL ) {
+ info->mMsnFtp = E.ft;
+ info->mMsnFtp->mOwnsThread = true;
+ }
+ }
+ while (MsgQueue_GetNext( hContact, E ) != 0 );
+
+ if ( MSN_GetByte( "EnableDeliveryPopup", 1 ))
+ MSN_ShowPopup( MSN_GetContactName( hContact ), MSN_Translate( "First message delivered" ), 0 );
+ } }
+
+ break;
+
+ case ' PLB': //********* BLP: section 7.6 List Retrieval And Property Management
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *junk, *listName; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) == 1 )
+ data.listName = data.junk;
+
+ msnOtherContactsBlocked = stricmp( data.listName, "BL" ) == 0;
+ break;
+ }
+ case ' RPB': //********* BPR:
+ {
+ char* tWords[ 2 ];
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ if ( sttListedContact != NULL ) {
+ UrlDecode( tWords[1] );
+ if ( !strcmp( tWords[0], "PHH" )) {
+ MSN_SetString( sttListedContact, "Phone", tWords[1] );
+ sttListedContactMask |= 0x0001;
+ }
+ else if ( !strcmp( tWords[0], "PHW" )) {
+ MSN_SetString( sttListedContact, "CompanyPhone", tWords[1] );
+ sttListedContactMask |= 0x0002;
+ }
+ else if ( !strcmp( tWords[0], "PHM" )) {
+ MSN_SetString( sttListedContact, "Cellular", tWords[1] );
+ sttListedContactMask |= 0x0004;
+ }
+ else if ( !strcmp( tWords[0], "MOB" )) {
+ MSN_SetString( sttListedContact, "OnMobile", tWords[1] );
+ sttListedContactMask |= 0x0008;
+ }
+ else if ( !strcmp( tWords[0], "MBE" )) {
+ MSN_SetString( sttListedContact, "OnMsnMobile", tWords[1] );
+ sttListedContactMask |= 0x0010;
+ } }
+ break;
+ }
+ case ' EYB': //********* BYE: section 8.5 Session Participant Changes
+ {
+ union {
+ char* tWords[ 2 ];
+ // modified for chat, orginally param2 = junk
+ // param 2: quit due to idle = "1", normal quit = nothing
+ struct { char *userEmail, *isIdle; } data;
+ };
+
+ sttDivideWords( params, 2, tWords );
+ UrlDecode( data.userEmail );
+
+ if ( MSN_GetByte( "EnableSessionPopup", 0 ))
+ MSN_ShowPopup( data.userEmail, MSN_Translate( "Contact left channel" ), 0 );
+
+ // modified for chat
+ if ( msnHaveChatDll ) {
+ GCDEST gcd = {0};
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_QUIT;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof( GCEVENT );
+ gce.pDest = &gcd;
+ gce.pszNick = MSN_GetContactName( MSN_HContactFromEmail( data.userEmail, NULL, 1, 1 ));
+ gce.pszUID = data.userEmail;
+ gce.time = time( NULL );
+ gce.bIsMe = FALSE;
+ gce.bAddToLog = TRUE;
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+
+ // in here, the first contact is the chat ID, starting from the second will be actual contact
+ // if only 1 person left in conversation
+ int personleft = MSN_ContactLeft( info, MSN_HContactFromEmail( data.userEmail, NULL, 0, 0 ));
+ // see if the session is quit due to idleness
+ if ( personleft == 1 && !lstrcmpA( data.isIdle, "1" ) ) {
+ GCDEST gcd = {0};
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_INFORMATION;
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof( GCEVENT );
+ gce.pDest = &gcd;
+ gce.bIsMe = FALSE;
+ gce.time = time(NULL);
+ gce.bAddToLog = TRUE;
+ gce.pszText = Translate("This conversation has been inactive, participants will be removed.");
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ gce.pszText = Translate("To resume the conversation, please quit this session and start a new chat session.");
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+ else if ( personleft == 2 && lstrcmpA( data.isIdle, "1" ) ) {
+ if ( MessageBoxA( NULL, Translate( "There is only 1 person left in the chat, do you want to switch back to standard message window?"), Translate("MSN Chat"), MB_YESNO|MB_ICONQUESTION) == IDYES) {
+ // kill chat dlg and open srmm dialog
+ GCEVENT gce = {0};
+ GCDEST gcd = {0};
+ gce.cbSize = sizeof( GCEVENT );
+ gce.pDest = &gcd;
+
+ // a flag to let the kill function know what to do
+ // if the value is 1, then it'll open up the srmm window
+ info->mJoinedCount--;
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_CONTROL;
+ MSN_CallService( MS_GC_EVENT, WINDOW_OFFLINE, ( LPARAM )&gce );
+ MSN_CallService( MS_GC_EVENT, WINDOW_TERMINATE, ( LPARAM )&gce );
+ } }
+ // this is not in chat session, quit the session when everyone left
+ else if ( personleft == 0 )
+ return 1; // die
+
+ break;
+ }
+ case ' LAC': //********* CAL: section 8.3 Inviting Users to a Switchboard Session
+ break;
+
+ case ' GHC': //********* CHG: section 7.7 Client States
+ {
+ int oldMode = msnStatusMode;
+ msnStatusMode = MSNStatusToMiranda( params );
+
+ MSN_SendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS,( HANDLE )oldMode, msnStatusMode );
+ MSN_DebugLog( "Status change acknowledged: %s", params );
+ break;
+ }
+ case ' LHC': //********* CHL: Query from Server on MSNP7
+ {
+ char authChallengeInfo[ 30 ];
+ if ( sscanf( params, "%30s", authChallengeInfo ) < 1 )
+ goto LBL_InvalidCommand;
+
+ //Digest it
+ DWORD md5hash[ 4 ];
+ MD5_CTX context;
+ MD5Init(&context);
+ MD5Update(&context, ( BYTE* )authChallengeInfo, strlen( authChallengeInfo ));
+ MD5Update(&context, ( BYTE* )msnProtChallenge, strlen( msnProtChallenge ));
+ MD5Final(( BYTE* )md5hash, &context);
+
+ if ( MyOptions.UseMSNP11 ) {
+ LONGLONG hash1 = *( LONGLONG* )&md5hash[0], hash2 = *( LONGLONG* )&md5hash[2];
+ size_t i;
+ for ( i=0; i < 4; i++ )
+ md5hash[i] &= 0x7FFFFFFF;
+
+ char chlString[128];
+ _snprintf( chlString, sizeof( chlString ), "%s%s00000000", authChallengeInfo, msnProductID );
+ chlString[ (strlen(authChallengeInfo)+strlen(msnProductID)+7) & 0xF8 ] = 0;
+
+ LONGLONG high=0, low=0, bskey=0;
+ int* chlStringArray = ( int* )chlString;
+ for ( i=0; i < strlen( chlString )/4; i += 2) {
+ LONGLONG temp = chlStringArray[i];
+
+ temp = (0x0E79A9C1 * temp) % 0x7FFFFFFF;
+ temp += high;
+ temp = md5hash[0] * temp + md5hash[1];
+ temp = temp % 0x7FFFFFFF;
+
+ high = chlStringArray[i + 1];
+ high = (high + temp) % 0x7FFFFFFF;
+ high = md5hash[2] * high + md5hash[3];
+ high = high % 0x7FFFFFFF;
+
+ low = low + high + temp;
+ }
+ high = (high + md5hash[1]) % 0x7FFFFFFF;
+ low = (low + md5hash[3]) % 0x7FFFFFFF;
+
+ LONGLONG key = (low << 32) + high;
+ sttSwapInt64( &key );
+ sttSwapInt64( &hash1 );
+ sttSwapInt64( &hash2 );
+
+ info->sendPacket( "QRY", "%s 32\r\n%016I64x%016I64x", msnProductID, hash1 ^ key, hash2 ^ key );
+ }
+ else info->sendPacket( "QRY", "%s 32\r\n%08x%08x%08x%08x", msnProductID,
+ htonl( md5hash[0] ), htonl( md5hash[1] ), htonl( md5hash[2] ), htonl( md5hash[3] ));
+ break;
+ }
+ case ' RVC': //********* CVR: MSNP8
+ {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ));
+ info->sendPacket( "USR", "TWN I %s", tEmail );
+ break;
+ }
+ case ' NLF': //********* FLN: section 7.9 Notification Messages
+ { HANDLE hContact;
+ UrlDecode( params );
+ if (( hContact = MSN_HContactFromEmail( params, NULL, 0, 0 )) != NULL )
+ {
+ MSN_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ MsgQueue_Clear( hContact );
+ }
+ break;
+ }
+ case ' CTG': //********* GTC: section 7.6 List Retrieval And Property Management
+ break;
+
+ case ' FNI': //********* INF: section 7.2 Server Policy Information
+ {
+ char security1[ 10 ];
+ //can be more security packages on the end, comma delimited
+ if ( sscanf( params, "%9s", security1 ) < 1 )
+ goto LBL_InvalidCommand;
+
+ //SEND USR I packet, section 7.3 Authentication
+ if ( !strcmp( security1, "MD5" )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail )))
+ info->sendPacket( "USR", "MD5 I %s", tEmail );
+ else
+ info->sendPacket( "USR", "MD5 I " ); //this will fail, of course
+ }
+ else {
+ MSN_DebugLog( "Unknown security package '%s'", security1 );
+ if ( info->mType == SERVER_NOTIFICATION || info->mType == SERVER_DISPATCH ) {
+ MSN_SendBroadcast(NULL,ACKTYPE_LOGIN,ACKRESULT_FAILED,NULL,LOGINERR_WRONGPROTOCOL);
+ MSN_GoOffline();
+ }
+ return 1;
+ }
+ break;
+ }
+ case ' NLI':
+ case ' NLN': //********* ILN/NLN: section 7.9 Notification Messages
+ {
+ union {
+ char* tWords[ 5 ];
+ struct { char *userStatus, *userEmail, *userNick, *objid, *cmdstring; } data;
+ };
+
+ int tArgs = sttDivideWords( params, 5, tWords );
+ if ( tArgs < 3 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userEmail ); UrlDecode( data.userNick );
+
+ HANDLE hContact = MSN_HContactFromEmail( data.userEmail, NULL, 0, 0 );
+ if ( hContact != NULL) {
+ // is there an uninitialized switchboard for this contact?
+ ThreadData* T = MSN_GetUnconnectedThread( hContact );
+ if ( T != NULL )
+ if ( hContact == T->mInitialContact )
+ T->sendPacket( "CAL", "%s", data.userEmail );
+
+ MSN_SetStringUtf( hContact, "Nick", data.userNick );
+ MSN_SetWord( hContact, "Status", ( WORD )MSNStatusToMiranda( data.userStatus ));
+// DBDeleteContactSetting( hContact, "CList", "StatusMsg" );
+ }
+
+ MSN_SetString( hContact, "MirVer", "" );
+
+ if ( tArgs > 3 && tArgs <= 5 ) {
+ UrlDecode( data.cmdstring );
+ DWORD dwValue = ( DWORD )atol( data.objid );
+ MSN_SetDword( hContact, "FlagBits", dwValue );
+ if ( dwValue & 0x200 )
+ MSN_SetString( hContact, "MirVer", "Webmessenger" );
+ else if ( dwValue == 1342177280 )
+ MSN_SetString( hContact, "MirVer", "Miranda IM 0.5.x" );
+ else if ( dwValue == 805306404 )
+ MSN_SetString( hContact, "MirVer", "Miranda IM 0.4.x" );
+ else if (( dwValue & 0x60000000 ) == 0x60000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 8.x" );
+ else if (( dwValue & 0x50000000 ) == 0x50000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 7.5" );
+ else if ( dwValue & 0x40000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 7.0" );
+ else if (( dwValue & 0x30000000 ) == 0x30000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 6.2" );
+ else if ( dwValue & 0x20000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 6.1" );
+ else if ( dwValue & 0x10000000 )
+ MSN_SetString( hContact, "MirVer", "MSN 6.0" );
+ else
+ MSN_SetString( hContact, "MirVer", "MSN 4.x-5.x" );
+
+ if ( data.cmdstring[0] ) {
+ int temp_status = MSN_GetWord(hContact, "Status", ID_STATUS_OFFLINE);
+ if (temp_status == (WORD)ID_STATUS_OFFLINE)
+ MSN_SetWord( hContact, "Status", (WORD)ID_STATUS_INVISIBLE);
+ MSN_SetString( hContact, "PictContext", data.cmdstring );
+ if ( hContact != NULL ) {
+ char szSavedContext[ 256 ];
+ int result = MSN_GetStaticString( "PictSavedContext", hContact, szSavedContext, sizeof szSavedContext );
+ if ( result || strcmp( szSavedContext, data.cmdstring ))
+ MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } }
+ else {
+ DBDeleteContactSetting( hContact, msnProtocolName, "PictContext" );
+ DBDeleteContactSetting( hContact, msnProtocolName, "PictSavedContext" );
+ MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } }
+
+ break;
+ }
+ case ' ORI': //********* IRO: section 8.4 Getting Invited to a Switchboard Session
+ {
+ union {
+ char* tWords[ 4 ];
+ struct { char *strThisContact, *totalContacts, *userEmail, *userNick; } data;
+ };
+
+ if ( sttDivideWords( params, 4, tWords ) != 4 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userEmail );
+ UrlDecode( data.userNick );
+
+ MSN_ContactJoined( info, MSN_HContactFromEmail( data.userEmail, data.userNick, 1, 1 ));
+
+ int thisContact = atol( data.strThisContact );
+ if ( thisContact != 1 ) {
+ char* tContactName = MSN_GetContactName( info->mJoinedContacts[0] );
+ Utf8Decode( data.userNick );
+
+ char multichatmsg[256];
+ mir_snprintf( multichatmsg, sizeof( multichatmsg ),
+ MSN_Translate( "%s (%s) has joined the chat with %s" ),
+ data.userNick, data.userEmail, tContactName );
+
+ MSN_ShowPopup( tContactName, multichatmsg, MSN_ALLOW_MSGBOX );
+ }
+
+ // only start the chat session after all the IRO messages has been recieved
+ if ( msnHaveChatDll && info->mJoinedCount > 1 && !lstrcmpA(data.strThisContact, data.totalContacts) ) {
+ if ( info->mChatID[0] == 0 )
+ MSN_ChatStart(info);
+ }
+
+ break;
+ }
+ case ' IOJ': //********* JOI: section 8.5 Session Participant Changes
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *userEmail, *userNick; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userEmail ); UrlDecode( data.userNick );
+ HANDLE hContact = MSN_HContactFromEmail( data.userEmail, data.userNick, 1, 1 );
+
+ Utf8Decode( data.userNick );
+ MSN_DebugLog( "New contact in channel %s %s", data.userEmail, data.userNick );
+
+ info->mInitialContact = NULL;
+ info->mMessageCount = 0;
+
+ if ( MSN_ContactJoined( info, hContact ) == 1 ) {
+ MsgQueueEntry E;
+ if ( MsgQueue_GetNext( hContact, E ) != 0 ) {
+ do {
+ if ( E.msgSize == 0 ) {
+ info->sendMessage( E.msgType, E.message, E.flags );
+ MSN_SendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )E.seq, 0 );
+ }
+ else info->sendRawMessage( E.msgType, E.message, E.msgSize );
+
+ free( E.message );
+
+ if ( E.ft != NULL ) {
+ info->mMsnFtp = E.ft;
+ info->mMsnFtp->mOwnsThread = true;
+ }
+ }
+ while (MsgQueue_GetNext( hContact, E ) != 0 );
+
+ if ( MSN_GetByte( "EnableDeliveryPopup", 1 ))
+ MSN_ShowPopup( MSN_GetContactName( hContact ), MSN_Translate( "First message delivered" ), 0 );
+ } }
+ else {
+ char* tContactName = MSN_GetContactName( info->mJoinedContacts[0] );
+
+ char multichatmsg[ 256 ];
+ mir_snprintf(
+ multichatmsg, sizeof( multichatmsg ),
+ MSN_Translate( "%s (%s) has joined the chat with %s" ),
+ data.userNick, data.userEmail, tContactName );
+
+ MSN_ShowPopup( tContactName, multichatmsg, MSN_ALLOW_MSGBOX );
+
+ if ( msnHaveChatDll ) {
+ GCDEST gcd = {0};
+ GCEVENT gce = {0};
+
+ gcd.pszModule = msnProtocolName;
+ gcd.pszID = info->mChatID;
+ gcd.iType = GC_EVENT_JOIN;
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszNick = MSN_GetContactName( MSN_HContactFromEmail( data.userEmail, NULL, 1, 1 ));
+ gce.pszUID = data.userEmail;
+ gce.pszStatus = Translate( "Others" );
+ gce.time = time(NULL);
+ gce.bIsMe = FALSE;
+ gce.bAddToLog = TRUE;
+ MSN_CallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ } }
+ return 0;
+ }
+
+ case ' GSL': //********* LSG: lists existing groups
+ if ( !sttAddGroup( params, true ))
+ goto LBL_InvalidCommand;
+ break;
+
+ case ' TSL': //********* LST: section 7.6 List Retrieval And Property Management
+ {
+ int listId;
+ char *userEmail = NULL, *userNick = NULL, *userId = NULL, *groupId = NULL;
+
+ union {
+ char* tWords[ 10 ];
+ struct { char *userEmail, *userNick, *list, *groupid; } data;
+ };
+
+ int tNumTokens = sttDivideWords( params, 10, tWords );
+
+ if ( --sttListNumber == 0 )
+ MSN_SetServerStatus( msnDesiredStatus );
+
+ for ( int i=0; i < tNumTokens; i++ ) {
+ char* p = tWords[ i ];
+ if ( *p == 'N' && p[1] == '=' )
+ userEmail = p+2;
+ else if ( *p == 'F' && p[1] == '=' )
+ userNick = p+2;
+ else if ( *p == 'C' && p[1] == '=' )
+ userId = p+2;
+ else {
+ listId = atol( p );
+ if ( i < tNumTokens-1 )
+ groupId = tWords[i+1];
+ break;
+ } }
+
+ if ( userEmail == NULL )
+ goto LBL_InvalidCommand;
+
+ if ( userNick == NULL )
+ userNick = userEmail;
+
+ UrlDecode( userEmail ); UrlDecode( userNick );
+
+ if ( !IsValidListCode( listId ) || !strcmp( userEmail, "messenger@microsoft.com" ))
+ break;
+
+ // add user if it wasn't included into a contact list
+ sttProcessListedContactMask();
+ sttListedContact = MSN_HContactFromEmail( userEmail, userNick, 1, 0 );
+
+ Utf8Decode( userNick );
+ Lists_Add( listId, userEmail, userNick );
+
+ if (( listId & ( LIST_AL + LIST_BL + LIST_FL )) == LIST_BL ) {
+ DBDeleteContactSetting( sttListedContact, "CList", "NotOnList" );
+ DBWriteContactSettingByte( sttListedContact, "CList", "Hidden", 1 );
+ }
+
+ if ( listId & LIST_PL ) {
+ if ( !Lists_IsInList( LIST_RL, userEmail )) {
+ MSN_AddUser( sttListedContact, userEmail, LIST_PL + LIST_REMOVE );
+ MSN_AddUser( sttListedContact, userEmail, LIST_RL );
+ }
+
+ if (( listId & ( LIST_AL + LIST_BL + LIST_FL )) == 0 )
+ MSN_AddAuthRequest( sttListedContact, userEmail, userNick );
+ }
+
+ if ( listId & ( LIST_BL | LIST_AL )) {
+ WORD tApparentMode = MSN_GetWord( sttListedContact, "ApparentMode", 0 );
+ if (( listId & LIST_BL ) && tApparentMode == 0 )
+ MSN_SetWord( sttListedContact, "ApparentMode", ID_STATUS_OFFLINE );
+ else if (( listId & LIST_AL ) && tApparentMode != 0 )
+ MSN_SetWord( sttListedContact, "ApparentMode", 0 );
+ }
+
+ if ( sttListedContact != NULL ) {
+ if ( userId != NULL )
+ MSN_SetString( sttListedContact, "ID", userId );
+
+ if ( MyOptions.ManageServer ) {
+ if ( groupId != NULL ) {
+ char* p = strchr( groupId, ',' );
+ if ( p != NULL )
+ *p = 0;
+
+ MSN_SetString( sttListedContact, "GroupID", groupId );
+
+ if (( p = ( char* )MSN_GetGroupById( groupId )) != NULL ) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingStringUtf( sttListedContact, "CList", "Group", &dbv )) {
+ if ( strcmp( dbv.pszVal, p ))
+ DBWriteContactSettingStringUtf( sttListedContact, "CList", "Group", p );
+ MSN_FreeVariant( &dbv );
+ }
+ else DBWriteContactSettingStringUtf( sttListedContact, "CList", "Group", p );
+ } }
+ else {
+ DBDeleteContactSetting( sttListedContact, "CList", "Group" );
+ DBDeleteContactSetting( sttListedContact, msnProtocolName, "GroupID" );
+ } } }
+ break;
+ }
+ case ' GSM': //********* MSG: sections 8.7 Instant Messages, 8.8 Receiving an Instant Message
+ MSN_ReceiveMessage( info, cmdString, params );
+ break;
+
+ case ' KAN': //********* NAK: section 8.7 Instant Messages
+ MSN_DebugLog( "Message send failed (trid=%d)", trid );
+ break;
+
+ case ' TON': //********* NOT: notification message
+ {
+ char* buffer = ( char* )alloca( trid+1 );
+ BYTE* p = HReadBuffer( info ).surelyRead( trid );
+ if ( p != NULL ) {
+ memcpy( buffer, p, trid );
+ buffer[ trid ] = 0;
+ }
+ else buffer[0] = 0;
+
+ MSN_DebugLog( "Notification message: %s", buffer );
+ break;
+ }
+ case ' TUO': //********* OUT: sections 7.10 Connection Close, 8.6 Leaving a Switchboard Session
+ if ( !stricmp( params, "OTH" )) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION );
+ MSN_DebugLog( "You have been disconnected from the MSN server because you logged on from another location using the same MSN passport." );
+ }
+
+ if ( !stricmp( params, "MIG" )) // ignore it
+ break;
+
+ return 1;
+
+ case ' PRP': //********* PRP: user property
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *name, *value; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.value );
+ if ( !stricmp( data.name, "MFN" ))
+ if ( !sttIsSync || !MSN_GetByte( "NeverUpdateNickname", 0 ))
+ MSN_SetStringUtf( NULL, "Nick", data.value );
+ break;
+ }
+ case ' YRQ': //********* QRY:
+ sttProcessListedContactMask();
+ break;
+
+ case ' GNQ': //********* QNG: reply to PNG
+ msnPingTimeoutCurrent = msnPingTimeout = trid;
+ if ( msnGetInfoContact != NULL ) {
+ MSN_SendBroadcast( msnGetInfoContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE )1, 0 );
+ msnGetInfoContact = NULL;
+ }
+ break;
+
+ case ' GER': //********* REG: rename group
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *id, *groupName; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.groupName );
+ MSN_SetGroupName( data.id, data.groupName );
+ break;
+ }
+ case ' MER': //********* REM: section 7.8 List Modifications
+ {
+ union {
+ char* tWords[ 3 ];
+ struct { char *list, *serial, *groupId; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) == 3 ) { // remove from a group
+ HANDLE hContact = MSN_HContactById( data.serial );
+ if ( hContact != NULL )
+ DBDeleteContactSetting( hContact, msnProtocolName, "GroupID" );
+ }
+ else { // remove a user from a list
+ int listId = Lists_NameToCode( data.list );
+ if ( IsValidListCode( listId )) {
+ if ( listId == LIST_FL ) {
+ HANDLE hContact = MSN_HContactById( data.serial );
+ if ( hContact != NULL ) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof tEmail ))
+ Lists_Remove( listId, tEmail );
+ } }
+ else {
+ UrlDecode( data.serial );
+ Lists_Remove( listId, data.serial );
+ } } }
+ break;
+ }
+ case ' GMR': //********* RMG: remove a group
+ {
+ MSN_DeleteGroup( params );
+ break;
+ }
+ case ' GNR': //********* RNG: section 8.4 Getting Invited to a Switchboard Session
+ //note: unusual message encoding: trid==sessionid
+ {
+ union {
+ char* tWords[ 5 ];
+ struct { char *newServer, *security, *authChallengeInfo, *callerEmail, *callerNick; } data;
+ };
+
+ if ( sttDivideWords( params, 5, tWords ) != 5 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.newServer ); UrlDecode( data.callerEmail );
+ UrlDecode( data.callerNick ); Utf8Decode( data.callerNick );
+
+ if ( strcmp( data.security, "CKI" )) {
+ MSN_DebugLog( "Unknown security package in RNG command: %s", data.security );
+ break;
+ }
+
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, data.newServer );
+ newThread->mType = SERVER_SWITCHBOARD;
+ MSN_ContactJoined( newThread, MSN_HContactFromEmail( data.callerEmail, data.callerNick, false, true ));
+ mir_snprintf( newThread->mCookie, sizeof( newThread->mCookie ), "%s %d", data.authChallengeInfo, trid );
+
+ MSN_DebugLog( "Opening caller's switchboard server '%s'...", data.newServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ break;
+ }
+ case ' PBS': //********* SBP: Server Property was changed
+ break;
+
+ case ' NYS': //********* SYN: section 7.5 Client User Property Synchronization
+ {
+ char* tWords[ 4 ];
+ if ( sttDivideWords( params, 4, tWords ) != 4 )
+ goto LBL_InvalidCommand;
+
+ Lists_Wipe();
+ sttIsSync = true;
+ if (( sttListNumber = atol( tWords[ 2 ] )) == 0 )
+ MSN_SetServerStatus( msnDesiredStatus );
+
+ sttListedContact = NULL;
+ tridUrlInbox = msnNsThread->sendPacket( "URL", "INBOX" );
+ tridUrlEdit = msnNsThread->sendPacket( "URL", "PROFILE 0x%04x", GetUserDefaultLCID() );
+ break;
+ }
+ case ' XBU': // UBX : MSNP11+ User Status Message
+ {
+ union {
+ char* tWords[ 2 ];
+ struct { char *email, *datalen; } data;
+ };
+
+ if ( sttDivideWords( params, 2, tWords ) != 2 )
+ goto LBL_InvalidCommand;
+
+ HANDLE hContact = MSN_HContactFromEmail( data.email, data.email, 0, 0 );
+ if ( hContact == NULL )
+ break;
+
+ int len = atol( data.datalen );
+ if ( len < 0 || len > 4000 )
+ goto LBL_InvalidCommand;
+
+ char* dataBuf = ( char* )alloca( len+1 ), *p = dataBuf;
+ BYTE* buff = HReadBuffer( info, 0 ).surelyRead( len );
+ if ( buff != NULL ) {
+ memcpy( dataBuf, buff, len );
+ dataBuf[ len ] = 0;
+ }
+ else dataBuf[0] = 0;
+
+ p = strstr( dataBuf, "<PSM>" );
+ if ( p ) {
+ p += 5;
+ char* p1 = strstr( p, "</PSM>" );
+ if ( p1 ) {
+ *p1 = 0;
+ if ( *p != 0 ) {
+ HtmlDecode( p );
+ DBWriteContactSettingStringUtf( hContact, "CList", "StatusMsg", p );
+ }
+ else DBDeleteContactSetting( hContact, "CList", "StatusMsg" );
+ } }
+ break;
+ }
+ case ' LRU':
+ {
+ union {
+ char* tWords[ 3 ];
+ struct { char *rru, *passport, *urlID; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 )
+ goto LBL_InvalidCommand;
+
+ if ( trid == tridUrlInbox ) {
+ replaceStr( passport, data.passport );
+ replaceStr( rru, data.rru );
+ tridUrlInbox = -1;
+ }
+ else if ( trid == tridUrlEdit ) {
+ replaceStr( profileURL, data.rru );
+ tridUrlEdit = -1;
+ }
+ break;
+ }
+ case ' RSU': //********* USR: sections 7.3 Authentication, 8.2 Switchboard Connections and Authentication
+ if ( info->mType == SERVER_SWITCHBOARD ) { //(section 8.2)
+ union {
+ char* tWords[ 3 ];
+ struct { char *status, *userHandle, *friendlyName; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 )
+ goto LBL_InvalidCommand;
+
+ UrlDecode( data.userHandle ); UrlDecode( data.friendlyName );
+ Utf8Decode( data.friendlyName );
+
+ if ( strcmp( data.status, "OK" )) {
+ MSN_DebugLog( "Unknown status to USR command (SB): '%s'", data.status );
+ break;
+ }
+
+ HANDLE hContact = MsgQueue_GetNextRecipient();
+ if ( hContact == NULL ) { //can happen if both parties send first message at the same time
+ MSN_DebugLog( "USR (SB) internal: thread created for no reason" );
+ info->sendPacket( "OUT", NULL );
+ break;
+ }
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail ))) {
+ MSN_DebugLog( "USR (SB) internal: Contact is not MSN" );
+ info->sendPacket( "OUT", NULL );
+ break;
+ }
+
+ info->mInitialContact = hContact;
+ info->sendPacket( "CAL", "%s", tEmail );
+ }
+ else //dispatch or notification server (section 7.3)
+ {
+ union {
+ char* tWords[ 3 ];
+ struct { char *security, *sequence, *authChallengeInfo; } data;
+ };
+
+ if ( sttDivideWords( params, 3, tWords ) != 3 )
+ goto LBL_InvalidCommand;
+
+ if ( !strcmp( data.security, "TWN" )) {
+ char* tAuth;
+ if ( MSN_GetPassportAuth( data.authChallengeInfo, tAuth )) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ MSN_GoOffline();
+ return 1;
+ }
+
+ info->sendPacket( "USR", "TWN S %s", tAuth );
+ free( tAuth );
+ }
+ else if ( !strcmp( data.security, "OK" )) {
+ UrlDecode( tWords[1] ); UrlDecode( tWords[2] );
+
+ if ( MSN_GetByte( "NeverUpdateNickname", 0 )) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ MSN_SendNicknameT( dbv.ptszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ }
+ else MSN_SetStringUtf( NULL, "Nick", tWords[2] );
+
+ msnLoggedIn = true;
+ sttListNumber = 0;
+ info->sendPacket( "SYN", "0 0" );
+ }
+ else {
+ MSN_DebugLog( "Unknown security package '%s'", data.security );
+
+ if ( info->mType == SERVER_NOTIFICATION || info->mType == SERVER_DISPATCH ) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL );
+ MSN_GoOffline();
+ }
+
+ return 1;
+ } }
+ break;
+
+ case ' XUU': // UUX: MSNP11 addition
+ break;
+
+ case ' REV': //******** VER: section 7.1 Protocol Versioning
+ {
+ char protocol1[ 7 ];
+ if ( sscanf( params, "%6s", protocol1 ) < 1 )
+ goto LBL_InvalidCommand;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ))) {
+ MSN_ShowError( "You must specify your e-mail in Options/Network/MSN" );
+ return 1;
+ }
+
+ if ( !strcmp( protocol1, "MSNP10" )) {
+ info->sendPacket( "CVR","0x0409 winnt 5.1 i386 MSNMSGR 6.2.0205 MSMSGS %s", tEmail );
+ msnProtChallenge = "Q1P7W2E4J9R8U3S5";
+ msnProductID = "msmsgs@msnmsgr.com";
+ }
+ else if ( !strcmp( protocol1, "MSNP11" )) {
+ info->sendPacket( "CVR","0x0409 winnt 5.1 i386 MSNMSGR 7.5.0311 MSMSGS %s", tEmail );
+ msnProtChallenge = "YMM8C_H7KCQ2S_KL";
+ msnProductID = "PROD0090YUAUV{2B";
+ }
+ else {
+ MSN_ShowError( "Server has requested an unknown protocol set (%s)", params );
+
+ if ( info->mType == SERVER_NOTIFICATION || info->mType == SERVER_DISPATCH ) {
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL );
+ MSN_GoOffline();
+ }
+
+ return 1;
+ }
+ break;
+ }
+ case ' RFX': //******** XFR: sections 7.4 Referral, 8.1 Referral to Switchboard
+ {
+ union {
+ char* tWords[ 4 ];
+ struct { char *type, *newServer, *security, *authChallengeInfo; } data;
+ };
+
+ int numWords = sttDivideWords( params, 4, tWords );
+ if ( numWords < 2 )
+ goto LBL_InvalidCommand;
+
+ if ( !strcmp( data.type, "NS" )) { //notification server
+ UrlDecode( data.newServer );
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, data.newServer );
+ newThread->mType = SERVER_NOTIFICATION;
+ newThread->mTrid = info->mTrid;
+ newThread->mIsMainThread = true;
+ info->mIsMainThread = false;
+
+ MSN_DebugLog( "Switching to notification server '%s'...", data.newServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ return 1; //kill the old thread
+ }
+
+ if ( !strcmp( data.type, "SB" )) { //switchboard server
+ UrlDecode( data.newServer );
+
+ if ( numWords < 4 )
+ goto LBL_InvalidCommand;
+
+ if ( strcmp( data.security, "CKI" )) {
+ MSN_DebugLog( "Unknown XFR SB security package '%s'", data.security );
+ break;
+ }
+
+ ThreadData* newThread = new ThreadData;
+ strcpy( newThread->mServer, data.newServer );
+ newThread->mType = SERVER_SWITCHBOARD;
+ newThread->mCaller = 1;
+ strcpy( newThread->mCookie, data.authChallengeInfo );
+
+ MSN_DebugLog( "Opening switchboard server '%s'...", data.newServer );
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ }
+ else MSN_DebugLog( "Unknown referral server: %s", data.type );
+ break;
+ }
+
+ default:
+ MSN_DebugLog( "Unrecognised message: %s", cmdString );
+ break;
+ }
+
+ info->mMessageCount++;
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_contact.cpp b/miranda-wine/protocols/MSN/msn_contact.cpp
new file mode 100644
index 0000000..af19333
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_contact.cpp
@@ -0,0 +1,74 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+HANDLE __stdcall MSN_HContactFromEmail( const char* msnEmail, const char* msnNick, int addIfNeeded, int temporary )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO,( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !strcmp( msnProtocolName, szProto )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail )))
+ if ( !strcmpi( msnEmail, tEmail ))
+ return hContact;
+ }
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
+ }
+
+ if ( addIfNeeded )
+ {
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_ADD, 0, 0 );
+ MSN_CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact, ( LPARAM )msnProtocolName );
+ MSN_SetString( hContact, "e-mail", msnEmail );
+ MSN_SetStringUtf( hContact, "Nick", ( char* )msnNick );
+ if ( temporary )
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+
+ return hContact;
+ }
+
+ return NULL;
+}
+
+HANDLE __stdcall MSN_HContactById( const char* szGuid )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO,( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !strcmp( msnProtocolName, szProto )) {
+ char tId[ 100 ];
+ if ( !MSN_GetStaticString( "ID", hContact, tId, sizeof tId ))
+ if ( !strcmpi( szGuid, tId ))
+ return hContact;
+ }
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
+ }
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/MSN/msn_errors.cpp b/miranda-wine/protocols/MSN/msn_errors.cpp
new file mode 100644
index 0000000..af6c674
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_errors.cpp
@@ -0,0 +1,95 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+extern int tridUrlInbox, tridUrlEdit;
+
+int MSN_HandleErrors( ThreadData* info, char* cmdString )
+{
+ int errorCode, packetID = -1;
+ sscanf( cmdString, "%d %d", &errorCode, &packetID );
+
+ if ( packetID == msnSearchID )
+ {
+ MSN_SendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)msnSearchID, 0 );
+ msnSearchID = -1;
+ }
+
+ MSN_DebugLog( "Server error:%s", cmdString );
+
+ switch( errorCode ) {
+ case ERR_INTERNAL_SERVER:
+ MSN_ShowError( "MSN Services are temporarily unavailable, please try to connect later" );
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
+ return 1;
+
+ case ERR_SERVER_UNAVAILABLE:
+ MSN_ShowError( "MSN Services are too busy, please try to connect later" );
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
+ return 1;
+
+ case ERR_NOT_ALLOWED_WHEN_OFFLINE:
+ MSN_ShowError( "MSN protocol does not allow you to communicate with others when you are invisible" );
+ return 0;
+
+ case ERR_LIST_FULL:
+ MSN_ShowError( "MSN plugin cannot add a new contact because the contact list is full" );
+ return 0;
+
+ case ERR_ALREADY_THERE:
+ MSN_ShowError( "User is already in your contact list" );
+ return 0;
+
+ case ERR_NOT_EXPECTED:
+ MSN_ShowError( "Your MSN account e-mail is unverified. Goto http://www.passport.com and verify the primary e-mail first" );
+ return 0;
+
+ case ERR_AUTHENTICATION_FAILED:
+ if ( info->mType != SERVER_SWITCHBOARD ) {
+ MSN_ShowError( "Your username or password is incorrect" );
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ }
+ return 1;
+
+ case 710:
+ if ( packetID == tridUrlInbox ) {
+ tridUrlInbox = -1;
+ return 0;
+ }
+
+ if ( packetID == tridUrlEdit ) {
+ tridUrlEdit = -1;
+ return 0;
+ }
+ // fall through
+
+ default:
+ MSN_DebugLog( "Unprocessed error: %s", cmdString );
+ if ( errorCode >= 500 ) //all these errors look fatal-ish
+ MSN_ShowError( "Unrecognised error %d. The server has closed our connection", errorCode );
+
+ break;
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_ftold.cpp b/miranda-wine/protocols/MSN/msn_ftold.cpp
new file mode 100644
index 0000000..24f6d82
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_ftold.cpp
@@ -0,0 +1,347 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <io.h>
+
+int MSN_HandleCommands(ThreadData *info,char *cmdString);
+int MSN_HandleErrors(ThreadData *info,char *cmdString);
+
+void msnftp_sendAcceptReject( filetransfer *ft, bool acc )
+{
+ ThreadData* thread = MSN_GetThreadByContact( ft->std.hContact );
+ if ( thread == NULL ) return;
+
+ if ( acc )
+ {
+ thread->sendPacket( "MSG",
+ "U %d\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: ACCEPT\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Launch-Application: FALSE\r\n"
+ "Request-Data: IP-Address:\r\n\r\n",
+ 172+4+strlen( ft->szInvcookie ), ft->szInvcookie );
+ }
+ else
+ {
+ thread->sendPacket( "MSG",
+ "U %d\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: CANCEL\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "Cancel-Code: REJECT\r\n\r\n",
+ 172-33+4+strlen( ft->szInvcookie ), ft->szInvcookie );
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN File Transfer Protocol commands processing
+
+int MSN_HandleMSNFTP( ThreadData *info, char *cmdString )
+{
+ char* params = "";
+ filetransfer* ft = info->mMsnFtp;
+
+ if ( cmdString[ 3 ] )
+ params = cmdString+4;
+
+ switch((*(PDWORD)cmdString&0x00FFFFFF)|0x20000000)
+ {
+ case ' EYB': //********* BYE
+ {
+ ft->complete();
+ return 1;
+ }
+ case ' LIF': //********* FIL
+ {
+ char filesize[ 30 ];
+ if ( sscanf( params, "%s", filesize ) < 1 )
+ goto LBL_InvalidCommand;
+
+ info->mCaller = 1;
+ info->send( "TFR\r\n", 5 );
+ break;
+ }
+ case ' RFT': //********* TFR
+ {
+ char* sendpacket = ( char* )alloca( 2048 );
+ filetransfer* ft = info->mMsnFtp;
+
+ info->mCaller = 3;
+
+ while( ft->std.currentFileProgress < ft->std.currentFileSize )
+ {
+ if ( ft->bCanceled ) {
+ sendpacket[0] = 0x01;
+ sendpacket[1] = 0x00;
+ sendpacket[2] = 0x00;
+ info->send( sendpacket, 3 );
+ return 0;
+ }
+
+ int wPlace = 0;
+ sendpacket[ wPlace++ ] = 0x00;
+ int packetLen = ft->std.currentFileSize - ft->std.currentFileProgress;
+ if ( packetLen > 2045 )
+ packetLen = 2045;
+
+ sendpacket[ wPlace++ ] = packetLen & 0x00ff;
+ sendpacket[ wPlace++ ] = ( packetLen & 0xff00 ) >> 8;
+ _read( ft->fileId, &sendpacket[wPlace], packetLen );
+
+ info->send( &sendpacket[0], packetLen+3 );
+
+ ft->std.totalProgress += packetLen;
+ ft->std.currentFileProgress += packetLen;
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+ }
+
+ ft->complete();
+ break;
+ }
+ case ' RSU': //********* USR
+ {
+ char email[130],authcookie[14];
+ if ( sscanf(params,"%129s %13s",email,authcookie) < 2 )
+ {
+ MSN_DebugLog( "Invalid USR OK command, ignoring" );
+ break;
+ }
+
+ char tCommand[ 30 ];
+ mir_snprintf( tCommand, sizeof( tCommand ), "FIL %i\r\n", info->mMsnFtp->std.totalBytes );
+ info->send( tCommand, strlen( tCommand ));
+ break;
+ }
+ case ' REV': //********* VER
+ {
+ char protocol1[ 7 ];
+ if ( sscanf( params, "%6s", protocol1 ) < 1 )
+ {
+LBL_InvalidCommand:
+ MSN_DebugLog( "Invalid %.3s command, ignoring", cmdString );
+ break;
+ }
+
+ if ( strcmp( protocol1, "MSNFTP" ) != 0 )
+ {
+ int tempInt;
+ int tFieldCount = sscanf( params, "%d %6s", &tempInt, protocol1 );
+ if ( tFieldCount != 2 || strcmp( protocol1, "MSNFTP" ) != 0 )
+ {
+ MSN_DebugLog( "Another side requested the unknown protocol (%s), closing thread", params );
+ return 1;
+ } }
+
+ { DBVARIANT dbv;
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "e-mail", &dbv ))
+ {
+ if ( info->mCaller == 0 ) //receive
+ {
+ char tCommand[ MSN_MAX_EMAIL_LEN + 50 ];
+ mir_snprintf( tCommand, sizeof( tCommand ), "USR %s %s\r\n", dbv.pszVal, info->mCookie );
+ info->send( tCommand, strlen( tCommand ));
+ }
+ else if ( info->mCaller == 2 ) //send
+ {
+ static char sttCommand[] = "VER MSNFTP\r\n";
+ info->send( sttCommand, strlen( sttCommand ));
+ }
+
+ MSN_FreeVariant( &dbv );
+ } }
+ break;
+ }
+ default: // receiving file
+ {
+ HReadBuffer tBuf( info, int( cmdString - info->mData ));
+
+ while ( true )
+ {
+ if ( ft->bCanceled )
+ { info->send( "CCL\r\n", 5 );
+ ft->close();
+ return 1;
+ }
+
+ BYTE* p = tBuf.surelyRead( 3 );
+ if ( p == NULL ) {
+LBL_Error: ft->close();
+ MSN_ShowError( "file transfer is canceled by remote host" );
+ return 1;
+ }
+
+ BYTE tIsTransitionFinished = *p++;
+ WORD dataLen = *p++;
+ dataLen |= (*p++ << 8);
+
+ if ( tIsTransitionFinished ) {
+LBL_Success:
+ static char sttCommand[] = "BYE 16777989\r\n";
+ info->send( sttCommand, strlen( sttCommand ));
+ return 1;
+ }
+
+ p = tBuf.surelyRead( dataLen );
+ if ( p == NULL )
+ goto LBL_Error;
+
+ _write( ft->fileId, p, dataLen );
+ ft->std.totalProgress += dataLen;
+ ft->std.currentFileProgress += dataLen;
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+
+ if ( ft->std.currentFileProgress == ft->std.totalBytes ) {
+ ft->complete();
+ goto LBL_Success;
+ } } } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// ft_startFileSend - sends a file using the old f/t protocol
+
+static void __cdecl sttSendFileThread( ThreadData* info )
+{
+ MSN_DebugLog( "Waiting for an incoming connection to '%s'...", info->mServer );
+
+ filetransfer* ft = info->mMsnFtp;
+
+ switch( WaitForSingleObject( ft->hWaitEvent, 60000 )) {
+ case WAIT_TIMEOUT:
+ case WAIT_FAILED:
+ MSN_DebugLog( "Incoming connection timed out, closing file transfer" );
+ return;
+ }
+
+ info->mBytesInData = 0;
+
+ while ( TRUE ) {
+ int recvResult = info->recv( info->mData+info->mBytesInData, 1000 - info->mBytesInData );
+ if ( recvResult == SOCKET_ERROR || !recvResult )
+ break;
+
+ info->mBytesInData += recvResult;
+
+ //pull off each line for parsing
+ if ( info->mCaller == 3 && info->mType == SERVER_FILETRANS ) {
+ if ( MSN_HandleMSNFTP( info, info->mData ))
+ break;
+ }
+ else { // info->mType!=SERVER_FILETRANS
+ while ( TRUE ) {
+ char* peol = strchr(info->mData,'\r');
+ if ( peol == NULL )
+ break;
+
+ if ( info->mBytesInData < peol - info->mData + 2 )
+ break; //wait for full line end
+
+ char msg[ sizeof(info->mData) ];
+ memcpy( msg, info->mData, peol - info->mData ); msg[ peol - info->mData ] = 0;
+ if ( *++peol != '\n' )
+ MSN_DebugLog( "Dodgy line ending to command: ignoring" );
+ else
+ peol++;
+
+ info->mBytesInData -= peol - info->mData;
+ memmove( info->mData, peol, info->mBytesInData );
+
+ MSN_DebugLog( "RECV:%s", msg );
+
+ if ( !isalnum(msg[0]) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' ')) {
+ MSN_DebugLog( "Invalid command name");
+ continue;
+ }
+
+ if ( MSN_HandleMSNFTP( info, msg ))
+ break;
+ } }
+
+ if ( info->mBytesInData == sizeof( info->mData )) {
+ MSN_DebugLog( "sizeof(data) is too small: the longest line won't fit" );
+ break;
+ } }
+
+ MSN_DebugLog( "Closing file transfer thread" );
+}
+
+void ft_startFileSend( ThreadData* info, const char* Invcommand, const char* Invcookie )
+{
+ if ( strcmpi( Invcommand,"ACCEPT" ))
+ return;
+
+ bool bHasError = false;
+ NETLIBBIND nlb = {0};
+ char ipaddr[256];
+
+ filetransfer* ft = info->mMsnFtp; info->mMsnFtp = NULL;
+ if ( ft != NULL ) {
+ if ( MSN_GetMyHostAsString( ipaddr, sizeof ipaddr ))
+ bHasError = true;
+ else {
+ nlb.cbSize = sizeof nlb;
+ nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ if (( ft->mIncomingBoundPort = ( HANDLE )MSN_CallService( MS_NETLIB_BINDPORT, ( WPARAM )hNetlibUser, ( LPARAM )&nlb)) == NULL ) {
+ MSN_DebugLog( "Unable to bind the port for incoming transfers" );
+ bHasError = true;
+ }
+ else ft->mIncomingPort = nlb.wPort;
+ } }
+ else bHasError = true;
+
+ char command[ 1024 ];
+ int nBytes = mir_snprintf( command, sizeof( command ),
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Invitation-Command: %s\r\n"
+ "Invitation-Cookie: %s\r\n"
+ "IP-Address: %s\r\n"
+ "Port: %i\r\n"
+ "AuthCookie: %i\r\n"
+ "Launch-Application: FALSE\r\n"
+ "Request-Data: IP-Address:\r\n\r\n",
+ ( bHasError ) ? "CANCEL" : "ACCEPT",
+ Invcookie, ipaddr, nlb.wExPort, WORD((( double )rand() / ( double )RAND_MAX ) * 4294967295 ));
+ info->sendPacket( "MSG", "N %d\r\n%s", nBytes, command );
+
+ if ( bHasError ) {
+ delete ft;
+ return;
+ }
+
+ ft->hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_FILETRANS;
+ newThread->mCaller = 2;
+ newThread->mMsnFtp = ft;
+ newThread->startThread(( pThreadFunc )sttSendFileThread );
+}
diff --git a/miranda-wine/protocols/MSN/msn_global.h b/miranda-wine/protocols/MSN/msn_global.h
new file mode 100644
index 0000000..9e7e894
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_global.h
@@ -0,0 +1,641 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 <malloc.h>
+
+#if defined(UNICODE) && !defined(_UNICODE)
+ #define _UNICODE
+#endif
+
+#ifdef _DEBUG
+ #define _CRTDBG_MAP_ALLOC
+ #include <stdlib.h>
+ #include <crtdbg.h>
+#endif
+
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+#include <commctrl.h>
+
+#include <process.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <newpluginapi.h>
+
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_message.h>
+#include <m_options.h>
+#include <m_png.h>
+#include <m_protocols.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <m_system.h>
+#include <m_userinfo.h>
+#include <m_utils.h>
+#include <win2k.h>
+
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_netlib.h>
+#include <m_popup.h>
+
+#include "SDK/m_chat.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN error codes
+
+#define ERR_SYNTAX_ERROR 200
+#define ERR_INVALID_PARAMETER 201
+#define ERR_INVALID_USER 205
+#define ERR_FQDN_MISSING 206
+#define ERR_ALREADY_LOGIN 207
+#define ERR_INVALID_USERNAME 208
+#define ERR_INVALID_FRIENDLY_NAME 209
+#define ERR_LIST_FULL 210
+#define ERR_ALREADY_THERE 215
+#define ERR_NOT_ON_LIST 216
+#define ERR_ALREADY_IN_THE_MODE 218
+#define ERR_ALREADY_IN_OPPOSITE_LIST 219
+#define ERR_SWITCHBOARD_FAILED 280
+#define ERR_NOTIFY_XFR_FAILED 281
+#define ERR_REQUIRED_FIELDS_MISSING 300
+#define ERR_NOT_LOGGED_IN 302
+#define ERR_INTERNAL_SERVER 500
+#define ERR_DB_SERVER 501
+#define ERR_FILE_OPERATION 510
+#define ERR_MEMORY_ALLOC 520
+#define ERR_SERVER_BUSY 600
+#define ERR_SERVER_UNAVAILABLE 601
+#define ERR_PEER_NS_DOWN 602
+#define ERR_DB_CONNECT 603
+#define ERR_SERVER_GOING_DOWN 604
+#define ERR_CREATE_CONNECTION 707
+#define ERR_BLOCKING_WRITE 711
+#define ERR_SESSION_OVERLOAD 712
+#define ERR_USER_TOO_ACTIVE 713
+#define ERR_TOO_MANY_SESSIONS 714
+#define ERR_NOT_EXPECTED 715
+#define ERR_BAD_FRIEND_FILE 717
+#define ERR_AUTHENTICATION_FAILED 911
+#define ERR_NOT_ALLOWED_WHEN_OFFLINE 913
+#define ERR_NOT_ACCEPTING_NEW_USERS 920
+#define ERR_EMAIL_ADDRESS_NOT_VERIFIED 924
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Global definitions
+
+#define MSN_MAX_EMAIL_LEN 128
+#define MSN_GUID_LEN 40
+
+#define MSN_DEFAULT_PORT 1863
+#define MSN_DEFAULT_LOGIN_SERVER "messenger.hotmail.com"
+#define MSN_DEFAULT_GATEWAY "gateway.messenger.hotmail.com"
+#define MSN_USER_AGENT "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"
+
+#define MSN_BLOCK "/BlockCommand"
+#define MSN_INVITE "/InviteCommand"
+#define MSN_NETMEETING "/NetMeeting"
+#define MSN_VIEW_PROFILE "/ViewProfile"
+#define MSN_SEND_NUDGE "/SendNudge"
+
+#define MENU_ITEMS_COUNT 2
+#define MS_GOTO_INBOX "/GotoInbox"
+#define MS_EDIT_PROFILE "/EditProfile"
+#define MS_SET_AVATAR "/SetAvatar"
+#define MS_VIEW_STATUS "/ViewMsnStatus"
+#define MS_SET_NICKNAME_UI "/SetNicknameUI"
+#define MS_SET_AVATAR_UI "/SetAvatarUI"
+
+#define MSN_SET_NICKNAME "/SetNickname"
+#define MSN_SET_AVATAR "/SetAvatar"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN plugin functions
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+
+#define MSN_ALLOW_MSGBOX 1
+#define MSN_ALLOW_ENTER 2
+#define MSN_HOTMAIL_POPUP 4
+#define MSN_SHOW_ERROR 8
+void __stdcall MSN_ShowPopup( const char* nickname, const char* msg, int flags );
+
+LONG __stdcall MSN_SendPacket( HANDLE, const char* cmd, const char* params, ... );
+char* __stdcall MirandaStatusToMSN( int status );
+int __stdcall MSNStatusToMiranda( const char* status );
+void __stdcall HtmlDecode( char* str );
+char* __stdcall HtmlEncode( const char* str );
+void __stdcall UrlDecode( char*str );
+void __stdcall UrlEncode( const char* src, char* dest, int cbDest );
+void __stdcall Utf8Decode( char* str, wchar_t** = NULL );
+char* __stdcall Utf8Encode( const char* src );
+char* __stdcall Utf8EncodeUcs2( const wchar_t* src );
+
+HANDLE __stdcall MSN_HContactFromEmail( const char* msnEmail, const char* msnNick, int addIfNeeded, int temporary );
+HANDLE __stdcall MSN_HContactById( const char* szGuid );
+
+int __stdcall MSN_AddContact( char* uhandle,char* nick ); //returns clist ID
+int __stdcall MSN_AddUser( HANDLE hContact, const char* email, int flags );
+void __stdcall MSN_AddAuthRequest( HANDLE hContact, const char *email, const char *nick );
+int __stdcall MSN_ContactFromHandle( char* uhandle ); //get cclist id from Uhandle
+void __stdcall MSN_DebugLog( const char* fmt, ... );
+void __stdcall MSN_DumpMemory( const char* buffer, int bufSize );
+void __stdcall MSN_HandleFromContact( unsigned long uin, char* uhandle );
+int __stdcall MSN_GetMyHostAsString( char* parBuf, int parBufSize );
+
+void __cdecl MSN_ConnectionProc( HANDLE hNewConnection, DWORD dwRemoteIP, void* );
+void __stdcall MSN_GoOffline( void );
+void __stdcall MSN_GetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen );
+LPTSTR __stdcall MSN_GetErrorText( DWORD parErrorCode );
+void __stdcall MSN_SendStatusMessage( const char* msg );
+void __stdcall MSN_SetServerStatus( int newStatus );
+char* __stdcall MSN_StoreLen( char* dest, char* last );
+void __stdcall LoadOptions( void );
+
+int __stdcall MSN_SendNickname(char *nickname);
+#if defined( _UNICODE )
+ int __stdcall MSN_SendNicknameW( WCHAR* nickname);
+ #define MSN_SendNicknameT MSN_SendNicknameW
+#else
+ #define MSN_SendNicknameT MSN_SendNickname
+#endif
+
+#if defined( _DEBUG )
+#define MSN_CallService CallService
+#else
+int __stdcall MSN_CallService( const char* szSvcName, WPARAM wParam, LPARAM lParam );
+#endif
+
+HANDLE __stdcall MSN_CreateProtoServiceFunction( const char*, MIRANDASERVICE );
+void __stdcall MSN_EnableMenuItems( BOOL );
+void __fastcall MSN_FreeVariant( DBVARIANT* dbv );
+char* __stdcall MSN_GetContactName( HANDLE hContact );
+TCHAR* __stdcall MSN_GetContactNameT( HANDLE hContact );
+DWORD __stdcall MSN_GetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue );
+DWORD __stdcall MSN_GetByte( const char* valueName, int parDefltValue );
+int __stdcall MSN_GetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len );
+WORD __stdcall MSN_GetWord( HANDLE hContact, const char* valueName, int parDefltValue );
+int __stdcall MSN_SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam );
+DWORD __stdcall MSN_SetByte( const char* valueName, int parValue );
+DWORD __stdcall MSN_SetDword( HANDLE hContact, const char* valueName, DWORD parValue );
+DWORD __stdcall MSN_SetWord( HANDLE hContact, const char* valueName, int parValue );
+DWORD __stdcall MSN_SetString( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall MSN_SetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue );
+DWORD __stdcall MSN_SetStringUtf( HANDLE hContact, const char* valueName, char* parValue );
+void __cdecl MSN_ShowError( const char* msgtext, ... );
+char* __stdcall MSN_Translate( const char* str );
+
+int __stdcall MSN_EnterBitmapFileName( char* szDest );
+int __stdcall MSN_SaveBitmapAsAvatar( HBITMAP hBitmap, const char* szFileName );
+HBITMAP __stdcall MSN_StretchBitmap( HBITMAP hBitmap );
+
+char* EscapeChatTags(char* pszText);
+char* UnEscapeChatTags(char* str_in);
+
+VOID CALLBACK MSNMainTimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime );
+LRESULT CALLBACK NullWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+DWORD WINAPI MsnShowMailThread( LPVOID );
+
+int IsWinver( void );
+
+void replaceStr( char*& dest, const char* src );
+char* rtrim( char *string );
+void strdel( char* parBuffer, int len );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// PNG library interface
+
+BOOL __stdcall MSN_LoadPngModule( void );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MIME headers processing
+
+struct MimeHeader
+{
+ char* name;
+ char* value;
+};
+
+struct MimeHeaders
+{
+ MimeHeaders();
+ MimeHeaders( int );
+ ~MimeHeaders();
+
+ const char* readFromBuffer( const char* pSrc );
+ const char* operator[]( const char* fieldName );
+
+ void addString( const char* name, const char* szValue );
+ void addLong( const char* name, long lValue );
+
+ int getLength( void );
+ char* writeToBuffer( char* pDest );
+
+ int mCount;
+ MimeHeader* mVals;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// File transfer helper
+
+struct ThreadData;
+
+struct P2P_Header
+{
+ DWORD mSessionID;
+ DWORD mID;
+ __int64 mOffset;
+ __int64 mTotalSize;
+ DWORD mPacketLen;
+ DWORD mFlags;
+ DWORD mAckSessionID;
+ DWORD mAckUniqueID;
+ __int64 mAckDataSize;
+};
+
+struct HReadBuffer
+{
+ HReadBuffer( ThreadData* info, int iStart = 0 );
+ ~HReadBuffer();
+
+ BYTE* surelyRead( int parBytes );
+
+ ThreadData* owner;
+ BYTE* buffer;
+ int totalDataSize;
+ int startOffset;
+};
+
+struct filetransfer
+{
+ filetransfer();
+ ~filetransfer( void );
+
+ void close();
+ void complete();
+ int create();
+
+ PROTOFILETRANSFERSTATUS std;
+
+ bool bCanceled; // flag to interrupt a transfer
+ bool bCompleted; // was a FT ever completed?
+ bool inmemTransfer; // flag: the file being received is to be stored in memory
+
+ union {
+ int fileId; // handle of file being transferring (r/w)
+ char* fileBuffer; // buffer of memory to handle the file
+ };
+
+ bool mOwnsThread, // thread was created specifically for that file transfer
+ mIsFirst; // set for the first transfer for a contact
+ LONG mThreadId; // unique id of the parent thread
+
+ WORD mIncomingPort;
+ HANDLE mIncomingBoundPort;
+ HANDLE hWaitEvent;
+
+ unsigned p2p_sessionid; // session id
+ unsigned p2p_msgid; // message id
+ unsigned p2p_acksessid; // acknowledged session id
+ unsigned p2p_sendmsgid; // send message id
+ unsigned p2p_byemsgid; // bye message id
+ unsigned p2p_ackID; // number of ack's state
+ unsigned p2p_appID; // application id: 1 = avatar, 2 = file transfer
+ char* p2p_branch; // header Branch: field
+ char* p2p_callID; // header Call-ID: field
+ char* p2p_dest; // destination e-mail address
+
+ //---- receiving a file
+ wchar_t* wszFileName; // file name in Unicode, for receiving
+ char* szInvcookie; // cookie for receiving
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Thread handling functions and datatypes
+
+#define MAX_THREAD_COUNT 64
+
+typedef void ( __cdecl* pThreadFunc )( void* );
+
+enum TInfoType
+{
+ SERVER_DISPATCH,
+ SERVER_NOTIFICATION,
+ SERVER_SWITCHBOARD,
+ SERVER_FILETRANS,
+ SERVER_P2P_DIRECT
+};
+
+struct TQueueItem
+{
+ TQueueItem* next;
+ int datalen;
+ char data[1];
+};
+
+#define MSG_DISABLE_HDR 1
+#define MSG_REQUIRE_ACK 2
+#define MSG_RTL 4
+
+struct ThreadData
+{
+ ThreadData();
+ ~ThreadData();
+
+ TInfoType mType; // thread type
+ char mServer[80]; // server name
+ LONG mUniqueID; // unique thread ID
+
+ HANDLE s; // NetLib connection for the thread
+ char mChatID[10];
+ bool mIsMainThread;
+ int mWaitPeriod;
+
+ //----| for gateways |----------------------------------------------------------------
+ char mSessionID[ 50 ]; // Gateway session ID
+ char mGatewayIP[ 80 ]; // Gateway IP address
+ int mGatewayTimeout;
+ char* mReadAheadBuffer;
+ int mEhoughData;
+ TQueueItem* mFirstQueueItem;
+
+ //----| for switchboard servers only |------------------------------------------------
+ int mCaller;
+ char mCookie[130]; // for switchboard servers only
+ HANDLE mInitialContact; // initial switchboard contact
+ HANDLE* mJoinedContacts; // another contacts
+ int mJoinedCount; // another contacts count
+ int mMessageCount; // message counter
+ LONG mTrid; // current message ID
+ bool mIsCalSent; // is CAL already sent?
+
+ //----| for file transfers only |-----------------------------------------------------
+ filetransfer* mMsnFtp; // file transfer block
+ filetransfer* mP2pSession; // new styled transfer
+ ThreadData* mParentThread; // thread that began the f/t
+ LONG mP2PInitTrid;
+
+ //----| internal data buffer |--------------------------------------------------------
+ int mBytesInData; // bytes available in data buffer
+ char mData[4096]; // data buffer for connection
+
+ //----| methods |---------------------------------------------------------------------
+ void applyGatewayData( HANDLE hConn, bool isPoll );
+ void getGatewayUrl( char* dest, int destlen, bool isPoll );
+ void processSessionData( const char* );
+ void startThread( pThreadFunc );
+
+ int send( char* data, int datalen );
+ int recv( char* data, long datalen );
+ int recv_dg( char* data, long datalen );
+
+ LONG sendMessage( int msgType, const char* msg, int parFlags );
+ LONG sendRawMessage( int msgType, const char* data, int datLen );
+ LONG sendPacket( const char* cmd, const char* fmt, ... );
+};
+
+void __stdcall MSN_CloseConnections( void );
+void __stdcall MSN_CloseThreads( void );
+int __stdcall MSN_ContactJoined( ThreadData* parInfo, HANDLE hContact );
+int __stdcall MSN_ContactLeft( ThreadData* parInfo, HANDLE hContact );
+void __stdcall MSN_InitThreads( void );
+int __stdcall MSN_GetChatThreads( ThreadData** parResult );
+int __stdcall MSN_GetActiveThreads( ThreadData** );
+ThreadData* __stdcall MSN_GetThreadByConnection( HANDLE hConn );
+ThreadData* __stdcall MSN_GetThreadByContact( HANDLE hContact );
+ThreadData* __stdcall MSN_GetThreadByPort( WORD wPort );
+ThreadData* __stdcall MSN_GetUnconnectedThread( HANDLE hContact );
+ThreadData* __stdcall MSN_GetThreadByID( LONG id );
+ThreadData* __stdcall MSN_GetOtherContactThread( ThreadData* thread );
+void __stdcall MSN_PingParentThread( ThreadData*, filetransfer* ft );
+void __stdcall MSN_StartThread( pThreadFunc parFunc, void* arg );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN P2P session support
+
+#define MSN_APPID_AVATAR 1
+#define MSN_APPID_FILE 2
+
+void __stdcall p2p_ackOtherFiles( ThreadData* info );
+void __stdcall p2p_invite( HANDLE hContact, int iAppID, filetransfer* ft = NULL );
+void __stdcall p2p_processMsg( ThreadData* info, const char* msgbody );
+void __stdcall p2p_sendAck( filetransfer* ft, ThreadData* info, P2P_Header* hdrdata );
+void __stdcall p2p_sendStatus( filetransfer* ft, ThreadData* info, long lStatus );
+void __stdcall p2p_sendBye( ThreadData* info, filetransfer* ft );
+void __stdcall p2p_sendCancel( ThreadData* info, filetransfer* ft );
+
+void __stdcall p2p_sendFeedStart( filetransfer* ft, ThreadData* T );
+long __stdcall p2p_sendPortion( filetransfer* ft, ThreadData* T );
+
+void __stdcall p2p_registerSession( filetransfer* ft );
+void __stdcall p2p_unregisterSession( filetransfer* ft );
+void __stdcall p2p_unregisterThreadSession( LONG threadID );
+
+filetransfer* __stdcall p2p_getAnotherContactSession( filetransfer* ft );
+filetransfer* __stdcall p2p_getFirstSession( HANDLE hContact );
+filetransfer* __stdcall p2p_getSessionByID( unsigned ID );
+filetransfer* __stdcall p2p_getSessionByMsgID( unsigned ID );
+filetransfer* __stdcall p2p_getSessionByCallID( const char* CallID );
+
+BOOL __stdcall p2p_sessionRegistered( filetransfer* ft );
+
+void ft_startFileSend( ThreadData* info, const char* Invcommand, const char* Invcookie );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Message queue
+
+#define MSGQUE_RAW 1
+
+struct MsgQueueEntry
+{
+ HANDLE hContact;
+ char* message;
+ int msgType;
+ int msgSize;
+ filetransfer* ft;
+ int seq;
+ int allocatedToThread;
+ int timeout;
+ int flags;
+};
+
+int __stdcall MsgQueue_Add( HANDLE hContact, int msgType, const char* msg, int msglen, filetransfer* ft = NULL, int flags = 0 );
+HANDLE __stdcall MsgQueue_CheckContact( HANDLE hContact );
+HANDLE __stdcall MsgQueue_GetNextRecipient( void );
+int __stdcall MsgQueue_GetNext( HANDLE hContact, MsgQueueEntry& retVal );
+void __stdcall MsgQueue_Clear( HANDLE hContact = NULL );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// User lists
+
+#define LIST_FL 0x0001
+#define LIST_AL 0x0002
+#define LIST_BL 0x0004
+#define LIST_RL 0x0008
+#define LIST_PL 0x0010
+
+#define LIST_REMOVE 0x0100
+
+#define IsValidListCode(n) ((n)!=0)
+
+int __stdcall Lists_NameToCode( const char* name );
+int __stdcall Lists_Add( int list, const char* email, const char* nick );
+int __stdcall Lists_IsInList( int list, const char* email );
+int __stdcall Lists_GetMask( const char* email );
+void __stdcall Lists_Remove( int list, const char* email );
+void __stdcall Lists_Wipe( void );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN server groups
+
+bool MSN_AddGroup( const char* pName, const char* pId );
+void MSN_AddServerGroup( const char* pszGroupName );
+void MSN_DeleteGroup( const char* pId );
+void MSN_FreeGroups( void );
+LPCSTR MSN_GetGroupById( const char* pId );
+LPCSTR MSN_GetGroupByName( const char* pName );
+LPCSTR MSN_GetGroupByNumber( int pNumber );
+void MSN_MoveContactToGroup( HANDLE hContact, const char* grpName );
+void MSN_RenameServerGroup( int iNumber, LPCSTR szId, const char* newName );
+void MSN_SetGroupName( const char* pId, const char* pName );
+void MSN_SetGroupNumber( const char* pId, int pNumber );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN plugin options
+
+typedef struct
+{
+ COLORREF BGColour;
+ COLORREF TextColour;
+ BOOL UseWinColors;
+
+ BOOL EnableSounds;
+
+ DWORD PopupTimeoutHotmail;
+ DWORD PopupTimeoutOther;
+
+ BOOL DisableMenu;
+ BOOL UseGateway;
+ BOOL UseProxy;
+ BOOL KeepConnectionAlive;
+ BOOL ShowErrorsAsPopups;
+ BOOL AwayAsBrb;
+ BOOL SlowSend;
+ BOOL ManageServer;
+ BOOL EnableAvatars;
+
+ BOOL UseMSNP11;
+}
+ MYOPTIONS;
+
+extern MYOPTIONS MyOptions;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Windows error class
+
+struct TWinErrorCode
+{
+ WINAPI TWinErrorCode();
+ WINAPI ~TWinErrorCode();
+
+ char* WINAPI getText();
+
+ long mErrorCode;
+ char* mErrorText;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// External variables
+
+#define MSN_NUM_MODES 7
+
+struct MSN_StatusMessage
+{
+ int m_mode;
+ char* m_msg;
+};
+
+extern MSN_StatusMessage msnModeMsgs[ MSN_NUM_MODES ];
+
+extern ThreadData* volatile msnNsThread;
+extern bool volatile msnLoggedIn;
+
+extern char* msnProtocolName;
+extern HANDLE msnMenuItems[ MENU_ITEMS_COUNT ];
+extern int msnSearchID;
+extern char* msnExternalIP;
+extern int msnStatusMode,
+ msnDesiredStatus;
+
+extern char* msnProtChallenge;
+extern char* msnProductID;
+
+extern char* ModuleName;
+extern char* mailsoundname;
+extern HANDLE msnGetInfoContact;
+
+extern char* sid;
+extern char* kv;
+extern char* passport;
+extern char* MSPAuth;
+
+extern HANDLE hNetlibUser;
+extern HINSTANCE hInst;
+extern int msnOtherContactsBlocked;
+
+extern bool msnHaveChatDll;
+
+extern HANDLE hGroupAddEvent;
+
+///////////////////////////////////////////////////////////////////////////////
+// memory manager
+
+extern struct MM_INTERFACE memoryManagerInterface;
+
+#define mir_alloc(n) memoryManagerInterface.mmi_malloc(n)
+#define mir_free(ptr) memoryManagerInterface.mmi_free(ptr)
+#define mir_realloc(ptr,size) memoryManagerInterface.mmi_realloc(ptr,size)
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8 encode helper
+
+class UTFEncoder {
+ char* m_body;
+
+public:
+ __forceinline UTFEncoder( const char* pSrc ) :
+ m_body( Utf8Encode( pSrc ))
+ {}
+
+ __forceinline ~UTFEncoder()
+ { free( m_body );
+ }
+
+ __forceinline const char* str() const { return m_body; }
+};
+
+#define UTF8(A) UTFEncoder(A).str()
diff --git a/miranda-wine/protocols/MSN/msn_http.cpp b/miranda-wine/protocols/MSN/msn_http.cpp
new file mode 100644
index 0000000..711925a
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_http.cpp
@@ -0,0 +1,97 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+//=======================================================================================
+// Fake function - it does nothing but confirms successful session initialization
+//=======================================================================================
+
+int msn_httpGatewayInit(HANDLE hConn, NETLIBOPENCONNECTION* nloc, NETLIBHTTPREQUEST* nlhr)
+{
+ NETLIBHTTPPROXYINFO nlhpi = {0};
+ nlhpi.cbSize = sizeof(nlhpi);
+ nlhpi.szHttpGetUrl = NULL;
+ nlhpi.szHttpPostUrl = "messenger.hotmail.com";
+ nlhpi.flags = NLHPIF_HTTP11;
+ return MSN_CallService(MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
+}
+
+//=======================================================================================
+// Prepares the szHttpPostUrl. If it's the very first send (mSessionID is void), this
+// function generates the initial URL depending on a thread type
+//=======================================================================================
+
+int msn_httpGatewayWrapSend(HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend)
+{
+ ThreadData* T = MSN_GetThreadByConnection( hConn );
+ if ( T != NULL )
+ T->applyGatewayData( hConn, len == 0 );
+
+ NETLIBBUFFER tBuf = { ( char* )buf, len, flags };
+ return pfnNetlibSend(( LPARAM )hConn, WPARAM( &tBuf ));
+}
+
+//=======================================================================================
+// Processes the results of the command execution. Parses HTTP headers to get the next
+// SessionID & gateway IP values
+//=======================================================================================
+
+PBYTE msn_httpGatewayUnwrapRecv( NETLIBHTTPREQUEST* nlhr, PBYTE buf, int len, int *outBufLen, void *(*NetlibRealloc)(void *, size_t))
+{
+ *outBufLen = len;
+
+ ThreadData* T = MSN_GetThreadByConnection( nlhr->nlc );
+ if ( T == NULL )
+ return buf;
+
+ bool tIsSessionClosed = false;
+
+ for ( int i=0; i < nlhr->headersCount; i++ )
+ {
+ NETLIBHTTPHEADER& tHeader = nlhr->headers[ i ];
+ if ( stricmp( tHeader.szName, "X-MSN-Messenger" ) != 0 )
+ continue;
+
+ if ( strstr( tHeader.szValue, "Session=close" ) != 0 )
+ { tIsSessionClosed = true;
+ break;
+ }
+
+ T->processSessionData( tHeader.szValue );
+ T->applyGatewayData( nlhr->nlc, false );
+ }
+
+ if ( tIsSessionClosed || nlhr->resultCode != 200)
+ { *outBufLen = 0;
+ buf = ( PBYTE )mir_alloc( 1 );
+ *buf = 0;
+ }
+ else if ( buf == NULL && len == 0 )
+ { *outBufLen = 1;
+ buf = ( PBYTE )mir_alloc( 1 );
+ *buf = 0;
+ }
+
+ return buf;
+}
diff --git a/miranda-wine/protocols/MSN/msn_libstr.cpp b/miranda-wine/protocols/MSN/msn_libstr.cpp
new file mode 100644
index 0000000..5a0c688
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_libstr.cpp
@@ -0,0 +1,54 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+void replaceStr( char*& dest, const char* src )
+{
+ if ( src != NULL ) {
+ if ( dest != NULL )
+ free( dest );
+ dest = strdup( src );
+} }
+
+char* rtrim( char *string )
+{
+ char* p = string + strlen( string ) - 1;
+
+ while ( p >= string )
+ { if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+
+void strdel( char* parBuffer, int len )
+{
+ char *p;
+ for ( p = parBuffer+len; *p != 0; p++ )
+ p[ -len ] = *p;
+
+ p[ -len ] = '\0';
+}
diff --git a/miranda-wine/protocols/MSN/msn_lists.cpp b/miranda-wine/protocols/MSN/msn_lists.cpp
new file mode 100644
index 0000000..d6015d1
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_lists.cpp
@@ -0,0 +1,346 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <mbstring.h>
+
+#include "resource.h"
+
+struct MsnContact
+{
+ int list;
+ char *email,*nick;
+};
+
+static int count;
+static MsnContact* lists;
+static CRITICAL_SECTION csLists;
+
+void Lists_Init(void)
+{
+ lists = NULL;
+ count = 0;
+ InitializeCriticalSection( &csLists );
+}
+
+void Lists_Uninit(void)
+{
+ for ( int i=0; i < count; i++ ) {
+ free( lists[i].email );
+ free( lists[i].nick );
+ }
+
+ if ( lists != NULL )
+ free( lists );
+
+ DeleteCriticalSection( &csLists );
+}
+
+int __stdcall Lists_NameToCode( const char *name )
+{
+ if ( name[2] )
+ return 0;
+
+ switch( *( PWORD )name ) {
+ case 'LA': return LIST_AL;
+ case 'LB': return LIST_BL;
+ case 'LR': return LIST_RL;
+ case 'LF': return LIST_FL;
+ case 'LP': return LIST_PL;
+ }
+
+ return 0;
+}
+
+void __stdcall Lists_Wipe( void )
+{
+ EnterCriticalSection( &csLists );
+ for ( int i=0; i < count; i++ ) {
+ free( lists[i].email );
+ free( lists[i].nick );
+ }
+
+ if ( lists != NULL ) {
+ free( lists );
+ lists = NULL;
+ }
+
+ count = 0;
+ LeaveCriticalSection( &csLists );
+}
+
+int __stdcall Lists_IsInList( int list, const char* email )
+{
+ int i;
+ EnterCriticalSection( &csLists );
+ for ( i=0; i < count; i++ )
+ if ( !strcmp( lists[i].email, email ))
+ break;
+
+ if ( list != -1 && i != count )
+ if (( lists[ i ].list & list ) != list )
+ i = count;
+
+ LeaveCriticalSection( &csLists );
+ return ( i == count ) ? 0 : i+1;
+}
+
+int __stdcall Lists_GetMask( const char* email )
+{
+ int i;
+ EnterCriticalSection( &csLists );
+ for ( i=0; i < count; i++ )
+ if ( !strcmp( lists[i].email, email )) {
+ LeaveCriticalSection( &csLists );
+ return lists[i].list;
+ }
+
+ LeaveCriticalSection( &csLists );
+ return 0;
+}
+
+int __stdcall Lists_Add( int list, const char* email, const char* nick )
+{
+ EnterCriticalSection( &csLists );
+
+ MsnContact* C;
+ int idx = Lists_IsInList( -1, email );
+ if ( idx == 0 )
+ {
+ lists = ( MsnContact* )realloc( lists, sizeof( MsnContact )*( count+1 ));
+ C = &lists[ count++ ];
+ C->list = 0;
+ C->email = strdup( email );
+ C->nick = ( char* )strdup( nick );
+ }
+ else C = &lists[ idx-1 ];
+
+ int result = ( C->list |= list );
+ LeaveCriticalSection( &csLists );
+ return result;
+}
+
+void __stdcall Lists_Remove( int list, const char* email )
+{
+ EnterCriticalSection( &csLists );
+ int i = Lists_IsInList( -1, email );
+ if ( i != 0 ) {
+ MsnContact* C = &lists[ --i ];
+
+ C->list &= ~list;
+ if ( C->list == 0 ) {
+ free( C->email );
+ free( C->nick );
+ count--;
+ memmove( lists+i, lists+i+1, sizeof( MsnContact )*( count-i ));
+ lists = ( MsnContact* )realloc( lists, sizeof( MsnContact )*count );
+ } }
+
+ LeaveCriticalSection( &csLists );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN Server List Manager dialog procedure
+
+static void ResetListOptions(HWND hwndList)
+{
+ int i;
+
+ SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL);
+ SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0);
+ SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
+ SendMessage(hwndList,CLM_SETLEFTMARGIN,2,0);
+ SendMessage(hwndList,CLM_SETINDENT,10,0);
+ for(i=0;i<=FONTID_MAX;i++)
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+ SetWindowLong(hwndList,GWL_STYLE,GetWindowLong(hwndList,GWL_STYLE)|CLS_SHOWHIDDEN);
+}
+
+static void SetAllContactIcons( HWND hwndList )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ do {
+ HANDLE hItem = ( HANDLE )SendMessage( hwndList, CLM_FINDCONTACT, ( WPARAM )hContact, 0 );
+ if ( hItem == NULL )
+ continue;
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto == NULL ) {
+LBL_Bad: SendMessage( hwndList, CLM_DELETEITEM, ( WPARAM )hItem, 0 );
+ continue;
+ }
+
+ if ( strcmp( szProto, msnProtocolName ))
+ goto LBL_Bad;
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof szEmail ))
+ goto LBL_Bad;
+
+ DWORD dwMask = Lists_GetMask( szEmail );
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(0,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(0,( dwMask & LIST_FL )?1:0));
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(1,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(1,( dwMask & LIST_AL )?2:0));
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(2,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(2,( dwMask & LIST_BL )?3:0));
+ if ( SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(3,0)) == 0xFF )
+ SendMessage( hwndList, CLM_SETEXTRAIMAGE,( WPARAM )hItem, MAKELPARAM(3,( dwMask & LIST_RL )?4:0));
+ }
+ while( hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ));
+}
+
+static void SaveListItem( HANDLE hContact, const char* szEmail, int list, int iPrevValue, int iNewValue )
+{
+ if ( iPrevValue == iNewValue )
+ return;
+
+ if ( iNewValue == 0 )
+ list += LIST_REMOVE;
+ MSN_AddUser( hContact, szEmail, list );
+}
+
+static void SaveSettings( HWND hwndList )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ do {
+ HANDLE hItem = ( HANDLE )SendMessage( hwndList, CLM_FINDCONTACT, ( WPARAM )hContact, 0 );
+ if ( hItem == NULL )
+ continue;
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto == NULL ) continue;
+ if ( strcmp( szProto, msnProtocolName )) continue;
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof szEmail ))
+ continue;
+
+ DWORD dwMask = Lists_GetMask( szEmail );
+ SaveListItem( hContact, szEmail, LIST_FL, ( dwMask & LIST_FL ) != 0, SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(0,0)));
+ SaveListItem( hContact, szEmail, LIST_AL, ( dwMask & LIST_AL ) != 0, SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(1,0)));
+ SaveListItem( hContact, szEmail, LIST_BL, ( dwMask & LIST_BL ) != 0, SendMessage( hwndList, CLM_GETEXTRAIMAGE, ( WPARAM )hItem, MAKELPARAM(2,0)));
+ }
+ while( hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ));
+}
+
+BOOL CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HANDLE hItemAll;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ HIMAGELIST hIml = ImageList_Create(
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 5, 5 );
+ ImageList_AddIcon( hIml,LoadIcon(GetModuleHandle(NULL),MAKEINTRESOURCE(211)));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_FL )));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_AL )));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_BL )));
+ ImageList_AddIcon( hIml, LoadIcon( hInst, MAKEINTRESOURCE( IDI_LIST_RL )));
+ SendDlgItemMessage( hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml );
+ }
+ ResetListOptions( GetDlgItem( hwndDlg, IDC_LIST ));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,4,0);
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ return TRUE;
+
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+
+ case WM_COMMAND:
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->idFrom == 0 && ((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ SaveSettings(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ }
+
+ if (((LPNMHDR)lParam)->idFrom != IDC_LIST )
+ break;
+
+ switch (((LPNMHDR)lParam)->code) {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+
+ case NM_CLICK:
+ HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+ int itemType;
+
+ // Make sure we have an extra column, also we can't change RL list
+ if ( nm->iColumn == -1 || nm->iColumn == 3 )
+ break;
+
+ // Find clicked item
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x,nm->pt.y));
+ // Nothing was clicked
+ if ( hItem == NULL )
+ break;
+
+ // It was not our extended icon
+ if ( !( hitFlags & CLCHT_ONITEMEXTRA ))
+ break;
+
+ // Get image in clicked column (0=none, 1=FL, 2=AL, 3=BL, 4=RL)
+ iImage = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0));
+ if ( iImage == 0 )
+ iImage = nm->iColumn + 1;
+ else
+ iImage = 0;
+
+ // Get item type (contact, group, etc...)
+ itemType = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+ if ( itemType == CLCIT_CONTACT ) { // A contact
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, iImage));
+ if (iImage && SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM( 3-nm->iColumn, 0)) != 0xFF )
+ if ( nm->iColumn == 1 || nm->iColumn == 2 )
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM( 3-nm->iColumn, 0));
+ }
+
+ // Activate Apply button
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/MSN/msn_md5.h b/miranda-wine/protocols/MSN/msn_md5.h
new file mode 100644
index 0000000..57dcc17
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_md5.h
@@ -0,0 +1,59 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init( MD5_CTX* );
+void MD5Update( MD5_CTX *, unsigned char *, unsigned int );
+void MD5Final(unsigned char [16], MD5_CTX * );
+
diff --git a/miranda-wine/protocols/MSN/msn_md5c.cpp b/miranda-wine/protocols/MSN/msn_md5c.cpp
new file mode 100644
index 0000000..3826ac4
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_md5c.cpp
@@ -0,0 +1,287 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include "msn_global.h"
+#include "msn_md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform( UINT4[4], unsigned char[64] );
+static void Encode( unsigned char *, UINT4 *, unsigned int );
+static void Decode( UINT4 *, unsigned char *, unsigned int );
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init( MD5_CTX* context)
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update( MD5_CTX* context, unsigned char* input, unsigned int inputLen)
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4) inputLen << 3)) <
+ ((UINT4) inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4) inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+ */
+ if (inputLen >= partLen)
+ {
+ memcpy((POINTER) & context->buffer[index], (POINTER) input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy((POINTER) & context->buffer[index], (POINTER) & input[i], inputLen - i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final( unsigned char* digest, MD5_CTX* context )
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode(bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update(context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update(context, bits, 8);
+ /* Store state in digest */
+ Encode(digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset((POINTER) context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform( UINT4 state[4], unsigned char block[64] )
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ memset((POINTER) x, 0, sizeof(x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode( unsigned char* output, UINT4 *input, unsigned int len )
+{
+ unsigned int i, j;
+
+ for ( i = 0, j = 0; j < len; i++, j += 4 )
+ {
+ output[j] = (unsigned char) (input[i] & 0xff);
+ output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
+ output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
+ output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
+} }
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode( UINT4 *output, unsigned char *input, unsigned int len )
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] =
+ ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
+ (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
+}
diff --git a/miranda-wine/protocols/MSN/msn_mime.cpp b/miranda-wine/protocols/MSN/msn_mime.cpp
new file mode 100644
index 0000000..f8a9d3b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_mime.cpp
@@ -0,0 +1,162 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// constructors and destructor
+
+MimeHeaders::MimeHeaders() :
+ mCount( 0 ),
+ mVals( NULL )
+{
+}
+
+MimeHeaders::MimeHeaders( int iInitCount ) :
+ mCount( 0 )
+{
+ mVals = ( MimeHeader* )malloc( iInitCount * sizeof( MimeHeader ));
+}
+
+MimeHeaders::~MimeHeaders()
+{
+ if ( mCount == NULL )
+ return;
+
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& H = mVals[ i ];
+ free( H.name );
+ free( H.value );
+ }
+
+ free( mVals );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// add various values
+
+void MimeHeaders::addString( const char* name, const char* szValue )
+{
+ MimeHeader& H = mVals[ mCount++ ];
+ H.name = strdup( name );
+ H.value = strdup( szValue );
+}
+
+void MimeHeaders::addLong( const char* name, long lValue )
+{
+ MimeHeader& H = mVals[ mCount++ ];
+ H.name = strdup( name );
+
+ char szBuffer[ 20 ];
+ ltoa( lValue, szBuffer, 10 );
+ H.value = strdup( szBuffer );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// write all values to a buffer
+
+int MimeHeaders::getLength()
+{
+ int iResult = 0;
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& H = mVals[ i ];
+ iResult += strlen( H.name ) + strlen( H.value ) + 4;
+ }
+
+ return iResult;
+}
+
+char* MimeHeaders::writeToBuffer( char* pDest )
+{
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& H = mVals[ i ];
+ pDest += sprintf( pDest, "%s: %s\r\n", H.name, H.value );
+ }
+
+ return pDest;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// read set of values from buffer
+
+const char* MimeHeaders::readFromBuffer( const char* parString )
+{
+ int headerCount = 0;
+ MimeHeader headers[ 100 ];
+ char line[ 4096 ];
+
+ while ( true ) {
+ if ( parString[0] == '\r' && parString[1] == '\n' ) {
+ parString += 2;
+ break;
+ }
+
+ const char* peol = strchr( parString, '\r' );
+ if ( peol == NULL )
+ break;
+
+ int cbLen = int( peol - parString );
+ if ( cbLen > sizeof( line ))
+ break;
+
+ memcpy( line, parString, cbLen );
+ line[ cbLen ] = 0;
+
+ if ( *++peol == '\n' )
+ peol++;
+
+ parString = peol;
+
+ char* delim = strchr( line, ':' );
+ if ( delim == NULL ) {
+ MSN_DebugLog( "MSG: Invalid MIME header: '%s'", line );
+ continue;
+ }
+
+ *delim++ = '\0';
+ while ( *delim == ' ' || *delim == '\t' )
+ delim++;
+
+ MimeHeader& H = headers[ headerCount ];
+ H.name = strdup( line );
+ H.value = strdup( delim );
+ headerCount++;
+ }
+
+ if (( mCount = headerCount ) != 0 ) {
+ mVals = ( MimeHeader* )malloc( sizeof( MimeHeader )*headerCount );
+ memcpy( mVals, headers, sizeof( MimeHeader )*headerCount );
+ }
+ return parString;
+}
+
+const char* MimeHeaders::operator[]( const char* szFieldName )
+{
+ for ( int i=0; i < mCount; i++ ) {
+ MimeHeader& MH = mVals[i];
+ if ( !strcmp( MH.name, szFieldName ))
+ return MH.value;
+ }
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/MSN/msn_misc.cpp b/miranda-wine/protocols/MSN/msn_misc.cpp
new file mode 100644
index 0000000..86c46c3
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_misc.cpp
@@ -0,0 +1,1069 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 <stdio.h>
+#include <stdarg.h>
+
+#include "msn_global.h"
+
+#include <direct.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "msn_md5.h"
+#include "resource.h"
+
+typedef LONG ( WINAPI pIncrementFunc )( PLONG );
+
+static pIncrementFunc MyInterlockedIncrement95;
+static pIncrementFunc MyInterlockedIncrementInit;
+
+pIncrementFunc *MyInterlockedIncrement = MyInterlockedIncrementInit;
+
+static CRITICAL_SECTION csInterlocked95;
+extern HANDLE msnMainThread;
+extern bool msnUseExtendedPopups;
+extern char* msnPreviousUUX;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MirandaStatusToMSN - status helper functions
+
+char* __stdcall MirandaStatusToMSN( int status )
+{
+ switch(status)
+ {
+ case ID_STATUS_OFFLINE: return "FLN";
+ case ID_STATUS_NA: return ( MyOptions.AwayAsBrb ) ? (char *)"AWY" : (char *)"BRB";
+ case ID_STATUS_AWAY: return ( MyOptions.AwayAsBrb ) ? (char *)"BRB" : (char *)"AWY";
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED: return "BSY";
+ case ID_STATUS_ONTHEPHONE: return "PHN";
+ case ID_STATUS_OUTTOLUNCH: return "LUN";
+ case ID_STATUS_INVISIBLE: return "HDN";
+// case ID_STATUS_IDLE: return "IDL";
+ default: return "NLN";
+} }
+
+int __stdcall MSNStatusToMiranda(const char *status)
+{
+ switch((*(PDWORD)status&0x00FFFFFF)|0x20000000) {
+ case ' NLN': return ID_STATUS_ONLINE;
+ case ' YWA': return ( MyOptions.AwayAsBrb ) ? ID_STATUS_NA : ID_STATUS_AWAY;
+ case ' LDI': //return ID_STATUS_IDLE;
+ case ' BRB': return ( MyOptions.AwayAsBrb ) ? ID_STATUS_AWAY : ID_STATUS_NA;
+ case ' YSB': return ID_STATUS_OCCUPIED;
+ case ' NHP': return ID_STATUS_ONTHEPHONE;
+ case ' NUL': return ID_STATUS_OUTTOLUNCH;
+ case ' NDH': return ID_STATUS_INVISIBLE;
+ default: return ID_STATUS_OFFLINE;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddUser - adds a e-mail address to one of the MSN server lists
+
+int __stdcall MSN_AddUser( HANDLE hContact, const char* email, int flags )
+{
+ if ( flags & LIST_REMOVE )
+ {
+ if ( !Lists_IsInList( flags & 0xFF, email ))
+ return 0;
+ }
+ else if ( Lists_IsInList( flags, email ))
+ return 0;
+
+ char* listName;
+
+ switch( flags & 0xFF )
+ {
+ case LIST_AL: listName = "AL"; break;
+ case LIST_BL: listName = "BL"; break;
+ case LIST_FL: listName = "FL"; break;
+ case LIST_RL: listName = "RL"; break;
+ case LIST_PL: listName = "PL"; break;
+ default:
+ return -1;
+ }
+
+ int msgid;
+ if (( flags & 0xFF ) == LIST_FL ) {
+ if ( flags & LIST_REMOVE ) {
+ if ( hContact == NULL )
+ if (( hContact = MSN_HContactFromEmail( email, NULL, 0, 0 )) == NULL )
+ return -1;
+
+ char id[ MSN_GUID_LEN ];
+ if ( !MSN_GetStaticString( "ID", hContact, id, sizeof id ))
+ msgid = msnNsThread->sendPacket( "REM", "%s %s", listName, id );
+ }
+ else msgid = msnNsThread->sendPacket( "ADC", "%s N=%s F=%s", listName, email, email );
+ }
+ else {
+ if ( flags & LIST_REMOVE )
+ msgid = msnNsThread->sendPacket( "REM", "%s %s", listName, email );
+ else
+ msgid = msnNsThread->sendPacket( "ADC", "%s N=%s", listName, email );
+ }
+
+ return msgid;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddAuthRequest - adds the authorization event to the database
+
+void __stdcall MSN_AddAuthRequest( HANDLE hContact, const char *email, const char *nick )
+{
+ //blob is: UIN=0(DWORD), hContact(DWORD), nick(ASCIIZ), ""(ASCIIZ), ""(ASCIIZ), email(ASCIIZ), ""(ASCIIZ)
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = msnProtocolName;
+ dbei.timestamp = (DWORD)time(NULL);
+ dbei.flags = 0;
+ dbei.eventType = EVENTTYPE_AUTHREQUEST;
+ dbei.cbBlob = sizeof(DWORD)*2+strlen(nick)+strlen(email)+5;
+
+ PBYTE pCurBlob = dbei.pBlob = ( PBYTE )malloc( dbei.cbBlob );
+ *( PDWORD )pCurBlob = 0; pCurBlob+=sizeof( DWORD );
+ *( PDWORD )pCurBlob = ( DWORD )hContact; pCurBlob+=sizeof( DWORD );
+ strcpy(( char* )pCurBlob, nick); pCurBlob += strlen( nick )+1;
+ *pCurBlob = '\0'; pCurBlob++; //firstName
+ *pCurBlob = '\0'; pCurBlob++; //lastName
+ strcpy(( char* )pCurBlob, email ); pCurBlob += strlen( email )+1;
+ *pCurBlob = '\0'; //reason
+ MSN_CallService( MS_DB_EVENT_ADD, NULL,( LPARAM )&dbei );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddServerGroup - adds a group to the server list
+
+void MSN_AddServerGroup( const char* pszGroupName )
+{
+ char szBuf[ 200 ];
+ UrlEncode( pszGroupName, szBuf, sizeof szBuf );
+
+ if ( hGroupAddEvent == NULL )
+ hGroupAddEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ msnNsThread->sendPacket( "ADG", "%s", szBuf );
+
+ WaitForSingleObject( hGroupAddEvent, INFINITE );
+ CloseHandle( hGroupAddEvent ); hGroupAddEvent = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_DebugLog - writes a line of comments to the network log
+
+void __stdcall MSN_DebugLog( const char *fmt, ... )
+{
+ char str[ 4096 ];
+ va_list vararg;
+
+ va_start( vararg, fmt );
+ int tBytes = _vsnprintf( str, sizeof(str)-1, fmt, vararg );
+ if ( tBytes == 0 )
+ return;
+
+ if ( tBytes > 0 )
+ str[ tBytes ] = 0;
+ else
+ str[ sizeof(str)-1 ] = 0;
+
+ MSN_CallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )str );
+ va_end( vararg );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_DumpMemory - dumps a memory block to the network log
+
+void __stdcall MSN_DumpMemory( const char* buffer, int bufSize )
+{
+ char TmpBuffer[ 256 ];
+ long Ptr = 0;
+
+ while ( Ptr < bufSize ) {
+ char* bufferPtr = TmpBuffer + sprintf( TmpBuffer, "%04X ", Ptr );
+ int i;
+
+ for ( i=0; Ptr+i < bufSize && i < 16; i++ )
+ bufferPtr += sprintf( bufferPtr, "%02X ", BYTE( buffer[Ptr+i] ));
+
+ while ( i++ < 17 ) {
+ strcat( bufferPtr, " " );
+ bufferPtr += 3;
+ }
+
+ for ( i=0; Ptr < bufSize && i < 16; i++, Ptr++ )
+ *bufferPtr++ = ( BYTE( buffer[ Ptr ]) >= ' ' ) ? buffer[ Ptr ] : '.';
+
+ *bufferPtr = 0;
+
+ MSN_CallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )TmpBuffer );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetAvatarFileName - gets a file name for an contact's avatar
+
+void __stdcall MSN_GetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen )
+{
+ MSN_CallService( MS_DB_GETPROFILEPATH, cbLen, LPARAM( pszDest ));
+
+ int tPathLen = strlen( pszDest );
+ tPathLen += mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "\\MSN\\" );
+ CreateDirectoryA( pszDest, NULL );
+
+ if ( hContact != NULL ) {
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof( szEmail )))
+ ltoa(( long )hContact, szEmail, 10 );
+
+ long digest[ 4 ];
+ MD5_CTX ctx;
+ MD5Init( &ctx );
+ MD5Update( &ctx, ( BYTE* )szEmail, strlen( szEmail ));
+ MD5Final(( BYTE* )digest, &ctx );
+
+ tPathLen += mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%08lX%08lX%08lX%08lX",
+ digest[0], digest[1], digest[2], digest[3] );
+
+ strcat( pszDest + tPathLen, ".bmp" );
+ }
+ else mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%s avatar.png", msnProtocolName );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GoOffline - performs several actions when a server goes offline
+
+void __stdcall MSN_GoOffline()
+{
+ int msnOldStatus = msnStatusMode; msnStatusMode = ID_STATUS_OFFLINE;
+ MSN_SendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)msnOldStatus, ID_STATUS_OFFLINE );
+
+ msnLoggedIn = false;
+
+ free(msnPreviousUUX);
+ msnPreviousUUX = NULL;
+
+ if ( !Miranda_Terminated() )
+ MSN_EnableMenuItems( FALSE );
+ MSN_CloseConnections();
+ MSN_FreeGroups();
+ MsgQueue_Clear();
+
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL )
+ {
+ if ( !lstrcmpA( msnProtocolName, (char*)MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 )))
+ if ( ID_STATUS_OFFLINE != MSN_GetWord( hContact, "Status", ID_STATUS_OFFLINE ))
+ MSN_SetWord( hContact, "Status", ID_STATUS_OFFLINE );
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendMessage - formats and sends a MSG packet through the server
+
+char sttHeaderStart[] = "MIME-Version: 1.0\r\n";
+
+LONG ThreadData::sendMessage( int msgType, const char* parMsg, int parFlags )
+{
+ char tHeader[ 1024 ];
+ strcpy( tHeader, sttHeaderStart );
+
+ if (( parFlags & MSG_DISABLE_HDR ) == 0 ) {
+ char tFontName[ 100 ], tFontStyle[ 3 ];
+ DWORD tFontColor;
+
+ strcpy( tFontName, "Arial" );
+
+ if ( MSN_GetByte( "SendFontInfo", 1 )) {
+ char* p;
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( NULL, "SRMsg", "Font0", &dbv )) {
+ for ( p = dbv.pszVal; *p; p++ )
+ if ( BYTE( *p ) >= 128 || *p < 32 )
+ break;
+
+ if ( *p == 0 ) {
+ UrlEncode( dbv.pszVal, tFontName, sizeof( tFontName ));
+ MSN_FreeVariant( &dbv );
+ } }
+
+ { BYTE tStyle = DBGetContactSettingByte( NULL, "SRMsg", "Font0Sty", 0 );
+ p = tFontStyle;
+ if ( tStyle & 1 ) *p++ = 'B';
+ if ( tStyle & 2 ) *p++ = 'I';
+ *p = 0;
+ }
+
+ tFontColor = DBGetContactSettingDword( NULL, "SRMsg", "Font0Col", 0 );
+ }
+ else {
+ tFontColor = 0;
+ tFontStyle[ 0 ] = 0;
+ }
+
+ mir_snprintf( tHeader + sizeof( sttHeaderStart )-1, sizeof( tHeader )-sizeof( sttHeaderStart ),
+ "Content-Type: text/plain; charset=UTF-8\r\n"
+ "X-MMS-IM-Format: FN=%s; EF=%s; CO=%x; CS=0; PF=31%s\r\n\r\n",
+ tFontName, tFontStyle, tFontColor, (parFlags & MSG_RTL) ? ";RL=1" : "" );
+ }
+
+ return sendPacket( "MSG", "%c %d\r\n%s%s", msgType, strlen( parMsg )+strlen( tHeader ), tHeader, parMsg );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendRawPacket - sends a packet accordingly to the MSN protocol
+
+LONG ThreadData::sendRawMessage( int msgType, const char* data, int datLen )
+{
+ if ( data == NULL )
+ data = "";
+
+ if ( datLen == -1 )
+ datLen = strlen( data );
+
+ char* buf = ( char* )alloca( datLen + 100 );
+
+ LONG thisTrid = MyInterlockedIncrement( &mTrid );
+ int nBytes = mir_snprintf( buf, 100, "MSG %d %c %d\r\n%s",
+ thisTrid, msgType, datLen + sizeof(sttHeaderStart)-1, sttHeaderStart );
+ memcpy( buf + nBytes, data, datLen );
+ send( buf, nBytes + datLen );
+
+ return thisTrid;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_RenameServerGroup - renames a group at the server
+
+void MSN_RenameServerGroup( int iNumber, LPCSTR szId, const char* newName )
+{
+ LPCSTR oldId = MSN_GetGroupByName( newName );
+ if ( oldId == NULL ) {
+ char szNewName[ 256 ];
+ UrlEncode( newName, szNewName, sizeof szNewName );
+ msnNsThread->sendPacket( "REG", "%s %s", szId, szNewName );
+ }
+ else MSN_SetGroupNumber( oldId, iNumber );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Msn_SendNickname - update our own nickname on the server
+
+int __stdcall MSN_SendNickname(char *nickname)
+{
+ char urlNick[ 387 ];
+ UrlEncode( UTF8(nickname), urlNick, sizeof( urlNick ));
+ msnNsThread->sendPacket( "PRP", "MFN %s", urlNick );
+ return 0;
+}
+
+int __stdcall MSN_SendNicknameW( WCHAR* nickname)
+{
+ char* nickutf = Utf8EncodeUcs2( nickname );
+
+ char urlNick[ 387 ];
+ UrlEncode( nickutf, urlNick, sizeof( urlNick ));
+ msnNsThread->sendPacket( "PRP", "MFN %s", urlNick );
+
+ free( nickutf );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendStatusMessage - notify a server about the status message change
+
+void __stdcall MSN_SendStatusMessage( const char* msg )
+{
+ if ( !msnLoggedIn || !MyOptions.UseMSNP11 )
+ return;
+
+ char* msgEnc = HtmlEncode(( msg == NULL ) ? "" : msg );
+ char szMsg[ 1024 ], szEmail[ MSN_MAX_EMAIL_LEN ];
+ mir_snprintf( szMsg, sizeof szMsg, "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia></Data>", UTF8(msgEnc));
+ free( msgEnc );
+
+ if ( !lstrcmpA( msnPreviousUUX, szMsg ))
+ return;
+
+ replaceStr( msnPreviousUUX, szMsg );
+ if ( !MSN_GetStaticString( "e-mail", NULL, szEmail, sizeof szEmail ))
+ msnNsThread->sendPacket( "UUX", "%d\r\n%s", strlen( szMsg ), szMsg );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SendPacket - sends a packet accordingly to the MSN protocol
+
+LONG ThreadData::sendPacket( const char* cmd, const char* fmt,...)
+{
+ if ( this == NULL ) // :)
+ return 0;
+
+ if ( !strcmp( cmd, "CAL" ) && mIsCalSent )
+ return 0;
+
+ va_list vararg;
+ va_start( vararg, fmt );
+
+ int strsize = 512;
+ char* str = ( char* )malloc( strsize );
+
+ LONG thisTrid = MyInterlockedIncrement( &mTrid );
+
+ if ( fmt == NULL || fmt[0] == '\0' )
+ sprintf( str, "%s %d", cmd, thisTrid );
+ else {
+ int paramStart = sprintf( str, "%s %d ", cmd, thisTrid );
+ while ( _vsnprintf( str+paramStart, strsize-paramStart-2, fmt, vararg ) == -1 )
+ str = (char*)realloc( str, strsize += 512 );
+ }
+
+ if ( strcmp( cmd, "MSG" ) && strcmp( cmd, "QRY" ) && strcmp( cmd, "UUX" ))
+ strcat( str,"\r\n" );
+
+ if ( !strcmp( cmd, "CAL" ))
+ mIsCalSent = true;
+
+ int result = send( str, strlen( str ));
+ free( str );
+ return ( result > 0 ) ? thisTrid : -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SetServerStatus - changes plugins status at the server
+
+void __stdcall MSN_SetServerStatus( int newStatus )
+{
+ MSN_DebugLog( "Setting MSN server status %d, logged in = %d", newStatus, msnLoggedIn );
+
+ if ( !msnLoggedIn )
+ return;
+
+ char* szStatusName = MirandaStatusToMSN( newStatus );
+
+ if ( newStatus != ID_STATUS_OFFLINE ) {
+ char szMsnObject[ 1000 ];
+ if ( MSN_GetStaticString( "PictObject", NULL, szMsnObject, sizeof szMsnObject ))
+ szMsnObject[ 0 ] = 0;
+
+ //here we say what functions can be used with this plugins : http://siebe.bot2k3.net/docs/?url=clientid.html
+ msnNsThread->sendPacket( "CHG", "%s 1342177280 %s", szStatusName, szMsnObject );
+
+ if ( MyOptions.UseMSNP11 ) {
+ for ( int i=0; i < MSN_NUM_MODES; i++ ) {
+ if ( msnModeMsgs[ i ].m_mode == newStatus ) {
+ MSN_SendStatusMessage( msnModeMsgs[ i ].m_msg );
+ break;
+ } } }
+ }
+ else msnNsThread->sendPacket( "CHG", szStatusName );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_ShowError - shows an error
+
+void __cdecl MSN_ShowError( const char* msgtext, ... )
+{
+ char tBuffer[ 4096 ];
+ va_list tArgs;
+
+ va_start( tArgs, msgtext );
+ mir_vsnprintf( tBuffer, sizeof( tBuffer ), MSN_Translate( msgtext ), tArgs );
+ va_end( tArgs );
+
+ if ( MyOptions.ShowErrorsAsPopups )
+ MSN_ShowPopup( msnProtocolName, tBuffer, MSN_ALLOW_MSGBOX | MSN_SHOW_ERROR );
+ else
+ MessageBoxA( NULL, tBuffer, msnProtocolName, MB_OK );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_ShowPopup - popup plugin support
+
+void CALLBACK sttMainThreadCallback( ULONG dwParam )
+{
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )dwParam;
+
+ if ( msnUseExtendedPopups )
+ MSN_CallService( MS_POPUP_ADDPOPUPEX, ( WPARAM )ppd, 0 );
+ else
+ MSN_CallService( MS_POPUP_ADDPOPUP, ( WPARAM )ppd, 0 );
+
+ free( ppd );
+}
+
+void __stdcall MSN_ShowPopup( const char* nickname, const char* msg, int flags )
+{
+ if ( !ServiceExists( MS_POPUP_ADDPOPUP )) {
+ if ( flags & MSN_ALLOW_MSGBOX )
+ MessageBoxA( NULL, msg, "MSN Protocol", MB_OK + ( flags & MSN_SHOW_ERROR ) ? MB_ICONERROR : MB_ICONINFORMATION );
+
+ return;
+ }
+
+ POPUPDATAEX* ppd = ( POPUPDATAEX* )calloc( sizeof( POPUPDATAEX ), 1 );
+
+ ppd->lchContact = NULL;
+ ppd->lchIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSN ));
+ strcpy( ppd->lpzContactName, nickname );
+ strcpy( ppd->lpzText, msg );
+
+ if ( flags & MSN_SHOW_ERROR ) {
+ ppd->lchIcon = LoadIcon( NULL, IDI_WARNING );
+ if ( ServiceExists( MS_POPUP_ADDCLASS ))
+ ppd->lpzClass = _T(POPUP_CLASS_WARNING);
+ else {
+ ppd->colorBack = RGB(191,0,0); //Red
+ ppd->colorText = RGB(255,245,225); //Yellow
+ }
+
+ ppd->iSeconds = 60;
+ }
+ else {
+ ppd->colorBack = ( MyOptions.UseWinColors ) ? GetSysColor( COLOR_BTNFACE ) : MyOptions.BGColour;
+ ppd->colorText = ( MyOptions.UseWinColors ) ? GetSysColor( COLOR_WINDOWTEXT ) : MyOptions.TextColour;
+ if ( msnUseExtendedPopups )
+ ppd->iSeconds = ( flags & MSN_HOTMAIL_POPUP ) ? MyOptions.PopupTimeoutHotmail : MyOptions.PopupTimeoutOther;
+ }
+
+ ppd->PluginWindowProc = ( WNDPROC )NullWindowProc;
+ ppd->PluginData = ( flags & MSN_ALLOW_ENTER ) ? &ppd : NULL;
+
+ QueueUserAPC( sttMainThreadCallback , msnMainThread, ( ULONG )ppd );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_StoreLen - stores a message's length in a buffer
+
+char* __stdcall MSN_StoreLen( char* dest, char* last )
+{
+ char tBuffer[ 20 ];
+ ltoa( short( last-dest )-7, tBuffer, 10 );
+ int cbDigits = strlen( tBuffer );
+ memcpy( dest, tBuffer, cbDigits );
+ memmove( dest + cbDigits, dest + 5, int( last-dest )-7 );
+ return last - ( 5 - cbDigits );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// UrlDecode - converts URL chars like %20 into printable characters
+
+static int SingleHexToDecimal(char c)
+{
+ if ( c >= '0' && c <= '9' ) return c-'0';
+ if ( c >= 'a' && c <= 'f' ) return c-'a'+10;
+ if ( c >= 'A' && c <= 'F' ) return c-'A'+10;
+ return -1;
+}
+
+void __stdcall UrlDecode( char* str )
+{
+ char* s = str, *d = str;
+
+ while( *s )
+ {
+ if ( *s != '%' ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ int digit1 = SingleHexToDecimal( s[1] ), digit2 = SingleHexToDecimal( s[2] );
+ if ( digit1 == -1 || digit2 == -1 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ s += 3;
+ *d++ = ( digit1 << 4 ) + digit2;
+ }
+
+ *d = 0;
+}
+
+void __stdcall HtmlDecode( char* str )
+{
+ char* p, *q;
+
+ if ( str == NULL )
+ return;
+
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !strncmp( p, "&amp;", 5 )) { *q = '&'; p += 4; }
+ else if ( !strncmp( p, "&apos;", 6 )) { *q = '\''; p += 5; }
+ else if ( !strncmp( p, "&gt;", 4 )) { *q = '>'; p += 3; }
+ else if ( !strncmp( p, "&lt;", 4 )) { *q = '<'; p += 3; }
+ else if ( !strncmp( p, "&quot;", 6 )) { *q = '"'; p += 5; }
+ else { *q = *p; }
+ }
+ else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// HtmlEncode - replaces special HTML chars
+
+char* __stdcall HtmlEncode( const char* str )
+{
+ char* s, *p, *q;
+ int c;
+
+ if ( str == NULL )
+ return NULL;
+
+ for ( c=0,p=( char* )str; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': c += 5; break;
+ case '\'': c += 6; break;
+ case '>': c += 4; break;
+ case '<': c += 4; break;
+ case '"': c += 6; break;
+ default: c++; break;
+ }
+ }
+ if (( s=( char* )malloc( c+1 )) != NULL ) {
+ for ( p=( char* )str,q=s; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': strcpy( q, "&amp;" ); q += 5; break;
+ case '\'': strcpy( q, "&apos;" ); q += 6; break;
+ case '>': strcpy( q, "&gt;" ); q += 4; break;
+ case '<': strcpy( q, "&lt;" ); q += 4; break;
+ case '"': strcpy( q, "&quot;" ); q += 6; break;
+ default: *q = *p; q++; break;
+ }
+ }
+ *q = '\0';
+ }
+
+ return s;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// UrlEncode - converts printable characters into URL chars like %20
+
+void __stdcall UrlEncode( const char* src,char* dest, int cbDest )
+{
+ BYTE* d = ( BYTE* )dest;
+ int i = 0;
+
+ for( const BYTE* s = ( const BYTE* )src; *s; s++ ) {
+ if (( *s < '0' && *s != '.' && *s != '-' ) ||
+ ( *s >= ':' && *s <= '?' ) ||
+ ( *s >= '[' && *s <= '`' && *s != '_' ))
+ {
+ if ( i >= cbDest-4 )
+ break;
+
+ *d++ = '%';
+ _itoa( *s, ( char* )d, 16 );
+ d += 2;
+ i += 3;
+ }
+ else
+ {
+ *d++ = *s;
+ if ( i++ == cbDest-1 )
+ break;
+ } }
+
+ *d = '\0';
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+void __stdcall Utf8Decode( char* str, wchar_t** ucs2 )
+{
+ if ( str == NULL )
+ return;
+
+ int len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )malloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return;
+ }
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ {
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+ }
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )malloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, len, NULL, NULL );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+char* __stdcall Utf8Encode( const char* src )
+{
+ if ( src == NULL )
+ return NULL;
+
+ int len = strlen( src );
+ char* result = ( char* )malloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, src, -1, tempBuf, len );
+ tempBuf[ len ] = 0;
+ {
+ wchar_t* s = tempBuf;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+char* __stdcall Utf8EncodeUcs2( const wchar_t* src )
+{
+ int len = wcslen( src );
+ char* result = ( char* )malloc( len*3 + 1 );
+ if ( result == NULL )
+ return NULL;
+
+ { const wchar_t* s = src;
+ BYTE* d = ( BYTE* )result;
+
+ while( *s ) {
+ int U = *s++;
+
+ if ( U < 0x80 ) {
+ *d++ = ( BYTE )U;
+ }
+ else if ( U < 0x800 ) {
+ *d++ = 0xC0 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x003F );
+ }
+ else {
+ *d++ = 0xE0 + ( U >> 12 );
+ *d++ = 0x80 + (( U >> 6 ) & 0x3F );
+ *d++ = 0x80 + ( U & 0x3F );
+ } }
+
+ *d = 0;
+ }
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// filetransfer class members
+
+filetransfer::filetransfer()
+{
+ memset( this, 0, sizeof( filetransfer ));
+ fileId = -1;
+ hWaitEvent = INVALID_HANDLE_VALUE;
+ std.cbSize = sizeof( std );
+}
+
+filetransfer::~filetransfer()
+{
+ MSN_DebugLog( "Destroying file transfer session %lu", p2p_sessionid );
+
+ if ( !bCompleted ) {
+ std.files = NULL;
+ std.totalFiles = 0;
+ MSN_SendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, this, 0);
+ }
+
+ if ( inmemTransfer ) {
+ if ( fileBuffer != NULL )
+ LocalFree( fileBuffer );
+ }
+ else if ( fileId != -1 )
+ _close( fileId );
+
+ if ( mIncomingBoundPort != NULL ) {
+ ThreadData* T = MSN_GetThreadByPort(mIncomingPort);
+ if ( T != NULL && T->s != NULL )
+ {
+ Netlib_CloseHandle( T->s );
+ T->s = NULL;
+ }
+ Netlib_CloseHandle( mIncomingBoundPort );
+ }
+
+ if ( hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( hWaitEvent );
+
+ if ( p2p_branch != NULL ) free( p2p_branch );
+ if ( p2p_callID != NULL ) free( p2p_callID );
+ if ( p2p_dest != NULL ) free( p2p_dest );
+
+ if ( std.currentFile != NULL ) free( std.currentFile );
+ if ( std.workingDir != NULL ) free( std.workingDir );
+ if ( std.files != NULL ) {
+ for ( int i=0; i < std.totalFiles; i++ )
+ mir_free( std.files[ i ] );
+ mir_free( std.files );
+ }
+
+ if ( wszFileName != NULL ) free( wszFileName );
+ if ( szInvcookie != NULL ) free( szInvcookie );
+}
+
+void filetransfer::close()
+{
+ if ( !inmemTransfer && fileId != -1 ) {
+ _close( fileId );
+ fileId = -1;
+} }
+
+void filetransfer::complete()
+{
+ close();
+
+ bCompleted = true;
+ MSN_SendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0);
+}
+
+int filetransfer::create()
+{
+ if ( inmemTransfer ) {
+ if ( fileBuffer == NULL ) {
+ if ( std.totalBytes == 0 ) {
+ MSN_DebugLog( "Zero buffer size was requested for avatar" );
+ return -1;
+ }
+
+ if (( fileBuffer = ( char* )LocalAlloc( LPTR, DWORD( std.totalBytes ))) == NULL ) {
+ MSN_DebugLog( "Not enough memory to receive file '%s'", std.currentFile );
+ return -1;
+ } }
+
+ return ( int )fileBuffer;
+ }
+
+ #if defined( _UNICODE )
+ if ( wszFileName != NULL ) {
+ WCHAR wszTemp[ MAX_PATH ];
+ _snwprintf( wszTemp, sizeof wszTemp, L"%S\\%s", std.workingDir, wszFileName );
+ wszTemp[ MAX_PATH-1 ] = 0;
+ fileId = _wopen( wszTemp, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if ( fileId != -1 ) {
+ WIN32_FIND_DATAW data;
+ HANDLE hFind = FindFirstFileW( wszFileName, &data );
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ free( std.currentFile );
+
+ char tShortName[ 20 ];
+ WideCharToMultiByte( CP_ACP, 0,
+ ( data.cAlternateFileName[0] != 0 ) ? data.cAlternateFileName : data.cFileName,
+ -1, tShortName, sizeof tShortName, 0, 0 );
+ char filefull[ MAX_PATH ];
+ mir_snprintf( filefull, sizeof( filefull ), "%s\\%s", std.workingDir, tShortName );
+ std.currentFile = strdup( filefull );
+ FindClose( hFind );
+ } }
+ }
+ else fileId = _open( std.currentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE );
+ #else
+ fileId = _open( std.currentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE );
+ #endif
+
+ if ( fileId == -1 )
+ MSN_DebugLog( "Cannot create file '%s' during a file transfer", std.currentFile );
+// else if ( std.currentFileSize != 0 )
+// _chsize( fileId, std.currentFileSize );
+
+ return fileId;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// TWinErrorCode class
+
+TWinErrorCode::TWinErrorCode() :
+ mErrorText( NULL )
+{
+ mErrorCode = ::GetLastError();
+}
+
+TWinErrorCode::~TWinErrorCode()
+{
+ if ( mErrorText != NULL )
+ ::LocalFree( mErrorText );
+}
+
+char* TWinErrorCode::getText()
+{
+ if ( mErrorText == NULL )
+ {
+ int tBytes = 0;
+
+ if ( mErrorCode >= 12000 && mErrorCode < 12500 )
+ tBytes = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ ::GetModuleHandleA( "WININET.DLL" ),
+ mErrorCode, LANG_NEUTRAL, (LPSTR)&mErrorText, 0, NULL );
+
+ if ( tBytes == 0 )
+ tBytes = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+ mErrorCode, LANG_NEUTRAL, (LPSTR)&mErrorText, 0, NULL );
+
+ if ( tBytes == 0 )
+ {
+ mErrorText = ( LPSTR )LocalAlloc( LMEM_FIXED, 100 );
+ tBytes = mir_snprintf( mErrorText, 100, "unknown Windows error code %d", mErrorCode );
+ }
+
+ *mErrorText = tolower( *mErrorText );
+
+ if ( mErrorText[ tBytes-1 ] == '\n' )
+ mErrorText[ --tBytes ] = 0;
+ if ( mErrorText[ tBytes-1 ] == '\r' )
+ mErrorText[ --tBytes ] = 0;
+ if ( mErrorText[ tBytes-1 ] == '.' )
+ mErrorText[ tBytes-1 ] = 0;
+ }
+
+ return mErrorText;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// InterlockedIncrement emulation
+
+//I hate Microsoft (c) cyreve
+
+static LONG WINAPI MyInterlockedIncrement95(PLONG pVal)
+{
+ DWORD ret;
+ EnterCriticalSection(&csInterlocked95);
+ ret=++*pVal;
+ LeaveCriticalSection(&csInterlocked95);
+ return ret;
+}
+
+//there's a possible hole here if too many people call this at the same time, but that doesn't happen
+
+static LONG WINAPI MyInterlockedIncrementInit(PLONG pVal)
+{
+ DWORD ver = GetVersion();
+ if (( ver & 0x80000000 ) && LOWORD( ver ) == 0x0004 )
+ {
+ InitializeCriticalSection( &csInterlocked95 );
+ MyInterlockedIncrement = MyInterlockedIncrement95;
+ }
+ else MyInterlockedIncrement = ( pIncrementFunc* )InterlockedIncrement;
+
+ return MyInterlockedIncrement( pVal );
+}
+
+// Process a string, and double all % characters, according to chat.dll's restrictions
+// Returns a pointer to the new string (old one is not freed)
+char* EscapeChatTags(char* pszText)
+{
+ int nChars = 0;
+ for ( char* p = pszText; ( p = strchr( p, '%' )) != NULL; p++ )
+ nChars++;
+
+ if ( nChars == 0 )
+ return _strdup( pszText );
+
+ char* pszNewText = (char*)malloc( strlen( pszText ) + 1 + nChars ), *s, *d;
+ if ( pszNewText == NULL )
+ return _strdup( pszText );
+
+ for ( s = pszText, d = pszNewText; *s; s++ ) {
+ if ( *s == '%' )
+ *d++ = '%';
+ *d++ = *s;
+ }
+ *d = 0;
+ return pszNewText;
+}
+
+char* UnEscapeChatTags(char* str_in)
+{
+ char* s = str_in, *d = str_in;
+ while ( *s ) {
+ if (( *s == '%' && s[1] == '%' ) || ( *s == '\n' && s[1] == '\n' ))
+ s++;
+ *d++ = *s++;
+ }
+ *d = 0;
+ return str_in;
+}
diff --git a/miranda-wine/protocols/MSN/msn_msgqueue.cpp b/miranda-wine/protocols/MSN/msn_msgqueue.cpp
new file mode 100644
index 0000000..9fc9458
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_msgqueue.cpp
@@ -0,0 +1,162 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+//a few little functions to manage queuing send message requests until the
+//connection is established
+
+static MsgQueueEntry* msgQueue;
+static int msgQueueCount;
+static CRITICAL_SECTION csMsgQueue;
+static int msgQueueSeq;
+
+void MsgQueue_Init( void )
+{
+ msgQueueCount = 0;
+ msgQueue = NULL;
+ msgQueueSeq = 1;
+ InitializeCriticalSection( &csMsgQueue );
+}
+
+void MsgQueue_Uninit( void )
+{
+ MsgQueue_Clear( NULL );
+ DeleteCriticalSection( &csMsgQueue );
+}
+
+int __stdcall MsgQueue_Add( HANDLE hContact, int msgType, const char* msg, int msgSize, filetransfer* ft, int flags )
+{
+ EnterCriticalSection( &csMsgQueue );
+ msgQueue = ( MsgQueueEntry* )realloc( msgQueue, sizeof( MsgQueueEntry )*( msgQueueCount+1 ));
+
+ int seq = msgQueueSeq++;
+
+ MsgQueueEntry& E = msgQueue[ msgQueueCount++ ];
+ E.hContact = hContact;
+ E.msgSize = msgSize;
+ E.msgType = msgType;
+ if ( msgSize <= 0 )
+ E.message = strdup( msg );
+ else
+ memcpy( E.message = ( char* )malloc( msgSize ), msg, msgSize );
+ E.ft = ft;
+ E.seq = seq;
+ E.flags = flags;
+ E.allocatedToThread = 0;
+ E.timeout = DBGetContactSettingDword(NULL, "SRMM", "MessageTimeout", 10000)/1000;
+
+ LeaveCriticalSection( &csMsgQueue );
+ return seq;
+}
+
+// shall we create another session?
+HANDLE __stdcall MsgQueue_CheckContact( HANDLE hContact )
+{
+ EnterCriticalSection( &csMsgQueue );
+
+ HANDLE ret = NULL;
+ for( int i=0; i < msgQueueCount; i++ )
+ {
+ if ( msgQueue[ i ].hContact == hContact )
+ { ret = hContact;
+ break;
+ } }
+
+ LeaveCriticalSection( &csMsgQueue );
+ return ret;
+}
+
+//for threads to determine who they should connect to
+HANDLE __stdcall MsgQueue_GetNextRecipient(void)
+{
+ EnterCriticalSection( &csMsgQueue );
+
+ HANDLE ret = NULL;
+ for( int i=0; i < msgQueueCount; i++ )
+ {
+ MsgQueueEntry& E = msgQueue[ i ];
+ if ( !E.allocatedToThread )
+ {
+ E.allocatedToThread = 1;
+ ret = E.hContact;
+
+ while( ++i < msgQueueCount )
+ if ( msgQueue[i].hContact == ret )
+ msgQueue[i].allocatedToThread = 1;
+
+ break;
+ } }
+
+ LeaveCriticalSection( &csMsgQueue );
+ return ret;
+}
+
+//deletes from list. Must free() return value
+int __stdcall MsgQueue_GetNext( HANDLE hContact, MsgQueueEntry& retVal )
+{
+ int i;
+
+ EnterCriticalSection( &csMsgQueue );
+ for( i=0; i < msgQueueCount; i++ )
+ if ( msgQueue[ i ].hContact == hContact )
+ break;
+
+ if ( i == msgQueueCount )
+ { LeaveCriticalSection(&csMsgQueue);
+ return 0;
+ }
+
+ retVal = msgQueue[ i ];
+
+ msgQueueCount--;
+ memmove( msgQueue+i, msgQueue+i+1, sizeof( MsgQueueEntry )*( msgQueueCount-i ));
+ msgQueue = ( MsgQueueEntry* )realloc( msgQueue, sizeof( MsgQueueEntry )*msgQueueCount );
+ LeaveCriticalSection( &csMsgQueue );
+ return i+1;
+}
+
+void __stdcall MsgQueue_Clear( HANDLE hContact )
+{
+ int i;
+
+ if (hContact == NULL)
+ {
+ EnterCriticalSection( &csMsgQueue );
+
+ for( i=0; i < msgQueueCount; i++ )
+ free ( msgQueue[ i ].message );
+ free( msgQueue );
+
+ msgQueueCount = 0;
+ msgQueue = NULL;
+ msgQueueSeq = 1;
+ LeaveCriticalSection( &csMsgQueue );
+ }
+ else
+ {
+ MsgQueueEntry E;
+ while (MsgQueue_GetNext(hContact, E) != 0)
+ free( E.message );
+ }
+}
diff --git a/miranda-wine/protocols/MSN/msn_opts.cpp b/miranda-wine/protocols/MSN/msn_opts.cpp
new file mode 100644
index 0000000..f47b317
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_opts.cpp
@@ -0,0 +1,866 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <commdlg.h>
+#include <direct.h>
+
+#include "resource.h"
+#include "msn_md5.h"
+#include "uxtheme.h"
+
+#define STYLE_DEFAULTBGCOLOUR RGB(173,206,247)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// External data declarations
+
+extern unsigned long sl;
+extern char *rru;
+
+static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
+
+BOOL CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static void __cdecl sttUploadGroups( void* )
+{
+ HANDLE hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA( msnProtocolName, ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact,0 ))) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingStringUtf( hContact, "CList", "Group", &dbv )) {
+ MSN_MoveContactToGroup( hContact, dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ } }
+
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN Options dialog procedure
+
+static BOOL CALLBACK DlgProcMsnOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault( hwndDlg );
+
+ char tBuffer[ MAX_PATH ];
+ if ( !MSN_GetStaticString( "e-mail", NULL, tBuffer, sizeof( tBuffer )))
+ SetDlgItemTextA( hwndDlg, IDC_HANDLE, tBuffer );
+
+ if ( !MSN_GetStaticString( "Password", NULL, tBuffer, sizeof( tBuffer ))) {
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( tBuffer )+1, ( LPARAM )tBuffer );
+ tBuffer[ 16 ] = 0;
+ SetDlgItemTextA( hwndDlg, IDC_PASSWORD, tBuffer );
+ }
+ SendDlgItemMessage( hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, 16, 0 );
+
+ HWND wnd = GetDlgItem( hwndDlg, IDC_HANDLE2 );
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ SetWindowText( wnd, dbv.ptszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ if ( !msnLoggedIn )
+ EnableWindow( wnd, FALSE );
+
+ CheckDlgButton( hwndDlg, IDC_DISABLE_MAIN_MENU, MSN_GetByte( "DisableSetNickname", 0 ));
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, MSN_GetByte( "EnableAvatars", 0 ));
+ CheckDlgButton( hwndDlg, IDC_SENDFONTINFO, MSN_GetByte( "SendFontInfo", 1 ));
+ CheckDlgButton( hwndDlg, IDC_USE_OWN_NICKNAME, MSN_GetByte( "NeverUpdateNickname", 0 ));
+ CheckDlgButton( hwndDlg, IDC_AWAY_AS_BRB, MSN_GetByte( "AwayAsBrb", 0 ));
+ CheckDlgButton( hwndDlg, IDC_MANAGEGROUPS, MSN_GetByte( "ManageServer", 0 ));
+
+ int tValue = MSN_GetByte( "RunMailerOnHotmail", 0 );
+ CheckDlgButton( hwndDlg, IDC_RUN_APP_ON_HOTMAIL, tValue );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MAILER_APP ), tValue );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_ENTER_MAILER_APP ), tValue );
+
+ if ( !MSN_GetStaticString( "MailerPath", NULL, tBuffer, sizeof( tBuffer )))
+ SetDlgItemTextA( hwndDlg, IDC_MAILER_APP, tBuffer );
+
+ if ( !msnLoggedIn ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MANAGEGROUPS ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS ), FALSE );
+ }
+ else CheckDlgButton( hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS, msnOtherContactsBlocked );
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ if ( LOWORD( wParam ) == IDC_NEWMSNACCOUNTLINK ) {
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )"http://lc2.law13.hotmail.passport.com/cgi-bin/register" );
+ return TRUE;
+ }
+
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) {
+ switch( LOWORD( wParam )) {
+ case IDC_HANDLE: case IDC_PASSWORD: case IDC_LOGINSERVER:
+ case IDC_MSNPORT: case IDC_YOURHOST: case IDC_HANDLE2:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } }
+
+ if ( HIWORD( wParam ) == BN_CLICKED )
+ switch( LOWORD( wParam )) {
+ case IDC_ENABLE_AVATARS: {
+ BYTE tIsChosen = IsDlgButtonChecked( hwndDlg, IDC_ENABLE_AVATARS );
+ if ( tIsChosen && MSN_LoadPngModule() == NULL ) {
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, 0 );
+ break;
+ }
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SETAVATAR ), tIsChosen );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETEAVATAR ), tIsChosen );
+ }
+
+ case IDC_DISABLE_MAIN_MENU: case IDC_SENDFONTINFO:
+ case IDC_DISABLE_ANOTHER_CONTACTS: case IDC_USE_OWN_NICKNAME:
+ case IDC_AWAY_AS_BRB:
+ LBL_Apply:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_MANAGEGROUPS:
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANAGEGROUPS ))
+ if ( IDYES == MessageBox( hwndDlg,
+ TranslateT( "Server groups import may change your contact list layout after next login. Do you want to upload your groups to the server?" ),
+ TranslateT( "MSN Protocol" ), MB_YESNOCANCEL ))
+ (new ThreadData())->startThread( sttUploadGroups );
+ goto LBL_Apply;
+
+ case IDC_RUN_APP_ON_HOTMAIL: {
+ BYTE tIsChosen = IsDlgButtonChecked( hwndDlg, IDC_RUN_APP_ON_HOTMAIL );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MAILER_APP ), tIsChosen );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_ENTER_MAILER_APP ), tIsChosen );
+ goto LBL_Apply;
+ }
+
+ case IDC_ENTER_MAILER_APP: {
+ HWND tEditField = GetDlgItem( hwndDlg, IDC_MAILER_APP );
+
+ char szFile[ MAX_PATH+2 ];
+ GetWindowTextA( tEditField, szFile, sizeof( szFile ));
+
+ int tSelectLen = 0;
+
+ if ( szFile[0] == '\"' ) {
+ char* p = strchr( szFile+1, '\"' );
+ if ( p != NULL ) {
+ *p = '\0';
+ strdel( szFile, 1 );
+ tSelectLen += 2;
+ goto LBL_Continue;
+ } }
+
+ { char* p = strchr( szFile, ' ' );
+ if ( p != NULL )
+ *p = '\0';
+ }
+LBL_Continue:
+ tSelectLen += strlen( szFile );
+
+ OPENFILENAMEA ofn = { 0 };
+ ofn.lStructSize = sizeof( ofn );
+ ofn.hwndOwner = hwndDlg;
+ ofn.nMaxFile = sizeof( szFile );
+ ofn.lpstrFile = szFile;
+ ofn.Flags = OFN_FILEMUSTEXIST;
+ if ( GetOpenFileNameA( &ofn ) != TRUE )
+ break;
+
+ if ( strchr( szFile, ' ' ) != NULL ) {
+ char tmpBuf[ MAX_PATH+2 ];
+ mir_snprintf( tmpBuf, sizeof( tmpBuf ), "\"%s\"", szFile );
+ strcpy( szFile, tmpBuf );
+ }
+
+ SendMessage( tEditField, EM_SETSEL, 0, tSelectLen );
+ SendMessage( tEditField, EM_REPLACESEL, TRUE, LPARAM( szFile ));
+ goto LBL_Apply;
+ } }
+
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ bool reconnectRequired = false, restartRequired = false;
+ TCHAR screenStr[ MAX_PATH ], dbStr[ MAX_PATH ];
+ char password[ 100 ];
+ DBVARIANT dbv;
+
+ GetDlgItemText( hwndDlg, IDC_HANDLE, screenStr, sizeof( screenStr ));
+ if ( DBGetContactSettingTString( "e-mail", msnProtocolName, NULL, &dbv ))
+ dbv.ptszVal = NULL;
+ if ( lstrcmp( screenStr, dbStr ))
+ reconnectRequired = true;
+ MSN_SetStringT( NULL, "e-mail", screenStr );
+ MSN_FreeVariant( &dbv );
+
+ GetDlgItemTextA( hwndDlg, IDC_PASSWORD, password, sizeof( password ));
+ MSN_CallService( MS_DB_CRYPT_ENCODESTRING, sizeof( password ),( LPARAM )password );
+ if ( DBGetContactSetting( "Password", msnProtocolName, NULL, &dbv ))
+ dbv.pszVal = NULL;
+ if ( lstrcmp( screenStr, dbStr ))
+ reconnectRequired = true;
+ MSN_SetString( NULL, "Password", password );
+ MSN_FreeVariant( &dbv );
+
+ GetDlgItemText( hwndDlg, IDC_HANDLE2, screenStr, sizeof( screenStr ));
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ if ( lstrcmp( dbv.ptszVal, screenStr ))
+ MSN_SendNicknameT( screenStr );
+ MSN_FreeVariant( &dbv );
+ }
+ MSN_SetStringT( NULL, "Nick", screenStr );
+
+ BYTE tValue = IsDlgButtonChecked( hwndDlg, IDC_DISABLE_ANOTHER_CONTACTS );
+ if ( tValue != msnOtherContactsBlocked && msnLoggedIn ) {
+ msnNsThread->sendPacket( "BLP", ( tValue ) ? "BL" : "AL" );
+ break;
+ }
+
+ MSN_SetByte( "EnableAvatars", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_ENABLE_AVATARS ));
+ MSN_SetByte( "SendFontInfo", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_SENDFONTINFO ));
+ MSN_SetByte( "RunMailerOnHotmail", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_RUN_APP_ON_HOTMAIL ));
+ MSN_SetByte( "NeverUpdateNickname", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USE_OWN_NICKNAME ));
+ MSN_SetByte( "DisableSetNickname", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLE_MAIN_MENU ));
+ MSN_SetByte( "AwayAsBrb", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AWAY_AS_BRB ));
+ MSN_SetByte( "ManageServer", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_MANAGEGROUPS ));
+
+ GetDlgItemText( hwndDlg, IDC_MAILER_APP, screenStr, sizeof( screenStr ));
+ MSN_SetStringT( NULL, "MailerPath", screenStr );
+
+ if ( reconnectRequired && msnLoggedIn )
+ MessageBox( hwndDlg, TranslateT( "The changes you have made require you to reconnect to the MSN Messenger network before they take effect"), _T("MSN Options"), MB_OK );
+
+ LoadOptions();
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN Connection Options dialog procedure
+
+static BOOL CALLBACK DlgProcMsnConnOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DBVARIANT dbv;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ int tUseGateway = MSN_GetByte( "UseGateway", 0 );
+ CheckDlgButton( hwndDlg, IDC_USEGATEWAY, tUseGateway );
+ if ( tUseGateway ) {
+ SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, MSN_DEFAULT_GATEWAY );
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, 80, FALSE );
+ }
+ else {
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "LoginServer", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, MSN_DEFAULT_LOGIN_SERVER );
+
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, MSN_GetWord( NULL, "MSNMPort", 1863 ), FALSE );
+ } }
+
+ CheckDlgButton( hwndDlg, IDC_KEEPALIVE, MSN_GetByte( "KeepAlive", 0 ));
+ CheckDlgButton( hwndDlg, IDC_AUTOGETHOST, MSN_GetByte( "AutoGetHost", 1 ));
+ CheckDlgButton( hwndDlg, IDC_USEIEPROXY, MSN_GetByte( "UseIeProxy", 0 ));
+ CheckDlgButton( hwndDlg, IDC_SLOWSEND, MSN_GetByte( "SlowSend", 0 ));
+ CheckDlgButton( hwndDlg, IDC_USEMSNP11, MSN_GetByte( "UseMSNP11", 0 ));
+ CheckDlgButton( hwndDlg, IDC_USEOPENSSL, MSN_GetByte( "UseOpenSSL", 0 ));
+
+ {
+ DWORD ptype = MSN_GetByte( "NLProxyType", 0 );
+ BOOL httpproxy = MyOptions.UseProxy && (ptype == PROXYTYPE_HTTP || ptype == PROXYTYPE_HTTPS);
+ EnableWindow( GetDlgItem( hwndDlg, IDC_USEGATEWAY ), !httpproxy);
+ }
+
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "YourHost", &dbv )) {
+ if ( !MSN_GetByte( "AutoGetHost", 1 ))
+ SetDlgItemTextA( hwndDlg, IDC_YOURHOST, dbv.pszVal );
+ else {
+ if ( msnExternalIP == NULL ) {
+ char ipaddr[ 256 ];
+ gethostname( ipaddr, sizeof( ipaddr ));
+ SetDlgItemTextA( hwndDlg, IDC_YOURHOST, ipaddr );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_YOURHOST, msnExternalIP );
+ }
+ MSN_FreeVariant( &dbv );
+ }
+ else {
+ char ipaddr[256];
+ gethostname( ipaddr, sizeof( ipaddr ));
+ SetDlgItemTextA( hwndDlg, IDC_YOURHOST, ipaddr );
+ }
+
+ if ( MSN_GetByte( "AutoGetHost", 1 ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_YOURHOST), FALSE );
+
+ if ( MyOptions.UseGateway ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_LOGINSERVER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MSNPORT ), FALSE );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_RESETSERVER:
+ SetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, MSN_DEFAULT_LOGIN_SERVER );
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, 1863, FALSE );
+ goto LBL_Apply;
+ }
+
+ if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus())
+ switch( LOWORD( wParam )) {
+ case IDC_LOGINSERVER: case IDC_MSNPORT:
+ case IDC_YOURHOST:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ if ( HIWORD( wParam ) == BN_CLICKED )
+ switch( LOWORD( wParam )) {
+ case IDC_AUTOGETHOST:
+ { int tValue = IsDlgButtonChecked( hwndDlg, IDC_AUTOGETHOST ) ? FALSE : TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_YOURHOST), tValue );
+ }
+
+ case IDC_KEEPALIVE: case IDC_USEIEPROXY: case IDC_SLOWSEND:
+ case IDC_USEMSNP11: case IDC_USEOPENSSL:
+ LBL_Apply:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_USEGATEWAY: {
+ bool tValue = !IsDlgButtonChecked( hwndDlg, IDC_USEGATEWAY );
+
+ HWND tWindow = GetDlgItem( hwndDlg, IDC_LOGINSERVER );
+ if ( !tValue ) {
+ SetWindowTextA( tWindow, MSN_DEFAULT_GATEWAY );
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, 80, FALSE );
+ }
+ else {
+ if ( !DBGetContactSetting( NULL, msnProtocolName, "LoginServer", &dbv )) {
+ SetWindowTextA( tWindow, dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ else SetWindowTextA( tWindow, MSN_DEFAULT_LOGIN_SERVER );
+
+ SetDlgItemInt( hwndDlg, IDC_MSNPORT, MSN_GetWord( NULL, "MSNMPort", 1863 ), FALSE );
+ }
+
+ EnableWindow( tWindow, tValue );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MSNPORT ), tValue );
+ goto LBL_Apply;
+ } }
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ bool restartRequired = false, reconnectRequired = false;
+ char str[ MAX_PATH ];
+
+ BYTE tValue = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEGATEWAY );
+ if ( MyOptions.UseGateway != tValue ) {
+ MSN_SetByte( "UseGateway", tValue );
+ restartRequired = true;
+ }
+ if ( !tValue ) {
+ GetDlgItemTextA( hwndDlg, IDC_LOGINSERVER, str, sizeof( str ));
+ MSN_SetString( NULL, "LoginServer", str );
+
+ MSN_SetWord( NULL, "MSNMPort", GetDlgItemInt( hwndDlg, IDC_MSNPORT, NULL, FALSE ));
+ }
+
+ tValue = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEMSNP11 );
+ if ( MyOptions.UseMSNP11 != tValue ) {
+ MSN_SetByte( "UseMSNP11", tValue );
+ if ( msnLoggedIn )
+ reconnectRequired = true;
+ }
+
+ tValue = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEOPENSSL );
+ if ( MSN_GetByte( "UseOpenSSL", 0 ) != tValue ) {
+ MSN_SetByte( "UseOpenSSL", tValue );
+ if ( msnLoggedIn )
+ reconnectRequired = true;
+ }
+
+ MSN_SetByte( "UseIeProxy", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEIEPROXY ));
+ MSN_SetByte( "KeepAlive", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_KEEPALIVE ));
+ MSN_SetByte( "AutoGetHost", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTOGETHOST ));
+ MSN_SetByte( "SlowSend", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_SLOWSEND ));
+
+ GetDlgItemTextA( hwndDlg, IDC_YOURHOST, str, sizeof( str ));
+ MSN_SetString( NULL, "YourHost", str );
+
+ if ( restartRequired )
+ MessageBox( hwndDlg, TranslateT( "The changes you have made require you to restart Miranda IM before they take effect"), TranslateT( "MSN Options" ), MB_OK );
+ else if ( reconnectRequired && msnLoggedIn )
+ MessageBox( hwndDlg, TranslateT( "The changes you have made require you to reconnect to the MSN Messenger network before they take effect"), TranslateT( "MSN Options" ), MB_OK );
+
+ LoadOptions();
+ return TRUE;
+ } }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// PopUp Options Dialog: style, position, color, font...
+
+static BOOL CALLBACK DlgProcHotmailPopUpOpts( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static bool bEnabled;
+
+ switch( msg ) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+ bEnabled = false;
+
+ //Colours. First step is configuring the colours.
+ SendDlgItemMessage( hwndDlg, IDC_BGCOLOUR, CPM_SETCOLOUR, 0, MyOptions.BGColour );
+ SendDlgItemMessage( hwndDlg, IDC_TEXTCOLOUR, CPM_SETCOLOUR, 0, MyOptions.TextColour);
+
+ //Second step is disabling them if we want to use default Windows ones.
+ CheckDlgButton( hwndDlg, IDC_USEWINCOLORS, MyOptions.UseWinColors ? BST_CHECKED : BST_UNCHECKED );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BGCOLOUR), !MyOptions.UseWinColors );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_TEXTCOLOUR), !MyOptions.UseWinColors );
+
+ if ( !ServiceExists( MS_POPUP_ADDPOPUPEX ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT ), FALSE );
+ else
+ SetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT, MyOptions.PopupTimeoutHotmail, FALSE );
+
+ CheckDlgButton( hwndDlg, IDC_DISABLEHOTMAIL, MSN_GetByte( "DisableHotmail", 0 ));
+ CheckDlgButton( hwndDlg, IDC_DISABLEHOTJUNK, MSN_GetByte( "DisableHotmailJunk", 0 ));
+ CheckDlgButton( hwndDlg, IDC_NOTIFY_USERTYPE, MSN_GetByte( "DisplayTyping", 0 ));
+ CheckDlgButton( hwndDlg, IDC_NOTIFY_ENDSESSION, MSN_GetByte( "EnableSessionPopup", 0 ));
+ CheckDlgButton( hwndDlg, IDC_NOTIFY_FIRSTMSG, MSN_GetByte( "EnableDeliveryPopup", 1 ));
+ CheckDlgButton( hwndDlg, IDC_ERRORS_USING_POPUPS, MSN_GetByte( "ShowErrorsAsPopups", 0 ));
+
+ int tTimeout = MSN_GetDword( NULL, "PopupTimeout", 3 );
+ SetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT, tTimeout, FALSE );
+ SetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT2, MSN_GetDword( NULL, "PopupTimeoutOther", tTimeout ), FALSE );
+ if ( !ServiceExists( MS_POPUP_ADDPOPUPEX )) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT2 ), FALSE );
+ }
+ bEnabled = true;
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch( LOWORD( wParam )) {
+ case IDC_DISABLEHOTMAIL: {
+ HWND wnd = GetDlgItem( hwndDlg, IDC_DISABLEHOTJUNK );
+ BOOL toSet;
+ if ( SendMessage( HWND( lParam ), BM_GETCHECK, 0, 0 ) == BST_CHECKED ) {
+ SendMessage( wnd, BM_GETCHECK, BST_CHECKED, 0 );
+ toSet = FALSE;
+ }
+ else toSet = TRUE;
+
+ EnableWindow( wnd, toSet );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_POPUP_TIMEOUT ), toSet );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PREVIEW ), toSet );
+ }
+
+ case IDC_DISABLEHOTJUNK:
+ case IDC_NOTIFY_USERTYPE:
+ case IDC_NOTIFY_ENDSESSION:
+ case IDC_POPUP_TIMEOUT:
+ case IDC_POPUP_TIMEOUT2:
+ case IDC_NOTIFY_FIRSTMSG:
+ case IDC_ERRORS_USING_POPUPS:
+ if ( bEnabled )
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_BGCOLOUR: //Fall through
+ case IDC_TEXTCOLOUR:
+ if ( HIWORD( wParam ) == CPN_COLOURCHANGED ) {
+ MyOptions.BGColour = SendDlgItemMessage( hwndDlg, IDC_BGCOLOUR, CPM_GETCOLOUR, 0, 0 );
+ MyOptions.TextColour = SendDlgItemMessage( hwndDlg, IDC_TEXTCOLOUR, CPM_GETCOLOUR, 0, 0 );
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ case IDC_USEWINCOLORS:
+ MyOptions.UseWinColors = IsDlgButtonChecked( hwndDlg, IDC_USEWINCOLORS );
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BGCOLOUR ), !( MyOptions.UseWinColors ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_TEXTCOLOUR ), !( MyOptions.UseWinColors ));
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_PREVIEW:
+ MSN_ShowPopup( MSN_Translate( "A New Hotmail has come!" ), MSN_Translate( "Test: Arrival Hotmail" ), MSN_HOTMAIL_POPUP );
+ break;
+
+ case IDC_PREVIEW2:
+ MSN_ShowPopup( "vasya.pupkin@hotmail.com", MSN_Translate( "First message delivered" ), 0 );
+ break;
+ }
+ break;
+
+ case WM_NOTIFY: //Here we have pressed either the OK or the APPLY button.
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadOptions();
+ return TRUE;
+
+ case PSN_APPLY:
+ MyOptions.TextColour = SendDlgItemMessage(hwndDlg,IDC_TEXTCOLOUR,CPM_GETCOLOUR,0,0);
+ DBWriteContactSettingDword(NULL, ModuleName, "TextColour",MyOptions.TextColour);
+
+ MyOptions.BGColour = SendDlgItemMessage(hwndDlg,IDC_BGCOLOUR,CPM_GETCOLOUR,0,0);
+ DBWriteContactSettingDword(NULL, ModuleName, "BackgroundColour",MyOptions.BGColour);
+
+ if ( ServiceExists( MS_POPUP_ADDPOPUPEX )) {
+ MyOptions.PopupTimeoutHotmail = GetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT, NULL, FALSE );
+ MSN_SetDword( NULL, "PopupTimeout", MyOptions.PopupTimeoutHotmail );
+
+ MyOptions.PopupTimeoutOther = GetDlgItemInt( hwndDlg, IDC_POPUP_TIMEOUT2, NULL, FALSE );
+ MSN_SetDword( NULL, "PopupTimeoutOther", MyOptions.PopupTimeoutOther );
+ }
+
+ MyOptions.ShowErrorsAsPopups = ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_ERRORS_USING_POPUPS );
+ MSN_SetByte( "ShowErrorsAsPopups", MyOptions.ShowErrorsAsPopups );
+
+ MSN_SetByte( "UseWinColors", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_USEWINCOLORS ));
+ MSN_SetByte( "DisplayTyping", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_NOTIFY_USERTYPE ));
+ MSN_SetByte( "DisableHotmail", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLEHOTMAIL ));
+ MSN_SetByte( "DisableHotmailJunk",( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLEHOTJUNK ));
+ MSN_SetByte( "EnableDeliveryPopup", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_NOTIFY_FIRSTMSG ));
+ MSN_SetByte( "EnableSessionPopup", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_NOTIFY_ENDSESSION ));
+ return TRUE;
+ }
+ break;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static HWND hwndAcc = 0, hwndConn = 0, hwndSrvList = 0;
+
+static void SetOptionsDlgToType(HWND hwnd, int iExpert)
+{
+ TCITEM tci;
+ RECT rcClient;
+ HWND hwndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB), hwndEnum;
+ int iPages = 0;
+
+ if(!hwndAcc)
+ hwndAcc = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_MSN), hwnd, DlgProcMsnOpts);
+
+ hwndEnum = GetWindow(hwndAcc, GW_CHILD);
+
+ while(hwndEnum) {
+ ShowWindow(hwndEnum, iExpert ? SW_SHOW : SW_HIDE);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ }
+ if(!iExpert) {
+ hwndEnum = GetDlgItem(hwndAcc, IDC_STMSNGROUP);
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ do {
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ } while(hwndEnum && hwndEnum != GetDlgItem(hwndAcc, IDC_NEWMSNACCOUNTLINK));
+ }
+ ShowWindow(hwndEnum, SW_SHOW);
+ GetClientRect(hwnd, &rcClient);
+ TabCtrl_DeleteAllItems(hwndTab);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)hwndAcc;
+ tci.pszText = TranslateT("Account");
+ TabCtrl_InsertItem(hwndTab, 0, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ iPages++;
+
+ if(!hwndConn)
+ hwndConn = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_MSN_CONN),hwnd,DlgProcMsnConnOpts);
+
+ if(!hwndSrvList)
+ hwndSrvList = CreateDialog(hInst,MAKEINTRESOURCE(IDD_LISTSMGR),hwnd,DlgProcMsnServLists);
+
+ if(pfnEnableThemeDialogTexture) {
+ if(hwndAcc)
+ pfnEnableThemeDialogTexture(hwndAcc, ETDT_ENABLETAB);
+ if(hwndConn)
+ pfnEnableThemeDialogTexture(hwndConn, ETDT_ENABLETAB);
+ if(hwndSrvList)
+ pfnEnableThemeDialogTexture(hwndSrvList, ETDT_ENABLETAB);
+ }
+
+ ShowWindow(hwndConn, SW_HIDE);
+ ShowWindow(hwndSrvList, SW_HIDE);
+ ShowWindow(hwndAcc, SW_SHOW);
+
+ if(iExpert) {
+ tci.lParam = (LPARAM)hwndConn;
+ tci.pszText = TranslateT("Connection");
+ TabCtrl_InsertItem(hwndTab, iPages++, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+
+ tci.lParam = (LPARAM)hwndSrvList;
+ tci.pszText = TranslateT("Server list");
+ TabCtrl_InsertItem(hwndTab, iPages++, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ }
+ TabCtrl_SetCurSel(hwndTab, 0);
+}
+
+// handle tabbed options dialog
+
+static BOOL CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ iInit = TRUE;
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ iInit = FALSE;
+ return FALSE;
+ }
+ case WM_DESTROY:
+ hwndAcc = hwndConn = hwndSrvList = 0;
+ break;
+ 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 = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ tci.mask = TCIF_PARAM;
+ for (i=0;i<count;i++) {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ } }
+ break;
+ case PSN_EXPERTCHANGED:
+ {
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ 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;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Initialize options pages
+
+int MsnOptInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ HMODULE hUxTheme = 0;
+
+ if(IsWinVerXPPlus()) {
+ hUxTheme = GetModuleHandle(_T("uxtheme.dll"));
+
+ if(hUxTheme)
+ pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+ }
+
+ odp.cbSize = sizeof(odp);
+ odp.position = -790000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSNMAIN);
+ odp.pszTitle = msnProtocolName;
+ odp.pszGroup = "Network";
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = OptionsDlgProc;
+ MSN_CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp );
+
+ if ( ServiceExists( MS_POPUP_ADDPOPUP )) {
+ memset( &odp, 0, sizeof( odp ));
+ odp.cbSize = sizeof( odp );
+ odp.position = 100000000;
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_HOTMAIL_OPT_POPUP );
+ odp.pszTitle = msnProtocolName;
+ odp.pszGroup = "Popups";
+ odp.groupPosition = 910000000;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = DlgProcHotmailPopUpOpts;
+ MSN_CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load resident option values into memory
+
+void __stdcall LoadOptions()
+{
+ memset( &MyOptions, 0, sizeof( MyOptions ));
+
+ //PopUp Options
+ MyOptions.BGColour =
+ DBGetContactSettingDword( NULL, ModuleName, "BackgroundColour", STYLE_DEFAULTBGCOLOUR );
+ MyOptions.TextColour =
+ DBGetContactSettingDword( NULL, ModuleName, "TextColour", GetSysColor( COLOR_WINDOWTEXT ));
+
+ MyOptions.AwayAsBrb = MSN_GetByte( "AwayAsBrb", FALSE );
+ MyOptions.DisableMenu = MSN_GetByte( "DisableSetNickname", FALSE );
+ MyOptions.EnableAvatars = MSN_GetByte( "EnableAvatars", FALSE );
+ MyOptions.KeepConnectionAlive = MSN_GetByte( "KeepAlive", FALSE );
+ MyOptions.ManageServer = MSN_GetByte( "ManageServer", FALSE );
+ MyOptions.PopupTimeoutHotmail = MSN_GetDword( NULL, "PopupTimeout", 3 );
+ MyOptions.PopupTimeoutOther = MSN_GetDword( NULL, "PopupTimeoutOther", MyOptions.PopupTimeoutHotmail );
+ MyOptions.ShowErrorsAsPopups = MSN_GetByte( "ShowErrorsAsPopups", FALSE );
+ MyOptions.SlowSend = MSN_GetByte( "SlowSend", FALSE );
+ MyOptions.UseMSNP11 = MSN_GetByte( "UseMSNP11", FALSE );
+ MyOptions.UseProxy = MSN_GetByte( "NLUseProxy", FALSE );
+ MyOptions.UseGateway = MSN_GetByte( "UseGateway", FALSE );
+ MyOptions.UseWinColors = MSN_GetByte( "UseWinColors", FALSE );
+
+ DWORD ptype = MSN_GetByte( "NLProxyType", 0 );
+ BOOL httpproxy = MyOptions.UseProxy && (ptype == PROXYTYPE_HTTP || ptype == PROXYTYPE_HTTPS);
+ if ( httpproxy && !MyOptions.UseGateway)
+ {
+ MyOptions.UseGateway = TRUE;
+ MSN_SetByte( "UseGateway", TRUE );
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Display Hotmail Inbox thread
+
+DWORD WINAPI MsnShowMailThread( LPVOID )
+{
+ DBVARIANT dbv;
+
+ DBGetContactSetting( NULL, msnProtocolName, "e-mail", &dbv );
+ char* email = ( char* )alloca( strlen( dbv.pszVal )*3 );
+ UrlEncode( dbv.pszVal, email, strlen( dbv.pszVal )*3 );
+ MSN_FreeVariant( &dbv );
+
+ DBGetContactSetting( NULL, msnProtocolName, "Password", &dbv );
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ char* passwd = ( char* )alloca( strlen( dbv.pszVal )*3 );
+ UrlEncode( dbv.pszVal, passwd, strlen( dbv.pszVal )*3 );
+ MSN_FreeVariant( &dbv );
+
+ // for hotmail access
+ int tm = time(NULL) - sl;
+
+ char hippy[ 2048 ];
+ long challen = mir_snprintf( hippy, sizeof( hippy ), "%s%lu%s", MSPAuth, tm, passwd );
+
+ //Digest it
+ unsigned char digest[16];
+ MD5_CTX context;
+ MD5Init( &context);
+ MD5Update( &context, ( BYTE* )hippy, challen );
+ MD5Final( digest, &context );
+
+ if ( rru && passport )
+ {
+ char rruenc[256];
+ UrlEncode(rru, rruenc, sizeof(rruenc));
+
+ mir_snprintf(hippy, sizeof(hippy),
+ "%s&auth=%s&creds=%08x%08x%08x%08x&sl=%d&username=%s&mode=ttl"
+ "&sid=%s&id=2&rru=%s&svc=mail&js=yes",
+ passport, MSPAuth, htonl(*(PDWORD)(digest+0)),htonl(*(PDWORD)(digest+4)),
+ htonl(*(PDWORD)(digest+8)),htonl(*(PDWORD)(digest+12)),
+ tm, email, sid, rruenc);
+ }
+ else
+ strcpy( hippy, "http://go.msn.com/0/1" );
+
+ MSN_DebugLog( "Starting URL: '%s'", hippy );
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )hippy );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popup plugin window proc
+
+LRESULT CALLBACK NullWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
+{
+ switch( message ) {
+ case WM_COMMAND: {
+ void* tData = PUGetPluginData( hWnd );
+ if ( tData != NULL ) {
+ DWORD tThreadID;
+ CreateThread( NULL, 0, MsnShowMailThread, hWnd, 0, &tThreadID );
+ PUDeletePopUp( hWnd );
+ }
+ break;
+ }
+
+ case WM_CONTEXTMENU:
+ PUDeletePopUp( hWnd );
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
diff --git a/miranda-wine/protocols/MSN/msn_p2p.cpp b/miranda-wine/protocols/MSN/msn_p2p.cpp
new file mode 100644
index 0000000..bde0c9b
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_p2p.cpp
@@ -0,0 +1,1433 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <direct.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+struct p2p_threadParams
+{
+ HANDLE s;
+ filetransfer* ft;
+};
+
+static char sttP2Pheader[] =
+ "Content-Type: application/x-msnmsgrp2p\r\n"
+ "P2P-Dest: %s\r\n\r\n";
+
+static char sttVoidNonce[] = "{00000000-0000-0000-0000-000000000000}";
+
+static void sttLogHeader( P2P_Header* hdrdata )
+{
+ MSN_DebugLog( "--- Printing message header" );
+ MSN_DebugLog( " SessionID = %lu", hdrdata->mSessionID );
+ MSN_DebugLog( " MessageID = %lu", hdrdata->mID );
+ MSN_DebugLog( " Offset of data = %I64u", hdrdata->mOffset );
+ MSN_DebugLog( " Total amount of data = %I64u", hdrdata->mTotalSize );
+ MSN_DebugLog( " Data in packet = %lu bytes", hdrdata->mPacketLen );
+ MSN_DebugLog( " Flags = %08X", hdrdata->mFlags );
+ MSN_DebugLog( " Acknowledged session ID: %lu", hdrdata->mAckSessionID );
+ MSN_DebugLog( " Acknowledged message ID: %lu", hdrdata->mAckUniqueID );
+ MSN_DebugLog( " Acknowledged data size: %I64u", hdrdata->mAckDataSize );
+ MSN_DebugLog( "------------------------" );
+}
+
+static bool sttIsCancelCommand( const BYTE* p )
+{
+ if ( !memcmp( p, "BYE MSNMSGR:", 12 ))
+ return true;
+
+ return ( memcmp( p, "MSNSLP/1.0 603 ", 15 ) == 0 );
+}
+
+static char* getNewUuid()
+{
+ BYTE* p;
+ UUID id;
+
+ UuidCreate( &id );
+ UuidToStringA( &id, &p );
+ int len = strlen(( const char* )p );
+ char* result = ( char* )malloc( len+3 );
+ result[0]='{';
+ memcpy( result+1, p, len );
+ result[ len+1 ] = '}';
+ result[ len+2 ] = 0;
+ strupr( result );
+ RpcStringFreeA( &p );
+ return result;
+}
+
+static int sttCreateListener(
+ ThreadData* info,
+ filetransfer* ft,
+ pThreadFunc thrdFunc,
+ char* szBody, size_t cbBody )
+{
+ char ipaddr[256];
+ if ( MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ))) {
+ MSN_DebugLog( "Cannot detect my host address" );
+ return 0;
+ }
+
+ NETLIBBIND nlb = {0};
+ nlb.cbSize = sizeof( nlb );
+ nlb.pfnNewConnectionV2 = MSN_ConnectionProc;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ if (( ft->mIncomingBoundPort = (HANDLE) MSN_CallService(MS_NETLIB_BINDPORT, (WPARAM) hNetlibUser, ( LPARAM )&nlb)) == NULL ) {
+ MSN_DebugLog( "Unable to bind the port for incoming transfers" );
+ return 0;
+ }
+
+ ft->mIncomingPort = nlb.wPort;
+
+ char* szUuid = getNewUuid();
+ {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_P2P_DIRECT;
+ newThread->mCaller = 3;
+ newThread->mP2pSession = ft;
+ newThread->mParentThread = info;
+ strncpy( newThread->mCookie, ( char* )szUuid, sizeof( newThread->mCookie ));
+ ft->hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ newThread->startThread( thrdFunc );
+ }
+
+ char hostname[256];
+
+ gethostname( hostname, sizeof( hostname ));
+ PHOSTENT he = gethostbyname( hostname );
+
+ hostname[0] = 0;
+ for( unsigned i=0; i<sizeof( hostname )/16 && he->h_addr_list[i] ; ++i ) {
+ if ( i != 0 ) strcat( hostname, " " );
+ strcat( hostname, inet_ntoa( *( PIN_ADDR )he->h_addr_list[i] ));
+ }
+
+ int cbBodyLen = mir_snprintf( szBody, cbBody,
+ "Bridge: TCPv1\r\n"
+ "Listening: true\r\n"
+ "Nonce: %s\r\n"
+ "IPv4External-Addrs: %s\r\n"
+ "IPv4External-Port: %u\r\n"
+ "IPv4Internal-Addrs: %s\r\n"
+ "IPv4Internal-Port: %u\r\n"
+ "SessionID: %lu\r\n"
+ "SChannelState: 0\r\n\r\n%c",
+ szUuid,
+ ipaddr, nlb.wExPort,
+ hostname, ft->mIncomingPort,
+ ft->p2p_sessionid, 0 );
+ free( szUuid );
+
+ return cbBodyLen;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// sttSavePicture2disk - final handler for avatars downloading
+
+static void sttSavePicture2disk( ThreadData* info, filetransfer* ft )
+{
+ if ( !ft->inmemTransfer )
+ return;
+
+ //---- Save temporary PNG image to disk --------------------
+ #if defined( _DEBUG )
+ char* Path = getenv( "TEMP" );
+ if ( Path == NULL )
+ Path = getenv( "TMP" );
+
+ char tPathName[ MAX_PATH ];
+ if ( Path == NULL ) {
+ MSN_DebugLog( "Temporary file is created in the current directory: %s",
+ getcwd( tPathName, sizeof( tPathName )));
+ }
+ else {
+ MSN_DebugLog( "Temporary path found: %s", Path );
+ strcpy( tPathName, Path );
+ }
+
+ strcat( tPathName, "\\avatar.png" );
+ MSN_DebugLog( "Opening temporary file '%s'", tPathName );
+ { FILE* out = fopen( tPathName, "wb" );
+ if ( out ) {
+ fwrite( ft->fileBuffer, ft->std.totalBytes, 1, out );
+ fclose( out );
+ } }
+ #endif
+
+ //---- Converting memory buffer to bitmap and saving it to disk
+ if ( !MSN_LoadPngModule() )
+ return;
+
+ BITMAPINFOHEADER* pDib;
+ PNG2DIB convert;
+ convert.pSource = (BYTE*)ft->fileBuffer;
+ convert.cbSourceSize = ft->std.totalBytes;
+ convert.pResult = &pDib;
+ if ( !CallService( MS_PNG2DIB, 0, (LPARAM)&convert ))
+ return;
+
+ HANDLE hContact;
+ if ( info->mJoinedContacts == NULL ) {
+ if ( info->mParentThread == NULL )
+ goto LBL_Exit;
+
+ if ( info->mParentThread->mJoinedContacts == NULL )
+ goto LBL_Exit;
+
+ hContact = info->mParentThread->mJoinedContacts[0];
+ }
+ else hContact = info->mJoinedContacts[0];
+
+ if ( hContact != NULL ) {
+ PROTO_AVATAR_INFORMATION AI;
+ AI.cbSize = sizeof( AI );
+ AI.format = PA_FORMAT_BMP;
+ AI.hContact = hContact;
+ MSN_GetAvatarFileName( hContact, AI.filename, sizeof( AI.filename ));
+ FILE* out = fopen( AI.filename, "wb" );
+ if ( out != NULL ) {
+ BITMAPFILEHEADER tHeader = { 0 };
+ tHeader.bfType = 0x4d42;
+ tHeader.bfOffBits = sizeof( tHeader ) + sizeof( BITMAPINFOHEADER );
+ tHeader.bfSize = tHeader.bfOffBits + pDib->biSizeImage;
+ fwrite( &tHeader, sizeof( tHeader ), 1, out );
+ fwrite( pDib, sizeof( BITMAPINFOHEADER ), 1, out );
+ fwrite( pDib+1, pDib->biSizeImage, 1, out );
+ fclose( out );
+
+ MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE( &AI ), NULL );
+ }
+ else MSN_SendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE( &AI ), NULL );
+ }
+
+LBL_Exit:
+ GlobalFree( pDib );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendAck - sends MSN P2P acknowledgement to the received message
+
+static char sttVoidSession[] = "ACHTUNG!!! an attempt made to send a message via the empty session";
+
+void __stdcall p2p_sendAck( filetransfer* ft, ThreadData* info, P2P_Header* hdrdata )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ char* buf = ( char* )alloca( 1000 + strlen( ft->p2p_dest ));
+ char* p = buf + sprintf( buf, sttP2Pheader, ft->p2p_dest );
+
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+ tHdr->mSessionID = hdrdata->mSessionID;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckDataSize = hdrdata->mTotalSize;
+ tHdr->mTotalSize = hdrdata->mTotalSize;
+ tHdr->mFlags = 2;
+ tHdr->mAckSessionID = hdrdata->mID;
+ tHdr->mAckUniqueID = hdrdata->mAckSessionID;
+ *( long* )p = 0; p += sizeof( long );
+
+ if ( info->mType == SERVER_P2P_DIRECT ) {
+ DWORD *p2pPacket = (DWORD*)tHdr-1;
+ *p2pPacket = sizeof( P2P_Header );
+ info->send(( char* )p2pPacket, sizeof( P2P_Header ) + sizeof( DWORD ));
+ }
+ else info->sendRawMessage( 'D', buf, int( p - buf ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendEndSession - sends MSN P2P file transfer end packet
+
+static void __stdcall p2p_sendEndSession( ThreadData* info, filetransfer* ft )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ char* buf = ( char* )alloca( 1000 + strlen( ft->p2p_dest ));
+ char* p = buf + sprintf( buf, sttP2Pheader, ft->p2p_dest );
+
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+ tHdr->mSessionID = ft->p2p_sessionid;
+
+ tHdr->mAckSessionID = ft->p2p_sendmsgid;
+
+ if ( ft->std.sending)
+ {
+ tHdr->mFlags = 0x40;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckSessionID = tHdr->mID - 2;
+ }
+ else
+ {
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckUniqueID = 0x8200000f;
+ tHdr->mFlags = 0x80;
+ tHdr->mAckDataSize = ft->std.currentFileSize;
+ }
+
+ if ( info->mType == SERVER_P2P_DIRECT ) {
+ DWORD *p2pPacket = (DWORD*)tHdr-1;
+ *p2pPacket = sizeof( P2P_Header );
+ info->send(( char* )p2pPacket, sizeof( P2P_Header ) + sizeof( DWORD ));
+ }
+ else info->sendRawMessage( 'D', buf, int( p - buf ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendSlp - send MSN P2P SLP packet
+
+void __stdcall p2p_sendSlp(
+ ThreadData* info,
+ filetransfer* ft,
+ MimeHeaders& pHeaders,
+ int iKind,
+ const char* szContent,
+ size_t szContLen )
+{
+ if ( ft == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ char szMyEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, szMyEmail, sizeof( szMyEmail ));
+
+ char* buf = ( char* )alloca( 1000 + szContLen + pHeaders.getLength());
+ char* p = buf;
+
+ if ( info == NULL || info->mType != SERVER_P2P_DIRECT )
+ p += sprintf( p, sttP2Pheader, ft->p2p_dest );
+ else
+ p += sizeof( DWORD );
+
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+
+ char* pktStart = p;
+
+ switch ( iKind ) {
+ case 200: p += sprintf( p, "MSNSLP/1.0 200 OK" ); break;
+ case 603: p += sprintf( p, "MSNSLP/1.0 603 DECLINE" ); break;
+ case -1: p += sprintf( p, "BYE MSNMSGR:%s MSNSLP/1.0", ft->p2p_dest ); break;
+ case -2: p += sprintf( p, "INVITE MSNMSGR:%s MSNSLP/1.0", ft->p2p_dest ); break;
+ default: return;
+ }
+
+ p += sprintf( p,
+ "\r\nTo: <msnmsgr:%s>\r\n"
+ "From: <msnmsgr:%s>\r\n"
+ "Via: MSNSLP/1.0/TLP ;branch=%s\r\n", ft->p2p_dest, szMyEmail, ft->p2p_branch );
+
+ p = pHeaders.writeToBuffer( p );
+
+ p += sprintf( p, "Content-Length: %d\r\n\r\n", szContLen );
+ memcpy( p, szContent, szContLen );
+ p += szContLen;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mAckSessionID = ft->p2p_acksessid;
+ tHdr->mTotalSize = tHdr->mPacketLen = int( p - pktStart );
+
+ if (iKind == 603)
+ ft->p2p_byemsgid = ft->p2p_msgid;
+
+ *( DWORD* )p = 0; p += sizeof( DWORD );
+
+ if ( info == NULL ) {
+ MsgQueue_Add( ft->std.hContact, 'D', buf, int( p - buf ), NULL );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ else if ( info->mType == SERVER_P2P_DIRECT ) {
+ DWORD *p2pPacket = (DWORD*)tHdr-1;
+ *p2pPacket = p - buf - 2 * sizeof( DWORD );
+ info->send(( char* )p2pPacket, *p2pPacket + sizeof( DWORD ));
+ }
+ else info->sendRawMessage( 'D', buf, int( p - buf ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendBye - closes P2P session
+
+void __stdcall p2p_sendBye( ThreadData* info, filetransfer* ft )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ MimeHeaders tHeaders(5);
+ tHeaders.addString( "CSeq", "0 " );
+ tHeaders.addString( "Call-ID", ft->p2p_callID );
+ tHeaders.addLong( "Max-Forwards", 0 );
+ tHeaders.addString( "Content-Type", "application/x-msnmsgr-sessionclosebody" );
+
+ char szContents[ 50 ];
+ p2p_sendSlp( info, ft, tHeaders, -1, szContents,
+ mir_snprintf( szContents, sizeof( szContents ), "SessionID: %lu\r\nSChannelState: 0\r\n\r\n%c",
+ ft->p2p_sessionid, 0 ));
+ ft->p2p_byemsgid = ft->p2p_msgid;
+}
+
+void __stdcall p2p_sendCancel( ThreadData* info, filetransfer* ft )
+{
+ p2p_sendBye(info, ft);
+ p2p_sendEndSession(info, ft);
+ ft->bCanceled = true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendStatus - send MSN P2P status and its description
+
+void __stdcall p2p_sendStatus( filetransfer* ft, ThreadData* info, long lStatus )
+{
+ if ( ft == NULL || info == NULL ) {
+ MSN_DebugLog( sttVoidSession );
+ return;
+ }
+
+ MimeHeaders tHeaders( 5 );
+ tHeaders.addString( "CSeq", "1 " );
+ tHeaders.addString( "Call-ID", ft->p2p_callID );
+ tHeaders.addLong( "Max-Forwards", 0 );
+ tHeaders.addString( "Content-Type", "application/x-msnmsgr-sessionreqbody" );
+
+ char szContents[ 50 ];
+ p2p_sendSlp( info, ft, tHeaders, lStatus, szContents,
+ mir_snprintf( szContents, sizeof( szContents ), "SessionID: %lu\r\nSChannelState: 0\r\n\r\n%c",
+ ft->p2p_sessionid, 0 ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_connectTo - connects to a remote P2P server
+
+static char p2p_greeting[8] = { 4, 0, 0, 0, 'f', 'o', 'o', 0 };
+
+static void sttSendPacket( ThreadData* T, P2P_Header& hdr )
+{
+ DWORD len = sizeof( P2P_Header );
+ T->send(( char* )&len, sizeof( DWORD ));
+ T->send(( char* )&hdr, sizeof( P2P_Header ));
+}
+
+bool p2p_connectTo( ThreadData* info )
+{
+ filetransfer* ft = info->mP2pSession;
+
+ NETLIBOPENCONNECTION tConn = { 0 };
+ tConn.cbSize = sizeof( tConn );
+ tConn.flags = NLOCF_V2;
+ tConn.szHost = info->mServer;
+ tConn.timeout = 5;
+ {
+ char* tPortDelim = strrchr( info->mServer, ':' );
+ if ( tPortDelim != NULL ) {
+ *tPortDelim = '\0';
+ tConn.wPort = ( WORD )atol( tPortDelim+1 );
+ } }
+
+ while( true ) {
+ char* pSpace = strchr( info->mServer, ' ' );
+ if ( pSpace != NULL )
+ *pSpace = 0;
+
+ MSN_DebugLog( "Connecting to %s:%d", info->mServer, tConn.wPort );
+
+ HANDLE h = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
+ if ( h != NULL ) {
+ info->s = h;
+ ft->mThreadId = info->mUniqueID;
+ break;
+ }
+ { TWinErrorCode err;
+ MSN_DebugLog( "Connection Failed (%d): %s", err.mErrorCode, err.getText() );
+ }
+
+ if ( pSpace == NULL ) {
+ if ( ft->std.sending )
+ MSN_PingParentThread( info->mParentThread, ft );
+ return false;
+ }
+
+ strdel( info->mServer, int( pSpace - info->mServer )+1 );
+ }
+
+ info->send( p2p_greeting, sizeof( p2p_greeting ));
+
+ P2P_Header reply;
+ memset( &reply, 0, sizeof( P2P_Header ));
+ reply.mID = ++ft->p2p_msgid;
+ reply.mFlags = 0x100;
+
+ strdel( info->mCookie, 1 );
+ info->mCookie[ strlen( info->mCookie )-1 ] = 0;
+ UuidFromStringA(( BYTE* )info->mCookie, ( UUID* )&reply.mAckSessionID );
+ sttSendPacket( info, reply );
+
+ long cbPacketLen;
+ HReadBuffer buf( info, 0 );
+ BYTE* p;
+ if (( p = buf.surelyRead( 4 )) == NULL ) {
+ MSN_DebugLog( "Error reading data, closing filetransfer" );
+ return false;
+ }
+
+ cbPacketLen = *( long* )p;
+ if (( p = buf.surelyRead( cbPacketLen )) == NULL )
+ return false;
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_listen - acts like a local P2P server
+
+bool p2p_listen( ThreadData* info )
+{
+ filetransfer* ft = info->mP2pSession;
+ DWORD ftID = ft->p2p_sessionid;
+
+ switch( WaitForSingleObject( ft->hWaitEvent, 5000 )) {
+ case WAIT_TIMEOUT:
+ case WAIT_FAILED:
+ MSN_DebugLog( "Incoming connection timed out, closing file transfer" );
+ if (( ft = p2p_getSessionByID( ftID )) != NULL )
+ if ( ft->std.sending )
+ MSN_PingParentThread( info->mParentThread, ft );
+LBL_Error:
+ MSN_DebugLog( "File transfer failed" );
+ return false;
+ }
+
+ HReadBuffer buf( info, 0 );
+ BYTE* p;
+
+ ft->mThreadId = info->mUniqueID;
+
+ if (( p = buf.surelyRead( 8 )) == NULL )
+ goto LBL_Error;
+
+ if ( memcmp( p, p2p_greeting, 8 ) != NULL ) {
+ MSN_DebugLog( "Invalid input data, exiting" );
+ goto LBL_Error;
+ }
+
+ if (( p = buf.surelyRead( 4 )) == NULL ) {
+ MSN_DebugLog( "Error reading data, closing filetransfer" );
+ goto LBL_Error;
+ }
+
+ long cbPacketLen = *( long* )p;
+ if (( p = buf.surelyRead( cbPacketLen )) == NULL )
+ goto LBL_Error;
+
+ UUID uuidCookie;
+ strdel( info->mCookie, 1 );
+ info->mCookie[ strlen(info->mCookie)-1 ] = 0;
+ UuidFromStringA(( BYTE* )info->mCookie, &uuidCookie );
+
+ P2P_Header* pCookie = ( P2P_Header* )p;
+ if ( memcmp( &pCookie->mAckSessionID, &uuidCookie, sizeof( UUID ))) {
+ MSN_DebugLog( "Invalid input cookie, exiting" );
+ goto LBL_Error;
+ }
+
+ pCookie->mID = ++ft->p2p_msgid;
+ sttSendPacket( info, *pCookie );
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendFeedThread - sends a file via server
+
+void __cdecl p2p_sendFeedThread( ThreadData* info )
+{
+ HANDLE s = info->s; info->s = NULL;
+ filetransfer* ft = info->mP2pSession;
+
+ if ( ft->p2p_sendmsgid == 0 )
+ ft->p2p_sendmsgid = ++ft->p2p_msgid;
+
+ while ( ft->std.currentFileProgress < ft->std.currentFileSize )
+ {
+ if ( ft->bCanceled ) {
+ MSN_DebugLog( "File transfer canceled" );
+ break;
+ }
+
+ ThreadData* T = MSN_GetThreadByConnection( s );
+ if ( T == NULL || p2p_sendPortion( ft, T ) == 0 ) {
+ MSN_DebugLog( "File transfer failed" );
+ break;
+} } }
+
+void __stdcall p2p_sendFeedStart( filetransfer* ft, ThreadData* T )
+{
+ if ( ft->std.sending )
+ {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_FILETRANS;
+ newThread->mP2pSession = ft;
+ newThread->s = T->s;
+ newThread->startThread(( pThreadFunc )p2p_sendFeedThread );
+} }
+
+LONG __stdcall p2p_sendPortion( filetransfer* ft, ThreadData* T )
+{
+ LONG trid;
+ char databuf[ 1500 ], *p = databuf;
+
+ // Compute the amount of data to send
+ const long fportion = T->mType == SERVER_P2P_DIRECT ? 1352 : 1202;
+ const unsigned long portion =
+ ( fportion + ft->std.currentFileProgress > ft->std.currentFileSize ) ?
+ ft->std.currentFileSize - ft->std.currentFileProgress : fportion;
+
+ // Fill data size for direct transfer
+
+ if ( T->mType != SERVER_P2P_DIRECT )
+ p += sprintf( p, sttP2Pheader, ft->p2p_dest );
+ else
+ {
+ *( unsigned long* )p = portion + sizeof( P2P_Header );
+ p += sizeof( unsigned long );
+ }
+
+ // Fill P2P header
+ P2P_Header* H = ( P2P_Header* ) p;
+ p += sizeof( P2P_Header );
+
+ memset( H, 0, sizeof( P2P_Header ));
+ H->mSessionID = ft->p2p_sessionid;
+ H->mID = ft->p2p_sendmsgid;
+ H->mFlags = ft->p2p_appID == 2 ? 0x01000030 : 0x20;
+ H->mTotalSize = ft->std.currentFileSize;
+ H->mOffset = ft->std.currentFileProgress;
+ H->mPacketLen = portion;
+ H->mAckSessionID = ft->p2p_acksessid;
+
+ // Fill data (payload) for transfer
+ ::read( ft->fileId, p, portion );
+ p += portion;
+
+ if ( T->mType == SERVER_P2P_DIRECT )
+ trid = T->send( databuf, p - databuf);
+ else
+ {
+ // Define packet footer for server transfer
+ *( unsigned long * )p = htonl(ft->p2p_appID);
+ p += sizeof( unsigned long );
+
+ trid = T->sendRawMessage( 'D', ( char * )databuf, p - databuf);
+ }
+
+ ft->std.totalProgress += portion;
+ ft->std.currentFileProgress += portion;
+ if ( ft->p2p_appID == 2 )
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+
+ return trid;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_sendFileDirectly - sends a file via MSN P2P protocol
+
+void p2p_sendRecvFileDirectly( ThreadData* info )
+{
+ BYTE* p;
+
+ p2p_sendFeedStart( info->mP2pSession, info );
+
+ HReadBuffer buf( info, 0 );
+ for ( ;; ) {
+ if (( p = buf.surelyRead( 4 )) == NULL ) {
+ info->mP2pSession->bCanceled = true;
+ MSN_DebugLog( "File transfer failed" );
+ break;
+ }
+
+ long cbPacketLen = *( long* )p;
+ if (( p = buf.surelyRead( cbPacketLen )) == NULL ) {
+ info->mP2pSession->bCanceled = true;
+ MSN_DebugLog( "File transfer failed" );
+ break;
+ }
+
+ p2p_processMsg( info, (char*)p );
+
+ if ( !p2p_sessionRegistered( info->mP2pSession ))
+ break;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// bunch of thread functions to cover all variants of P2P file transfers
+
+void __cdecl p2p_fileActiveThread( ThreadData* info )
+{
+ MSN_DebugLog( "p2p_fileActiveThread() started: connecting to '%s'", info->mServer );
+
+ if ( p2p_connectTo( info ))
+ p2p_sendRecvFileDirectly( info );
+}
+
+void __cdecl p2p_filePassiveThread( ThreadData* info )
+{
+ MSN_DebugLog( "p2p_filePassiveThread() started: listening" );
+
+ if ( p2p_listen( info ))
+ p2p_sendRecvFileDirectly( info );
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_processMsg - processes all MSN P2P incoming messages
+
+static void sttInitFileTransfer(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2,
+ const char* msgbody )
+{
+ char szMyEmail[ MSN_MAX_EMAIL_LEN ], szContactEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", info->mJoinedContacts[0], szContactEmail, sizeof( szContactEmail )))
+ return;
+
+ MSN_GetStaticString( "e-mail", NULL, szMyEmail, sizeof( szMyEmail ));
+
+ const char *szCallID = tFileInfo[ "Call-ID" ],
+ *szBranch = tFileInfo[ "Via" ];
+
+ if ( szBranch != NULL ) {
+ szBranch = strstr( szBranch, "branch=" );
+ if ( szBranch != NULL )
+ szBranch += 7;
+ }
+ if ( szCallID == NULL || szBranch == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: CallID='%s', szBranch='%s'", szCallID, szBranch );
+ return;
+ }
+
+ char* szContext = NULL;
+ long dwAppID = -1;
+
+ const char *szSessionID = tFileInfo2[ "SessionID" ],
+ *szEufGuid = tFileInfo2[ "EUF-GUID" ];
+ { const char* p = tFileInfo2[ "AppID" ];
+ if ( p )
+ dwAppID = atol( p );
+ if ( dwAppID == 12 )
+ dwAppID = 1;
+ }
+ { const char* p = tFileInfo2[ "Context" ];
+ if ( p ) {
+ int cbLen = strlen( p );
+ szContext = ( char* )alloca( cbLen+1 );
+
+ NETLIBBASE64 nlb = { ( char* )p, cbLen, ( PBYTE )szContext, cbLen };
+ MSN_CallService( MS_NETLIB_BASE64DECODE, 0, LPARAM( &nlb ));
+ } }
+
+ if ( szContext == NULL && memcmp( msgbody, "Context: ", 9 ) == 0 ) {
+ msgbody += 9;
+ int cbLen = strlen( msgbody );
+ if ( cbLen > 252 )
+ cbLen = 252;
+ szContext = ( char* )alloca( cbLen+1 );
+
+ NETLIBBASE64 nlb = { ( char* )msgbody, cbLen, ( PBYTE )szContext, cbLen };
+ MSN_CallService( MS_NETLIB_BASE64DECODE, 0, LPARAM( &nlb ));
+ }
+
+ if ( szSessionID == NULL || dwAppID == -1 || szEufGuid == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: SessionID='%s', AppID=%ld, Branch='%s'", szSessionID, dwAppID, szEufGuid );
+ return;
+ }
+
+ srand( time( NULL ));
+
+ filetransfer* ft = new filetransfer();
+ ft->p2p_appID = dwAppID;
+ ft->p2p_acksessid = 0x024F0000 + rand();
+ ft->p2p_sessionid = strtoul( szSessionID, NULL, 10 );
+ ft->p2p_msgid = ft->p2p_acksessid + 5;
+ ft->p2p_ackID = ft->p2p_appID * 1000;
+ replaceStr( ft->p2p_callID, szCallID );
+ replaceStr( ft->p2p_branch, szBranch );
+ ft->p2p_dest = strdup( szContactEmail );
+ ft->mThreadId = info->mUniqueID;
+ ft->mOwnsThread = info->mMessageCount == 0;
+
+ p2p_sendAck( ft, info, hdrdata );
+
+ if ( dwAppID == 1 && !strcmp( szEufGuid, "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}" )) {
+ char szFileName[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, szFileName, sizeof( szFileName ));
+ ft->fileId = _open( szFileName, O_RDONLY | _O_BINARY, _S_IREAD );
+ if ( ft->fileId == -1 ) {
+ p2p_sendStatus( ft, info, 603 );
+ MSN_DebugLog( "Unable to open avatar file '%s', error %d", szFileName, errno );
+ delete ft;
+ return;
+ }
+ MSN_DebugLog( "My avatar file opened for %s as %08p::%d", szContactEmail, ft, ft->fileId );
+ ft->std.totalBytes = ft->std.currentFileSize = filelength( ft->fileId );
+ ft->std.sending = true;
+
+ ft->p2p_msgid -= 3;
+
+ //---- send 200 OK Message
+ p2p_sendStatus( ft, info, 200 );
+ p2p_registerSession( ft );
+ return;
+ }
+
+ if ( dwAppID == 2 && !strcmp( szEufGuid, "{5D3E02AB-6190-11D3-BBBB-00C04F795683}" )) {
+ WCHAR* wszFileName = ( WCHAR* )&szContext[ 20 ];
+ { for ( WCHAR* p = wszFileName; *p != 0; p++ )
+ { switch( *p ) {
+ case ':': case '?': case '/': case '\\': case '*':
+ *p = '_';
+ } } }
+
+ #if defined( _UNICODE )
+ ft->wszFileName = _wcsdup( wszFileName );
+ #endif
+
+ char szFileName[ MAX_PATH ];
+ char cDefaultChar = '_';
+ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,
+ wszFileName, -1, szFileName, MAX_PATH, &cDefaultChar, 0 );
+ MSN_DebugLog( "File name: '%s'", szFileName );
+
+ ft->std.hContact = info->mJoinedContacts[0];
+ replaceStr( ft->std.currentFile, szFileName );
+ ft->std.totalBytes = ft->std.currentFileSize = *( long* )&szContext[ 8 ];
+ ft->std.totalFiles = 1;
+
+ p2p_registerSession( ft );
+
+ if ( !ft->mIsFirst ) {
+ filetransfer* parentFt = p2p_getFirstSession( ft->std.hContact );
+ if ( parentFt != NULL )
+ ft->p2p_acksessid = parentFt->p2p_acksessid;
+ }
+
+ ft->p2p_msgid -= 3;
+
+ int tFileNameLen = strlen( ft->std.currentFile );
+ char tComment[ 40 ];
+ int tCommentLen = mir_snprintf( tComment, sizeof( tComment ), "%ld bytes", ft->std.currentFileSize );
+ char* szBlob = ( char* )alloca( sizeof( DWORD ) + tFileNameLen + tCommentLen + 2 );
+ *( PDWORD )szBlob = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), ft->std.currentFile );
+ strcpy( szBlob + sizeof( DWORD ) + tFileNameLen + 1, tComment );
+
+ PROTORECVEVENT pre;
+ pre.flags = 0;
+ pre.timestamp = ( DWORD )time( NULL );
+ pre.szMessage = ( char* )szBlob;
+ pre.lParam = ( LPARAM )( char* )"";
+
+ CCSDATA ccs;
+ ccs.hContact = info->mJoinedContacts[0];
+ ccs.szProtoService = PSR_FILE;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )&pre;
+ MSN_CallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ return;
+ }
+
+ if ( dwAppID == 4 ) {
+ if ( !strcmp( szEufGuid, "{4BD96FC0-AB17-4425-A14A-439185962DC8}" )) {
+ MSN_ShowPopup( MSN_GetContactName( info->mJoinedContacts[0] ),
+ MSN_Translate( "Contact tried to send its webcam data (currently not supported)" ), MSN_ALLOW_MSGBOX );
+ return;
+ }
+ if ( !strcmp( szEufGuid, "{1C9AA97E-9C05-4583-A3BD-908A196F1E92}" )) {
+ MSN_ShowPopup( MSN_GetContactName( info->mJoinedContacts[0] ),
+ MSN_Translate( "Contact tried to view our webcam data (currently not supported)" ), MSN_ALLOW_MSGBOX );
+ return;
+ } }
+
+ delete ft;
+ MSN_DebugLog( "Invalid or unknown AppID/EUF-GUID combination: %ld/%s", dwAppID, szEufGuid );
+}
+
+static void sttInitDirectTransfer(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2 )
+{
+ const char *szCallID = tFileInfo[ "Call-ID" ],
+ *szBranch = tFileInfo[ "Via" ];
+
+ if ( szBranch != NULL ) {
+ szBranch = strstr( szBranch, "branch=" );
+ if ( szBranch != NULL )
+ szBranch += 7;
+ }
+ if ( szCallID == NULL || szBranch == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: CallID='%s', Branch='%s', SessionID=%s", szCallID, szBranch );
+ return;
+ }
+
+ filetransfer* ft = p2p_getSessionByCallID( szCallID );
+ if ( ft == NULL )
+ return;
+
+ ++ft->p2p_msgid;
+ p2p_sendAck( ft, info, hdrdata );
+
+ replaceStr( ft->p2p_callID, szCallID );
+ replaceStr( ft->p2p_branch, szBranch );
+ ft->p2p_acksessid = 0x024B0000 + rand();
+
+ const char *szConnType = tFileInfo2[ "Conn-Type" ],
+ *szUPnPNat = tFileInfo2[ "UPnPNat" ],
+ *szNetID = tFileInfo2[ "NetID" ],
+ *szICF = tFileInfo2[ "ICF" ];
+
+ if ( szConnType == NULL || szUPnPNat == NULL || szICF == NULL || szNetID == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: ConnType='%s', UPnPNat='%s', ICF='%s', NetID='%s'",
+ szConnType, szUPnPNat, szICF, szNetID );
+ return;
+ }
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+
+ bool bUseDirect = false, bActAsServer = false;
+ if ( atol( szNetID ) == 0 ) {
+ if ( !strcmp( szConnType, "Direct-Connect" ) || !strcmp( szConnType, "Firewall" ))
+ bUseDirect = true;
+ }
+
+ if ( MSN_GetByte( "NLSpecifyIncomingPorts", 0 )) {
+ MSN_DebugLog( "My machine can accept incoming connections" );
+ bUseDirect = bActAsServer = true;
+ }
+
+ MimeHeaders tResult(20);
+ tResult.addString( "CSeq", "1 " );
+ tResult.addString( "Call-ID", ft->p2p_callID );
+ tResult.addLong( "Max-Forwards", 0 );
+ if ( bUseDirect )
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transrespbody" );
+ else
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transreqbody" );
+
+ char szBody[ 512 ];
+ int cbBodyLen = 0;
+ if ( bActAsServer )
+ cbBodyLen = sttCreateListener( info, ft, ( pThreadFunc )p2p_filePassiveThread, szBody, sizeof( szBody ));
+
+ if ( !cbBodyLen )
+ cbBodyLen = mir_snprintf( szBody, sizeof( szBody ),
+ "Bridge: TCPv1\r\n"
+ "Listening: false\r\n"
+ "Nonce: %s\r\n\r\n%c", sttVoidNonce, 0 );
+
+ ft->p2p_msgid -= 2;
+ p2p_sendSlp( info, ft, tResult, 200, szBody, cbBodyLen );
+ ++ft->p2p_msgid;
+}
+
+static void sttInitDirectTransfer2(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2 )
+{
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft == NULL )
+ return;
+
+ const char *szInternalAddress = tFileInfo2[ "IPv4Internal-Addrs" ],
+ *szInternalPort = tFileInfo2[ "IPv4Internal-Port" ],
+ *szExternalAddress = tFileInfo2[ "IPv4External-Addrs" ],
+ *szExternalPort = tFileInfo2[ "IPv4External-Port" ],
+ *szNonce = tFileInfo2[ "Nonce" ],
+ *szListening = tFileInfo2[ "Listening" ];
+
+ if ( szNonce == NULL || szListening == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: Listening='%s', Nonce=%s", szNonce, szListening );
+ return;
+ }
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+ p2p_sendAck( ft, info, hdrdata );
+
+ if ( !strcmp( szListening, "true" ) && strcmp( szNonce, sttVoidNonce )) {
+ ThreadData* newThread = new ThreadData;
+ newThread->mType = SERVER_P2P_DIRECT;
+ newThread->mP2pSession = ft;
+ newThread->mParentThread = info;
+ strncpy( newThread->mCookie, szNonce, sizeof( newThread->mCookie ));
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%s", szInternalAddress, szInternalPort );
+ newThread->startThread(( pThreadFunc )p2p_fileActiveThread );
+ }
+ else p2p_sendStatus( ft, info, 603 );
+}
+
+static void sttAcceptTransfer(
+ P2P_Header* hdrdata,
+ ThreadData* info,
+ MimeHeaders& tFileInfo,
+ MimeHeaders& tFileInfo2 )
+{
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft == NULL )
+ return;
+
+ ft->mThreadId = info->mUniqueID;
+
+ ++ft->p2p_msgid;
+ p2p_sendAck( ft, info, hdrdata );
+
+ const char *szCallID = tFileInfo[ "Call-ID" ], *szBranch = tFileInfo[ "Via" ];
+ if ( szBranch != NULL ) {
+ szBranch = strstr( szBranch, "branch=" );
+ if ( szBranch != NULL )
+ szBranch += 7;
+ }
+
+ if ( szCallID == NULL || szBranch == NULL ) {
+ MSN_DebugLog( "Ignoring invalid invitation: CallID='%s', szBranch='%s'", szCallID, szBranch );
+LBL_Close:
+ p2p_sendBye( info, ft );
+ return;
+ }
+
+ if ( !ft->std.sending ) {
+ replaceStr( ft->p2p_branch, szBranch );
+ replaceStr( ft->p2p_callID, szCallID );
+ return;
+ }
+
+ const char* szOldContentType = tFileInfo[ "Content-Type" ];
+ if ( szOldContentType == NULL )
+ goto LBL_Close;
+
+ bool bAllowIncoming = ( MSN_GetByte( "NLSpecifyIncomingPorts", 0 ) != 0 );
+
+ MimeHeaders tResult(20);
+ tResult.addString( "CSeq", "0 " );
+ tResult.addString( "Call-ID", ft->p2p_callID );
+ tResult.addLong( "Max-Forwards", 0 );
+
+ char* szBody = ( char* )alloca( 1024 );
+ int cbBody = 0;
+ if ( !strcmp( szOldContentType, "application/x-msnmsgr-sessionreqbody" )) {
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transreqbody" );
+ cbBody = mir_snprintf( szBody, 1024,
+ "Bridges: TCPv1\r\nNetID: 0\r\nConn-Type: %s\r\nUPnPNat: false\r\nICF: false\r\n\r\n%c",
+// "Nonce: %s\r\nSessionID: %lu\r\nSChannelState: 0\r\n\r\n%c",
+ ( bAllowIncoming ) ? "Direct-Connect" : "Unknown-Connect", 0 );
+ }
+ else if ( !strcmp( szOldContentType, "application/x-msnmsgr-transrespbody" )) {
+ const char *szListening = tFileInfo2[ "Listening" ],
+ *szNonce = tFileInfo2[ "Nonce" ],
+ *szExternalAddress = tFileInfo2[ "IPv4External-Addrs" ],
+ *szExternalPort = tFileInfo2[ "IPv4External-Port" ],
+ *szInternalAddress = tFileInfo2[ "IPv4Internal-Addrs" ],
+ *szInternalPort = tFileInfo2[ "IPv4Internal-Port" ];
+ if ( szListening == NULL || szNonce == NULL ) {
+ MSN_DebugLog( "Invalid data packet, exiting..." );
+ goto LBL_Close;
+ }
+
+ // another side reported that it will be a server.
+ if ( !strcmp( szListening, "true" ) && strcmp( szNonce, sttVoidNonce )) {
+ bool extOk = szExternalAddress != NULL && szExternalPort != NULL;
+ bool intOk = szInternalAddress != NULL && szInternalPort != NULL;
+
+ ThreadData* newThread = new ThreadData;
+
+ char ipaddr[256] = "";
+ MSN_GetMyHostAsString( ipaddr, sizeof( ipaddr ));
+
+ if ( extOk && ( strcmp( szExternalAddress, ipaddr ) || !intOk ))
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%s", szExternalAddress, szExternalPort );
+ else if ( intOk )
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%s", szInternalAddress, szInternalPort );
+ else {
+ MSN_DebugLog( "Invalid data packet, exiting..." );
+ delete newThread;
+ goto LBL_Close;
+ }
+
+ newThread->mType = SERVER_P2P_DIRECT;
+ newThread->mP2pSession = ft;
+ newThread->mParentThread = info;
+ strncpy( newThread->mCookie, szNonce, sizeof( newThread->mCookie ));
+ newThread->startThread(( pThreadFunc )p2p_fileActiveThread );
+ return;
+ }
+
+ // can we be a server?
+ if ( bAllowIncoming )
+ cbBody = sttCreateListener( info, ft, ( pThreadFunc )p2p_filePassiveThread, szBody, 1024 );
+
+ // no, send a file via server
+ if ( cbBody == 0 ) {
+ p2p_sendFeedStart( ft, info );
+ return;
+ }
+
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transrespbody" );
+ }
+ else if ( !strcmp( szOldContentType, "application/x-msnmsgr-transreqbody" )) {
+ // can we be a server?
+ if ( bAllowIncoming )
+ cbBody = sttCreateListener( info, ft, ( pThreadFunc )p2p_filePassiveThread, szBody, 1024 );
+
+ // no, send a file via server
+ if ( cbBody == 0 ) {
+ p2p_sendFeedStart( ft, info );
+ return;
+ }
+
+ tResult.addString( "Content-Type", "application/x-msnmsgr-transrespbody" );
+ }
+ else goto LBL_Close;
+
+ ft->p2p_msgid -= 2;
+ p2p_sendSlp( info, ft, tResult, -2, szBody, cbBody );
+ ++ft->p2p_msgid;
+}
+
+static void sttCloseTransfer( P2P_Header* hdrdata, ThreadData* info, MimeHeaders& tFileInfo )
+{
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft == NULL )
+ return;
+
+ p2p_sendAck( ft, info, hdrdata );
+ p2p_unregisterSession( ft );
+}
+
+void __stdcall p2p_processMsg( ThreadData* info, const char* msgbody )
+{
+ P2P_Header* hdrdata = ( P2P_Header* )msgbody; msgbody += sizeof( P2P_Header );
+ sttLogHeader( hdrdata );
+
+ //---- if we got a message
+ if ( hdrdata->mFlags == 0 )
+ {
+ int iMsgType = 0;
+ if ( !memcmp( msgbody, "INVITE MSNMSGR:", 15 ))
+ iMsgType = 1;
+ else if ( !memcmp( msgbody, "MSNSLP/1.0 200 ", 15 ))
+ iMsgType = 2;
+ else if ( !memcmp( msgbody, "BYE MSNMSGR:", 12 ))
+ iMsgType = 3;
+ else if ( !memcmp( msgbody, "MSNSLP/1.0 603 ", 15 ))
+ iMsgType = 4;
+
+ if ( iMsgType ) {
+ const char* peol = strstr( msgbody, "\r\n" );
+ if ( peol != NULL )
+ msgbody = peol+2;
+
+ MimeHeaders tFileInfo, tFileInfo2;
+ msgbody = tFileInfo.readFromBuffer( msgbody );
+ msgbody = tFileInfo2.readFromBuffer( msgbody );
+
+ const char* szContentType = tFileInfo[ "Content-Type" ];
+ if ( szContentType == NULL ) {
+ MSN_DebugLog( "Invalid or missing Content-Type field, exiting" );
+ return;
+ }
+
+ switch( iMsgType ) {
+ case 1:
+ if ( info->mType == SERVER_SWITCHBOARD) {
+ if ( !strcmp( szContentType, "application/x-msnmsgr-sessionreqbody" ))
+ sttInitFileTransfer( hdrdata, info, tFileInfo, tFileInfo2, msgbody );
+ else if ( iMsgType == 1 && !strcmp( szContentType, "application/x-msnmsgr-transreqbody" ))
+ sttInitDirectTransfer( hdrdata, info, tFileInfo, tFileInfo2 );
+ else if ( iMsgType == 1 && !strcmp( szContentType, "application/x-msnmsgr-transrespbody" ))
+ sttInitDirectTransfer2( hdrdata, info, tFileInfo, tFileInfo2 );
+ }
+ break;
+
+ case 2:
+ if ( info->mType == SERVER_SWITCHBOARD)
+ sttAcceptTransfer( hdrdata, info, tFileInfo, tFileInfo2 );
+ break;
+
+ case 3:
+ if ( !strcmp( szContentType, "application/x-msnmsgr-sessionclosebody" ))
+ {
+ filetransfer* ft = p2p_getSessionByCallID( tFileInfo[ "Call-ID" ] );
+ if ( ft != NULL )
+ {
+ p2p_sendAck( ft, info, hdrdata );
+ if ( ft->std.currentFileProgress < ft->std.currentFileSize )
+ {
+ p2p_sendEndSession(info, ft);
+ ft->bCanceled = true;
+ }
+ else if ( !ft->std.sending )
+ ft->complete();
+
+ p2p_unregisterSession( ft );
+ } }
+ break;
+
+ case 4:
+ sttCloseTransfer( hdrdata, info, tFileInfo );
+ break;
+ }
+ return;
+ } }
+
+ //---- receiving ack -----------
+ if ( hdrdata->mFlags == 0x02 ) {
+ filetransfer* ft = p2p_getSessionByID( hdrdata->mSessionID );
+ if ( ft == NULL )
+ if ((ft = p2p_getSessionByMsgID( hdrdata->mAckSessionID )) == NULL )
+ return;
+
+ if ( hdrdata->mAckSessionID == ft->p2p_sendmsgid )
+ {
+ if ( ft->p2p_appID == 2 )
+ {
+ ft->complete();
+ p2p_sendBye( info, ft );
+ }
+ return;
+ }
+
+ if ( hdrdata->mAckSessionID == ft->p2p_byemsgid )
+ {
+ if ( ft->p2p_appID == 1 ) {
+ sttSavePicture2disk( info, ft );
+
+ char tContext[ 256 ];
+ if ( !MSN_GetStaticString( "PictContext", ft->std.hContact, tContext, sizeof( tContext )))
+ MSN_SetString( ft->std.hContact, "PictSavedContext", tContext );
+ }
+
+ p2p_unregisterSession( ft );
+ if ( ft->mOwnsThread )
+ info->sendPacket( "OUT", NULL );
+ return;
+ }
+
+ switch( ft->p2p_ackID ) {
+ case 1000:
+ {
+ //---- send Data Preparation Message
+ char* buf = ( char* )alloca( 2000 + 3*strlen( ft->p2p_dest ));
+ char* p = buf + sprintf( buf, sttP2Pheader, ft->p2p_dest );
+ P2P_Header* tHdr = ( P2P_Header* )p; p += sizeof( P2P_Header );
+ memset( tHdr, 0, sizeof( P2P_Header ));
+ tHdr->mSessionID = ft->p2p_sessionid;
+ tHdr->mID = ++ft->p2p_msgid;
+ tHdr->mTotalSize = tHdr->mPacketLen = 4;
+ tHdr->mAckSessionID = ft->p2p_acksessid;
+ *( long* )p = 0; p += sizeof( long );
+ *( long* )p = htonl(ft->p2p_appID); p += sizeof( long );
+ info->sendRawMessage( 'D', buf, int( p - buf ));
+ }
+ break;
+
+ case 1001:
+ //---- send Data Messages
+ p2p_sendFeedStart( ft, info );
+ break;
+ }
+
+ ft->p2p_ackID++;
+ return;
+ }
+
+ filetransfer* ft = p2p_getSessionByID( hdrdata->mSessionID );
+ if ( ft == NULL )
+ return;
+
+ if ( hdrdata->mFlags == 0 ) {
+ //---- accept the data preparation message ------
+ long* pLongs = ( long* )msgbody;
+ if ( pLongs[0] == 0 && pLongs[1] == 0x01000000 && hdrdata->mPacketLen == 4 ) {
+ p2p_sendAck( ft, info, hdrdata );
+ return;
+ } }
+
+ //---- receiving data -----------
+ if ( hdrdata->mFlags == 0x01000030 || hdrdata->mFlags == 0x20 ) {
+
+ if ( hdrdata->mOffset + hdrdata->mPacketLen > hdrdata->mTotalSize )
+ hdrdata->mPacketLen = DWORD( hdrdata->mTotalSize - hdrdata->mOffset );
+
+ ft->p2p_sendmsgid = hdrdata->mID;
+ ft->std.totalBytes = ft->std.currentFileSize = ( long )hdrdata->mTotalSize;
+
+ if ( ft->inmemTransfer )
+ memcpy( ft->fileBuffer + hdrdata->mOffset, msgbody, hdrdata->mPacketLen );
+ else {
+ ::lseek( ft->fileId, long( hdrdata->mOffset ), SEEK_SET );
+ ::_write( ft->fileId, msgbody, hdrdata->mPacketLen );
+ }
+
+ ft->std.totalProgress += hdrdata->mPacketLen;
+ ft->std.currentFileProgress += hdrdata->mPacketLen;
+
+ if ( ft->p2p_appID == 2 )
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+
+ //---- send an ack: body was transferred correctly
+ MSN_DebugLog( "Transferred %lu bytes out of %lu", ft->std.currentFileProgress, hdrdata->mTotalSize );
+
+ if ( ft->std.currentFileProgress == hdrdata->mTotalSize ) {
+ p2p_sendAck( ft, info, hdrdata );
+ if ( ft->p2p_appID == 2 )
+ ft->complete();
+ else
+ p2p_sendBye( info, ft );
+ } }
+
+ if ( hdrdata->mFlags == 0x40 || hdrdata->mFlags == 0x80 ) {
+ if ( ft->mOwnsThread )
+ info->sendPacket( "OUT", NULL );
+ p2p_unregisterSession( ft );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// p2p_invite - invite another side to transfer an avatar
+
+struct HFileContext
+{
+ DWORD len, dw1, dwSize, dw2, dw3;
+ WCHAR wszFileName[ MAX_PATH ];
+};
+
+void __stdcall p2p_invite( HANDLE hContact, int iAppID, filetransfer* ft )
+{
+ const char* szAppID;
+ switch( iAppID ) {
+ case MSN_APPID_FILE: szAppID = "{5D3E02AB-6190-11D3-BBBB-00C04F795683}"; break;
+ case MSN_APPID_AVATAR: szAppID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}"; break;
+ default:
+ return;
+ }
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", hContact, szEmail, sizeof( szEmail ));
+
+ ThreadData *thread = MSN_GetThreadByContact( hContact );
+
+ srand( (unsigned)time( NULL ) );
+ long sessionID = rand();
+
+ if ( ft == NULL ) {
+ ft = new filetransfer();
+ ft->std.hContact = hContact;
+ }
+ ft->p2p_appID = iAppID;
+ ft->p2p_msgid = rand();
+ ft->p2p_acksessid = rand();
+ ft->p2p_sessionid = sessionID;
+ ft->p2p_dest = strdup( szEmail );
+ ft->p2p_branch = getNewUuid();
+ ft->p2p_callID = getNewUuid();
+ p2p_registerSession( ft );
+
+ BYTE* pContext;
+ int cbContext;
+
+ if ( iAppID == MSN_APPID_AVATAR ) {
+ ft->inmemTransfer = true;
+ ft->fileBuffer = NULL;
+ ft->std.sending = false;
+
+ char tBuffer[ 256 ] = "";
+ MSN_GetStaticString( "PictContext", hContact, tBuffer, sizeof( tBuffer ));
+
+ char* p = strstr( tBuffer, "Size=\"" );
+ if ( p != NULL )
+ ft->std.totalBytes = ft->std.currentFileSize = atol( p+6 );
+
+ if (ft->create() == -1) {
+ MSN_DebugLog( "Avatar creation failed for MSNCTX=\'%s\'", tBuffer );
+ return;
+ }
+
+ pContext = ( BYTE* )tBuffer;
+ cbContext = strlen( tBuffer )+1;
+ }
+ else {
+ HFileContext ctx;
+ memset( &ctx, 0, sizeof( ctx ));
+ ctx.len = sizeof( ctx );
+ ctx.dwSize = ft->std.totalBytes;
+ if ( ft->wszFileName != NULL )
+ wcsncpy( ctx.wszFileName, ft->wszFileName, sizeof( ctx.wszFileName ));
+ else {
+ char* pszFiles = strrchr( ft->std.currentFile, '\\' );
+ if ( pszFiles )
+ pszFiles++;
+ else
+ pszFiles = ft->std.currentFile;
+
+ MultiByteToWideChar( CP_ACP, 0, pszFiles, -1, ctx.wszFileName, sizeof( ctx.wszFileName ));
+ }
+
+ pContext = ( BYTE* )&ctx;
+ cbContext = sizeof( ctx );
+ }
+
+ char* body = ( char* )alloca( 2000 );
+ int tBytes = mir_snprintf( body, 2000,
+ "EUF-GUID: %s\r\n"
+ "SessionID: %lu\r\n"
+ "AppID: %d\r\n"
+ "Context: ",
+ szAppID, sessionID, iAppID );
+
+ NETLIBBASE64 nlb = { body+tBytes, 2000-tBytes, pContext, cbContext };
+ MSN_CallService( MS_NETLIB_BASE64ENCODE, 0, LPARAM( &nlb ));
+ strcat( body, "\r\n\r\n" );
+ int cbBody = strlen( body );
+ body[ cbBody++ ] = 0;
+
+ MimeHeaders tResult(20);
+ tResult.addString( "CSeq", "0 " );
+ tResult.addString( "Call-ID", ft->p2p_callID );
+ tResult.addLong( "Max-Forwards", 0 );
+ tResult.addString( "Content-Type", "application/x-msnmsgr-sessionreqbody" );
+
+ p2p_sendSlp( MSN_GetThreadByContact( hContact ), ft, tResult, -2, body, cbBody );
+}
diff --git a/miranda-wine/protocols/MSN/msn_p2ps.cpp b/miranda-wine/protocols/MSN/msn_p2ps.cpp
new file mode 100644
index 0000000..55fd57e
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_p2ps.cpp
@@ -0,0 +1,248 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+static int sessionCount = 0;
+static filetransfer** sessionList = NULL;
+static CRITICAL_SECTION sessionLock;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// add file session to a list
+
+void __stdcall p2p_registerSession( filetransfer* ft )
+{
+ EnterCriticalSection( &sessionLock );
+
+ bool bIsFirst = true;
+ for ( int i=0; i < sessionCount; i++ ) {
+ if ( sessionList[i]->std.hContact == ft->std.hContact ) {
+ bIsFirst = false;
+ break;
+ } }
+
+ sessionList = ( filetransfer** )realloc( sessionList, sizeof( void* ) * ( sessionCount+1 ));
+ sessionList[ sessionCount++ ] = ft;
+ ft->mIsFirst = bIsFirst;
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// remove file session from a list
+
+void __stdcall p2p_unregisterSession( filetransfer* ft )
+{
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ if ( sessionList[i] == ft ) {
+ delete sessionList[i];
+ while( i < sessionCount-1 ) {
+ sessionList[ i ] = sessionList[ i+1 ];
+ i++;
+ }
+ sessionCount--;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// remove file sessions for a thread
+
+void __stdcall p2p_unregisterThreadSession( LONG threadID )
+{
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ if ( sessionList[i]->mThreadId == threadID ) {
+ delete sessionList[i];
+ while( i < sessionCount-1 ) {
+ sessionList[ i ] = sessionList[ i+1 ];
+ i++;
+ }
+ sessionCount--;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// get session by some parameter
+
+filetransfer* __stdcall p2p_getSessionByID( unsigned ID )
+{
+ if ( ID == 0 )
+ return NULL;
+
+ filetransfer* ft = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->p2p_sessionid == ID ) {
+ ft = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ if ( ft == NULL )
+ MSN_DebugLog( "Ignoring unknown session id %lu", ID );
+
+ return ft;
+}
+
+filetransfer* __stdcall p2p_getSessionByMsgID( unsigned ID )
+{
+ if ( ID == 0 )
+ return NULL;
+
+ filetransfer* ft = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->p2p_msgid == ID || FT->p2p_msgid == (ID + 1) ) {
+ ft = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ if ( ft == NULL )
+ MSN_DebugLog( "Ignoring unknown message id %lu", ID );
+
+ return ft;
+}
+
+filetransfer* __stdcall p2p_getAnotherContactSession( filetransfer* ft )
+{
+ filetransfer* result = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->std.hContact == ft->std.hContact && FT != ft ) {
+ result = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ return result;
+}
+
+BOOL __stdcall p2p_sessionRegistered( filetransfer* ft )
+{
+ BOOL result = FALSE;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( sessionList[i] == ft ) {
+ result = TRUE;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ return result;
+}
+
+filetransfer* __stdcall p2p_getFirstSession( HANDLE hContact )
+{
+ filetransfer* result = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->std.hContact == hContact && FT->mIsFirst ) {
+ result = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ return result;
+}
+
+filetransfer* __stdcall p2p_getSessionByCallID( const char* CallID )
+{
+ if ( CallID == NULL )
+ return NULL;
+
+ filetransfer* ft = NULL;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->p2p_callID == NULL )
+ continue;
+
+ if ( !strcmp( FT->p2p_callID, CallID )) {
+ ft = FT;
+ break;
+ } }
+
+ LeaveCriticalSection( &sessionLock );
+ if ( ft == NULL )
+ MSN_DebugLog( "Ignoring unknown session call id %s", CallID );
+
+ return ft;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// push another file transfers
+
+void __stdcall p2p_ackOtherFiles( ThreadData* info )
+{
+ filetransfer* ft = info->mP2pSession;
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ ) {
+ filetransfer* FT = sessionList[i];
+ if ( FT->std.hContact == ft->std.hContact && FT != ft )
+ p2p_sendStatus( FT, info->mParentThread, 200 );
+ }
+
+ LeaveCriticalSection( &sessionLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// external functions
+
+void P2pSessions_Init()
+{
+ InitializeCriticalSection( &sessionLock );
+}
+
+void P2pSessions_Uninit()
+{
+ EnterCriticalSection( &sessionLock );
+
+ for ( int i=0; i < sessionCount; i++ )
+ delete sessionList[i];
+ if ( sessionList != NULL )
+ free( sessionList );
+
+ LeaveCriticalSection( &sessionLock );
+ DeleteCriticalSection( &sessionLock );
+}
diff --git a/miranda-wine/protocols/MSN/msn_srv.cpp b/miranda-wine/protocols/MSN/msn_srv.cpp
new file mode 100644
index 0000000..80fb64e
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_srv.cpp
@@ -0,0 +1,184 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+struct ServerGroupItem
+{
+ char* id;
+ char* name; // in UTF8
+ int number;
+
+ ServerGroupItem* next;
+};
+
+static ServerGroupItem* sttFirst = NULL;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_AddGroup - adds new server group to the list
+
+bool MSN_AddGroup( const char* pName, const char* pId )
+{
+ ServerGroupItem* p = new ServerGroupItem;
+ if ( p == NULL )
+ return false;
+
+ p->number = -1;
+ p->id = strdup( pId );
+ p->name = strdup( pName );
+ p->next = sttFirst;
+ sttFirst = p;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_DeleteGroup - deletes a group from the list
+
+void MSN_DeleteGroup( const char* pId )
+{
+ ServerGroupItem* prev = NULL;
+
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next ) {
+ if ( !strcmp( p->id, pId )) {
+ if ( prev == NULL ) sttFirst = p->next;
+ else prev->next = p->next;
+ free( p->id );
+ free( p->name );
+ delete p;
+ return;
+ }
+
+ prev = p;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_FreeGroups - clears the server groups list
+
+void MSN_FreeGroups()
+{
+ ServerGroupItem* p1;
+
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p1 ) {
+ p1 = p->next;
+
+ free( p->id );
+ free( p->name );
+ delete p;
+ }
+
+ sttFirst = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetGroupById - tries to return a group name associated with given UUID
+
+LPCSTR MSN_GetGroupById( const char* pId )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next )
+ if ( stricmp( p->id, pId ) == 0 )
+ return p->name;
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetGroupByName - tries to return a group UUID associated with the given name
+
+LPCSTR MSN_GetGroupByName( const char* pName )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next )
+ if ( strcmp( p->name, pName ) == 0 )
+ return p->id;
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_GetGroupByNumber - tries to return a group UUID associated with the given id
+
+LPCSTR MSN_GetGroupByNumber( int pNumber )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next )
+ if ( p->number == pNumber )
+ return p->id;
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_MoveContactToGroup - sends a contact to the specified group
+
+void MSN_MoveContactToGroup( HANDLE hContact, const char* grpName )
+{
+ LPCSTR szId;
+ char szContactID[ 100 ], szGroupID[ 100 ];
+ if ( MSN_GetStaticString( "ID", hContact, szContactID, sizeof szContactID ))
+ return;
+
+ if ( MSN_GetStaticString( "GroupID", hContact, szGroupID, sizeof szGroupID ))
+ szGroupID[ 0 ] = 0;
+
+ bool bInsert = szGroupID[0] == 0, bDelete = szGroupID[0] != 0;
+
+ if ( grpName != NULL )
+ {
+ if (( szId = MSN_GetGroupByName( grpName )) == NULL ) {
+ MSN_AddServerGroup( grpName );
+ if (( szId = MSN_GetGroupByName( grpName )) == NULL )
+ return;
+ }
+
+ if ( !strcmp( szGroupID, szId )) bDelete = false;
+ else bInsert = true;
+ }
+ else bInsert = false;
+
+ if ( bInsert )
+ msnNsThread->sendPacket( "ADC", "FL C=%s %s", szContactID, szId );
+
+ if ( bDelete )
+ msnNsThread->sendPacket( "REM", "FL %s %s", szContactID, szGroupID );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SetGroupName - sets a new name to a server group
+
+void MSN_SetGroupName( const char* pId, const char* pNewName )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next ) {
+ if ( strcmp( p->id, pId ) == 0 ) {
+ free( p->name );
+ p->name = strdup( pNewName );
+ return;
+} } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN_SetGroupNumber - associate a server group with Miranda's group number
+
+void MSN_SetGroupNumber( const char* pId, int pNumber )
+{
+ for ( ServerGroupItem* p = sttFirst; p != NULL; p = p->next ) {
+ if ( strcmp( p->id, pId ) == 0 ) {
+ p->number = pNumber;
+ return;
+} } }
diff --git a/miranda-wine/protocols/MSN/msn_ssl.cpp b/miranda-wine/protocols/MSN/msn_ssl.cpp
new file mode 100644
index 0000000..7ad28ed
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_ssl.cpp
@@ -0,0 +1,667 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Basic SSL operation class
+
+struct SSL_Base
+{
+ char* m_szEmail;
+
+ virtual ~SSL_Base() {}
+
+ virtual int init() = 0;
+ virtual char* getSslResult( char* parUrl, char* parAuthInfo ) = 0;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// WinInet class
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define ERROR_FLAGS (FLAGS_ERROR_UI_FILTER_FOR_ERRORS | FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS )
+
+#include "wininet.h"
+
+#define SSL_BUF_SIZE 8192
+
+typedef BOOL ( WINAPI *ft_HttpQueryInfo )( HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD );
+typedef BOOL ( WINAPI *ft_HttpSendRequest )( HINTERNET, LPCSTR, DWORD, LPVOID, DWORD );
+typedef BOOL ( WINAPI *ft_InternetCloseHandle )( HINTERNET );
+typedef DWORD ( WINAPI *ft_InternetErrorDlg )( HWND, HINTERNET, DWORD, DWORD, LPVOID* );
+typedef BOOL ( WINAPI *ft_InternetSetOption )( HINTERNET, DWORD, LPVOID, DWORD );
+typedef BOOL ( WINAPI *ft_InternetReadFile )( HINTERNET, LPVOID, DWORD, LPDWORD );
+typedef BOOL ( WINAPI *ft_HttpAddRequestHeaders )( HINTERNET, LPCSTR, DWORD, DWORD );
+
+typedef HINTERNET ( WINAPI *ft_HttpOpenRequest )( HINTERNET, LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPCSTR*, DWORD, DWORD );
+typedef HINTERNET ( WINAPI *ft_InternetConnect )( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD );
+typedef HINTERNET ( WINAPI *ft_InternetOpen )( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD );
+
+struct SSL_WinInet : public SSL_Base
+{
+ virtual ~SSL_WinInet();
+
+ virtual char* getSslResult( char* parUrl, char* parAuthInfo );
+ virtual int init();
+
+ void applyProxy( HINTERNET );
+ void readInput( HINTERNET );
+
+ //-----------------------------------------------------------------------------------
+ HMODULE m_dll;
+
+ ft_InternetCloseHandle f_InternetCloseHandle;
+ ft_InternetConnect f_InternetConnect;
+ ft_InternetErrorDlg f_InternetErrorDlg;
+ ft_InternetOpen f_InternetOpen;
+ ft_InternetReadFile f_InternetReadFile;
+ ft_InternetSetOption f_InternetSetOption;
+ ft_HttpOpenRequest f_HttpOpenRequest;
+ ft_HttpQueryInfo f_HttpQueryInfo;
+ ft_HttpSendRequest f_HttpSendRequest;
+ ft_HttpAddRequestHeaders f_HttpAddRequestHeaders;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int SSL_WinInet::init()
+{
+ if (( m_dll = LoadLibraryA( "WinInet.dll" )) == NULL )
+ return 10;
+
+ f_InternetCloseHandle = (ft_InternetCloseHandle)GetProcAddress( m_dll, "InternetCloseHandle" );
+ f_InternetConnect = (ft_InternetConnect)GetProcAddress( m_dll, "InternetConnectA" );
+ f_InternetErrorDlg = (ft_InternetErrorDlg)GetProcAddress( m_dll, "InternetErrorDlg" );
+ f_InternetOpen = (ft_InternetOpen)GetProcAddress( m_dll, "InternetOpenA" );
+ f_InternetReadFile = (ft_InternetReadFile)GetProcAddress( m_dll, "InternetReadFile" );
+ f_InternetSetOption = (ft_InternetSetOption)GetProcAddress( m_dll, "InternetSetOptionA" );
+ f_HttpOpenRequest = (ft_HttpOpenRequest)GetProcAddress( m_dll, "HttpOpenRequestA" );
+ f_HttpQueryInfo = (ft_HttpQueryInfo)GetProcAddress( m_dll, "HttpQueryInfoA" );
+ f_HttpSendRequest = (ft_HttpSendRequest)GetProcAddress( m_dll, "HttpSendRequestA" );
+ f_HttpAddRequestHeaders = (ft_HttpAddRequestHeaders)GetProcAddress( m_dll, "HttpAddRequestHeadersA" );
+ return 0;
+}
+
+SSL_WinInet::~SSL_WinInet()
+{
+ #if defined( _UNICODE )
+ FreeLibrary( m_dll ); // we free WININET.DLL only if we're under NT
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void SSL_WinInet::applyProxy( HINTERNET parHandle )
+{
+ char tBuffer[ 100 ];
+
+ MSN_DebugLog( "Applying proxy parameters..." );
+
+ if ( !MSN_GetStaticString( "NLProxyAuthUser", NULL, tBuffer, SSL_BUF_SIZE ))
+ f_InternetSetOption( parHandle, INTERNET_OPTION_PROXY_USERNAME, tBuffer, strlen( tBuffer )+1);
+ else
+ MSN_DebugLog( "Warning: proxy user name is required but missing" );
+
+ if ( !MSN_GetStaticString( "NLProxyAuthPassword", NULL, tBuffer, SSL_BUF_SIZE )) {
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( tBuffer ), ( LPARAM )tBuffer );
+ f_InternetSetOption( parHandle, INTERNET_OPTION_PROXY_PASSWORD, tBuffer, strlen( tBuffer )+1);
+ }
+ else MSN_DebugLog( "Warning: proxy user password is required but missing" );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void SSL_WinInet::readInput( HINTERNET hRequest )
+{
+ DWORD dwSize;
+
+ do {
+ char tmpbuf[100];
+ f_InternetReadFile( hRequest, tmpbuf, 50, &dwSize);
+ }
+ while (dwSize != 0);
+}
+
+char* SSL_WinInet::getSslResult( char* parUrl, char* parAuthInfo )
+{
+ DWORD tFlags =
+ INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS |
+ INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP |
+ INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
+ INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
+ INTERNET_FLAG_KEEP_CONNECTION |
+ INTERNET_FLAG_NO_AUTO_REDIRECT |
+ INTERNET_FLAG_NO_CACHE_WRITE |
+ INTERNET_FLAG_NO_COOKIES |
+ INTERNET_FLAG_RELOAD |
+ INTERNET_FLAG_SECURE;
+
+ HINTERNET tNetHandle;
+ char* tBuffer = ( char* )alloca( SSL_BUF_SIZE );
+
+ int tUsesProxy = MSN_GetByte( "NLUseProxy", 0 );
+ if ( tUsesProxy ) {
+ DWORD ptype = MSN_GetByte( "NLProxyType", 0 );
+ if ( !MSN_GetByte( "UseIeProxy", 0 ) && ( ptype == PROXYTYPE_HTTP || ptype == PROXYTYPE_HTTPS )) {
+ char szProxy[ 100 ];
+ if ( MSN_GetStaticString( "NLProxyServer", NULL, szProxy, sizeof szProxy )) {
+ MSN_DebugLog( "Proxy server name should be set if proxy is used" );
+ return NULL;
+ }
+
+ int tPortNumber = MSN_GetWord( NULL, "NLProxyPort", -1 );
+ if ( tPortNumber == -1 ) {
+ MSN_DebugLog( "Proxy server port should be set if proxy is used" );
+ return NULL;
+ }
+
+ mir_snprintf( tBuffer, SSL_BUF_SIZE, "https=http://%s:%d http=http://%s:%d",
+ szProxy, tPortNumber, szProxy, tPortNumber );
+
+ tNetHandle = f_InternetOpen( "MSMSGS", INTERNET_OPEN_TYPE_PROXY, tBuffer, NULL, 0 );
+ }
+ else tNetHandle = f_InternetOpen( "MSMSGS", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
+ }
+ else tNetHandle = f_InternetOpen( "MSMSGS", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0 );
+
+ if ( tNetHandle == NULL ) {
+ MSN_DebugLog( "InternetOpen() failed" );
+ return NULL;
+ }
+
+ MSN_DebugLog( "SSL request (%s): '%s'", ( tUsesProxy ) ? "using proxy": "direct connection", parUrl );
+
+ char* urlStart = strstr( parUrl, "://" );
+ if ( urlStart == NULL )
+ urlStart = parUrl;
+ else
+ urlStart += 3;
+
+ { int tLen = strlen( urlStart )+1;
+ parUrl = ( char* )alloca( tLen );
+ memcpy( parUrl, urlStart, tLen );
+ }
+
+ char* tObjectName = ( char* )strchr( parUrl, '/' );
+ if ( tObjectName != NULL ) {
+ int tLen = strlen( tObjectName )+1;
+ char* newBuf = ( char* )alloca( tLen );
+ memcpy( newBuf, tObjectName, tLen );
+
+ *tObjectName = 0;
+ tObjectName = newBuf;
+ }
+ else tObjectName = "/";
+
+ char* tSslAnswer = NULL;
+
+ HINTERNET tUrlHandle = f_InternetConnect( tNetHandle, parUrl, INTERNET_DEFAULT_HTTPS_PORT, "", "", INTERNET_SERVICE_HTTP, 0, 0 );
+ if ( tUrlHandle != NULL )
+ {
+ HINTERNET tRequest = f_HttpOpenRequest( tUrlHandle, "GET", tObjectName,
+ parAuthInfo ? NULL: HTTP_VERSIONA, NULL, NULL, tFlags, NULL );
+ if ( tRequest != NULL ) {
+ DWORD tBufSize;
+
+ unsigned tm = 3000;
+ f_InternetSetOption( tRequest, INTERNET_OPTION_CONNECT_TIMEOUT, &tm, sizeof(tm));
+ f_InternetSetOption( tRequest, INTERNET_OPTION_SEND_TIMEOUT, &tm, sizeof(tm));
+ f_InternetSetOption( tRequest, INTERNET_OPTION_RECEIVE_TIMEOUT, &tm, sizeof(tm));
+
+ if ( tUsesProxy && MSN_GetByte( "NLUseProxyAuth", 0 ))
+ applyProxy( tRequest );
+
+ char cclose[] = "Connection: close";
+ f_HttpAddRequestHeaders(tRequest, cclose, strlen(cclose), HTTP_ADDREQ_FLAG_ADD );
+LBL_Restart:
+ MSN_DebugLog( "Sending request..." );
+ DWORD tErrorCode = f_HttpSendRequest( tRequest, parAuthInfo, DWORD(-1), NULL, 0 );
+ if ( tErrorCode == 0 ) {
+ TWinErrorCode errCode;
+ MSN_DebugLog( "HttpSendRequest() failed with error %ld", errCode.mErrorCode );
+
+ if ( errCode.mErrorCode == 2 )
+ MSN_ShowError( "Internet Explorer is in the 'Offline' mode. Switch IE to the 'Online' mode and then try to relogin" );
+ else
+ MSN_ShowError( "MSN Passport verification failed with error %d: %s",
+ errCode.mErrorCode, errCode.getText());
+ }
+ else {
+ DWORD dwCode;
+ tBufSize = sizeof( dwCode );
+ f_HttpQueryInfo( tRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &tBufSize, 0 );
+
+ switch( dwCode ) {
+ case HTTP_STATUS_REDIRECT:
+ tBufSize = SSL_BUF_SIZE;
+ f_HttpQueryInfo( tRequest, HTTP_QUERY_LOCATION, tBuffer, &tBufSize, NULL );
+ MSN_DebugLog( "Redirected to '%s'", tBuffer );
+ tSslAnswer = getSslResult( tBuffer, parAuthInfo );
+ break;
+
+ case HTTP_STATUS_OK:
+ LBL_PrintHeaders:
+ tBufSize = SSL_BUF_SIZE;
+ f_HttpQueryInfo( tRequest, HTTP_QUERY_RAW_HEADERS_CRLF, tBuffer, &tBufSize, NULL );
+ MSN_DebugLog( "SSL response: '%s'", tBuffer );
+ tSslAnswer = dwCode == HTTP_STATUS_OK ? strdup( tBuffer ) : NULL;
+ break;
+
+ case ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR:
+ case ERROR_INTERNET_INCORRECT_PASSWORD:
+ case ERROR_INTERNET_INVALID_CA:
+ case ERROR_INTERNET_POST_IS_NON_SECURE:
+ case ERROR_INTERNET_SEC_CERT_CN_INVALID:
+ case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
+ case ERROR_INTERNET_SEC_CERT_ERRORS:
+ case ERROR_INTERNET_SEC_CERT_NO_REV:
+ case ERROR_INTERNET_SEC_CERT_REV_FAILED:
+ MSN_DebugLog( "HttpSendRequest returned error code %d", tErrorCode );
+ if ( ERROR_INTERNET_FORCE_RETRY == f_InternetErrorDlg( GetDesktopWindow(), tRequest, tErrorCode, ERROR_FLAGS, NULL )) {
+ readInput( tRequest );
+ goto LBL_Restart;
+ }
+
+ // else fall into the general error handling routine
+
+ default:
+ tBufSize = SSL_BUF_SIZE;
+ if ( !f_HttpQueryInfo( tRequest, HTTP_QUERY_STATUS_TEXT, tBuffer, &tBufSize, NULL ))
+ strcpy( tBuffer, "unknown error" );
+
+ MSN_ShowError( "Internet secure connection (SSL) failed with error %d: %s", dwCode, tBuffer );
+ MSN_DebugLog( "SSL error %d: '%s'", dwCode, tBuffer );
+ goto LBL_PrintHeaders;
+ } }
+
+ f_InternetCloseHandle( tRequest );
+ }
+
+ f_InternetCloseHandle( tUrlHandle );
+ }
+ else MSN_DebugLog( "InternetOpenUrl() failed" );
+
+ f_InternetCloseHandle( tNetHandle );
+ return tSslAnswer;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Performs the MSN Passport login via SSL3 using the OpenSSL library
+
+typedef int ( *PFN_SSL_int_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_pvoid ) ( PVOID );
+typedef void ( *PFN_SSL_void_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_int ) ( PVOID, int );
+typedef int ( *PFN_SSL_int_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_pvoid_int ) ( PVOID, PVOID, int );
+
+struct SSL_OpenSsl : public SSL_Base
+{
+ virtual char* getSslResult( char* parUrl, char* parAuthInfo );
+ virtual int init();
+
+ static PVOID sslCtx;
+
+ static HMODULE hLibSSL, hLibEAY;
+ static PFN_SSL_int_void pfn_SSL_library_init;
+ static PFN_SSL_pvoid_void pfn_SSLv23_client_method;
+ static PFN_SSL_pvoid_pvoid pfn_SSL_CTX_new;
+ static PFN_SSL_void_pvoid pfn_SSL_CTX_free;
+ static PFN_SSL_pvoid_pvoid pfn_SSL_new;
+ static PFN_SSL_void_pvoid pfn_SSL_free;
+ static PFN_SSL_int_pvoid_int pfn_SSL_set_fd;
+ static PFN_SSL_int_pvoid pfn_SSL_connect;
+ static PFN_SSL_int_pvoid_pvoid_int pfn_SSL_read;
+ static PFN_SSL_int_pvoid_pvoid_int pfn_SSL_write;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PVOID SSL_OpenSsl::sslCtx = NULL;
+
+HMODULE SSL_OpenSsl::hLibSSL = NULL,
+ SSL_OpenSsl::hLibEAY = NULL;
+
+PFN_SSL_int_void SSL_OpenSsl::pfn_SSL_library_init;
+PFN_SSL_pvoid_void SSL_OpenSsl::pfn_SSLv23_client_method;
+PFN_SSL_pvoid_pvoid SSL_OpenSsl::pfn_SSL_CTX_new;
+PFN_SSL_void_pvoid SSL_OpenSsl::pfn_SSL_CTX_free;
+PFN_SSL_pvoid_pvoid SSL_OpenSsl::pfn_SSL_new;
+PFN_SSL_void_pvoid SSL_OpenSsl::pfn_SSL_free;
+PFN_SSL_int_pvoid_int SSL_OpenSsl::pfn_SSL_set_fd;
+PFN_SSL_int_pvoid SSL_OpenSsl::pfn_SSL_connect;
+PFN_SSL_int_pvoid_pvoid_int SSL_OpenSsl::pfn_SSL_read;
+PFN_SSL_int_pvoid_pvoid_int SSL_OpenSsl::pfn_SSL_write;
+
+int SSL_OpenSsl::init()
+{
+ if ( sslCtx != NULL )
+ return 0;
+
+ if ( hLibSSL == NULL ) {
+ if (( hLibEAY = LoadLibraryA( "LIBEAY32.DLL" )) == NULL ) {
+ MSN_ShowError( "Valid %s must be installed to perform the SSL login", "LIBEAY32.DLL" );
+ return 1;
+ }
+
+ if (( hLibSSL = LoadLibraryA( "LIBSSL32.DLL" )) == NULL ) {
+ MSN_ShowError( "Valid %s must be installed to perform the SSL login", "LIBSSL32.DLL" );
+ return 1;
+ } }
+
+ int retVal = 0;
+ if (( pfn_SSL_library_init = ( PFN_SSL_int_void )GetProcAddress( hLibSSL, "SSL_library_init" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSLv23_client_method = ( PFN_SSL_pvoid_void )GetProcAddress( hLibSSL, "SSLv23_client_method" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_CTX_new = ( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_new" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_CTX_free = ( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_free" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_new = ( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_new" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_free = ( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_free" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_set_fd = ( PFN_SSL_int_pvoid_int )GetProcAddress( hLibSSL, "SSL_set_fd" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_connect = ( PFN_SSL_int_pvoid )GetProcAddress( hLibSSL, "SSL_connect" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_read = ( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_read" )) == NULL )
+ retVal = TRUE;
+ if (( pfn_SSL_write = ( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_write" )) == NULL )
+ retVal = TRUE;
+
+ if ( retVal ) {
+ FreeLibrary( hLibSSL );
+ MSN_ShowError( "Valid %s must be installed to perform the SSL login", "LIBSSL32.DLL" );
+ return 1;
+ }
+
+ pfn_SSL_library_init();
+ sslCtx = pfn_SSL_CTX_new( pfn_SSLv23_client_method());
+ MSN_DebugLog( "OpenSSL context successully allocated" );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+char* SSL_OpenSsl::getSslResult( char* parUrl, char* parAuthInfo )
+{
+ if ( strnicmp( parUrl, "https://", 8 ) != 0 )
+ return NULL;
+
+ char* url = NEWSTR_ALLOCA( parUrl );
+ char* path = strchr( url+9, '//' );
+ if ( path == NULL ) {
+ MSN_DebugLog( "Invalid URL passed: '%s'", parUrl );
+ return NULL;
+ }
+ *path++ = 0;
+
+ NETLIBUSERSETTINGS nls = { 0 };
+ nls.cbSize = sizeof( nls );
+ MSN_CallService(MS_NETLIB_GETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ int cpType = nls.proxyType;
+
+ if (cpType == PROXYTYPE_HTTP)
+ {
+ nls.proxyType = PROXYTYPE_HTTPS;
+ nls.szProxyServer = NEWSTR_ALLOCA(nls.szProxyServer);
+ nls.szIncomingPorts = NEWSTR_ALLOCA(nls.szIncomingPorts);
+ nls.szOutgoingPorts = NEWSTR_ALLOCA(nls.szOutgoingPorts);
+ nls.szProxyAuthPassword = NEWSTR_ALLOCA(nls.szProxyAuthPassword);
+ nls.szProxyAuthUser = NEWSTR_ALLOCA(nls.szProxyAuthUser);
+ MSN_CallService(MS_NETLIB_SETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ }
+
+ NETLIBOPENCONNECTION tConn = { 0 };
+ tConn.cbSize = sizeof( tConn );
+ tConn.szHost = url+8;
+ tConn.wPort = 443;
+ HANDLE h = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
+
+ if (cpType == PROXYTYPE_HTTP)
+ {
+ nls.proxyType = PROXYTYPE_HTTP;
+ nls.szProxyServer = NEWSTR_ALLOCA(nls.szProxyServer);
+ nls.szIncomingPorts = NEWSTR_ALLOCA(nls.szIncomingPorts);
+ nls.szOutgoingPorts = NEWSTR_ALLOCA(nls.szOutgoingPorts);
+ nls.szProxyAuthPassword = NEWSTR_ALLOCA(nls.szProxyAuthPassword);
+ nls.szProxyAuthUser = NEWSTR_ALLOCA(nls.szProxyAuthUser);
+ MSN_CallService(MS_NETLIB_SETUSERSETTINGS,WPARAM(hNetlibUser),LPARAM(&nls));
+ }
+
+ if ( h == NULL )
+ return NULL;
+
+ char* result = NULL;
+ PVOID ssl = pfn_SSL_new( sslCtx );
+ if ( ssl != NULL ) {
+ SOCKET s = MSN_CallService( MS_NETLIB_GETSOCKET, ( WPARAM )h, 0 );
+ if ( s != INVALID_SOCKET ) {
+ pfn_SSL_set_fd( ssl, s );
+ if ( pfn_SSL_connect( ssl ) > 0 ) {
+ MSN_DebugLog( "SSL connection succeeded" );
+
+ char *buf = ( char* )alloca( SSL_BUF_SIZE );
+
+ int nBytes = mir_snprintf( buf, SSL_BUF_SIZE,
+ "GET /%s HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Accept-Language: en;q=0.5\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)\r\n"
+ "Host: %s\r\n"
+ "Connection: Keep-Alive\r\n", path, url+8 );
+
+ if ( parAuthInfo != NULL ) {
+ strcat( buf+nBytes, parAuthInfo );
+ strcat( buf+nBytes, "\r\n" );
+ }
+
+ strcat( buf+nBytes, "\r\n" );
+
+// MSN_DebugLog( "Sending SSL query:\n%s", buf );
+ pfn_SSL_write( ssl, buf, strlen( buf ));
+
+ nBytes = pfn_SSL_read( ssl, buf, SSL_BUF_SIZE );
+ if ( nBytes > 0 ) {
+ result = ( char* )malloc( nBytes+1 );
+ memcpy( result, buf, nBytes+1 );
+ result[ nBytes ] = 0;
+
+ MSN_DebugLog( "SSL read successfully read %d bytes:\n%s", nBytes, result );
+ }
+ else MSN_DebugLog( "SSL read failed" );
+ }
+ else MSN_DebugLog( "SSL connection failed" );
+ }
+ else MSN_DebugLog( "pfn_SSL_connect failed" );
+
+ pfn_SSL_free( ssl );
+ }
+ else MSN_DebugLog( "pfn_SSL_new failed" );
+
+ MSN_CallService( MS_NETLIB_CLOSEHANDLE, ( WPARAM )h, 0 );
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Checks the MSN Passport redirector site
+
+int MSN_CheckRedirector()
+{
+ int retVal = 0;
+ SSL_Base* pAgent;
+ if ( MSN_GetByte( "UseOpenSSL", 0 ))
+ pAgent = new SSL_OpenSsl();
+ else
+ pAgent = new SSL_WinInet();
+ if ( pAgent == NULL )
+ return 1;
+
+ if ( pAgent->init() ) {
+ delete pAgent;
+ return 2;
+ }
+
+ char* msnLoginHost = pAgent->getSslResult( "https://nexus.passport.com/rdr/pprdr.asp", NULL );
+ if ( msnLoginHost == NULL ) {
+ retVal = 1;
+LBL_Exit:
+ delete pAgent;
+ MSN_DebugLog( "MSN_CheckRedirector exited with errorCode = %d", retVal );
+ return retVal;
+ }
+
+ char* p = strstr( msnLoginHost, "DALogin=" );
+ if ( p == NULL ) {
+ free( msnLoginHost ); msnLoginHost = NULL;
+ retVal = 2;
+ goto LBL_Exit;
+ }
+
+ strcpy( msnLoginHost, "https://" );
+ strdel( msnLoginHost+8, int( p-msnLoginHost ));
+ if (( p = strchr( msnLoginHost, ',' )) != 0 )
+ *p = 0;
+
+ MSN_SetString( NULL, "MsnPassportHost", msnLoginHost );
+ MSN_DebugLog( "MSN Passport login host is set to '%s'", msnLoginHost );
+ free( msnLoginHost );
+ goto LBL_Exit;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Performs the MSN Passport login via SSL3
+
+int MSN_GetPassportAuth( char* authChallengeInfo, char*& parResult )
+{
+ int retVal = 0;
+ parResult = NULL;
+ SSL_Base* pAgent;
+ if ( MSN_GetByte( "UseOpenSSL", 0 ))
+ pAgent = new SSL_OpenSsl();
+ else
+ pAgent = new SSL_WinInet();
+ if ( pAgent == NULL )
+ return 1;
+
+ if ( pAgent->init() ) {
+ delete pAgent;
+ return 2;
+ }
+
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, szEmail, MSN_MAX_EMAIL_LEN );
+ char* p = strchr( szEmail, '@' );
+ if ( p != NULL ) {
+ memmove( p+3, p+1, strlen( p ));
+ memcpy( p, "%40", 3 );
+ }
+
+ char szPassword[ 100 ];
+ MSN_GetStaticString( "Password", NULL, szPassword, sizeof szPassword );
+ MSN_CallService( MS_DB_CRYPT_DECODESTRING, strlen( szPassword )+1, ( LPARAM )szPassword );
+ szPassword[ 16 ] = 0;
+
+ char* szAuthInfo = ( char* )alloca( 1024 );
+ int nBytes = mir_snprintf( szAuthInfo, 1024,
+ "Authorization: Passport1.4 OrgVerb=GET,OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom,sign-in=%s,pwd=",
+ szEmail );
+ UrlEncode( szPassword, szAuthInfo+nBytes, 1024-nBytes );
+ strcat( szAuthInfo+nBytes, "," );
+ strcat( szAuthInfo+nBytes, authChallengeInfo );
+
+ char szPassportHost[ 256 ];
+ if ( MSN_GetStaticString( "MsnPassportHost", NULL, szPassportHost, sizeof( szPassportHost ))) {
+ retVal = 3;
+LBL_Exit:
+ delete pAgent;
+ MSN_DebugLog( "MSN_CheckRedirector exited with errorCode = %d", retVal );
+ return retVal;
+ }
+
+ char* tResult;
+
+ for (;;)
+ {
+ tResult = pAgent->getSslResult( szPassportHost, szAuthInfo );
+ if ( tResult == NULL ) {
+ retVal = 4;
+ goto LBL_Exit;
+ }
+
+ int status = 0;
+ sscanf( tResult, "HTTP/1.1 %d", &status );
+ if ( status == 302 ) // Handle redirect
+ {
+ if (( p = strstr( tResult, "Location:" )) == NULL ) {
+ free( tResult );
+ retVal = 7;
+ goto LBL_Exit;
+ }
+ strdel( tResult, int( p-tResult )+10 );
+ if (( p = strchr( tResult, '\r' )) != NULL )
+ *p = 0;
+ strcpy(szPassportHost, tResult);
+ MSN_DebugLog( "Redirected to '%s'", tResult );
+ free( tResult );
+ }
+ else if (status != 200)
+ {
+ retVal = 6;
+ free( tResult );
+ goto LBL_Exit;
+ }
+ else break;
+ }
+
+ if (( p = strstr( tResult, "from-PP=" )) == NULL ) {
+ free( tResult );
+ retVal = 5;
+ goto LBL_Exit;
+ }
+
+ strdel( tResult, int( p-tResult )+9 );
+
+ if (( p = strchr( tResult, '\'' )) != NULL )
+ *p = 0;
+
+ parResult = tResult;
+ goto LBL_Exit;
+}
+
+void UninitSsl( void )
+{
+ if ( SSL_OpenSsl::hLibEAY )
+ FreeLibrary( SSL_OpenSsl::hLibEAY );
+
+ if ( SSL_OpenSsl::hLibSSL ) {
+ SSL_OpenSsl::pfn_SSL_CTX_free( SSL_OpenSsl::sslCtx );
+
+ MSN_DebugLog( "Free SSL library" );
+ FreeLibrary( SSL_OpenSsl::hLibSSL );
+} }
diff --git a/miranda-wine/protocols/MSN/msn_std.cpp b/miranda-wine/protocols/MSN/msn_std.cpp
new file mode 100644
index 0000000..c13af19
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_std.cpp
@@ -0,0 +1,158 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+extern HANDLE msnBlockMenuItem;
+
+HANDLE __stdcall MSN_CreateProtoServiceFunction(
+ const char* szService,
+ MIRANDASERVICE serviceProc )
+{
+ char str[ MAXMODULELABELLENGTH ];
+ strcpy( str, msnProtocolName );
+ strcat( str, szService );
+ return CreateServiceFunction( str, serviceProc );
+}
+
+#if !defined( _DEBUG )
+int __stdcall MSN_CallService( const char* szSvcName, WPARAM wParam, LPARAM lParam )
+{
+ return CallService( szSvcName, wParam, lParam );
+}
+#endif
+
+void __stdcall MSN_EnableMenuItems( BOOL parEnable )
+{
+ CLISTMENUITEM clmi;
+ memset( &clmi, 0, sizeof( clmi ));
+ clmi.cbSize = sizeof( clmi );
+ clmi.flags = CMIM_FLAGS;
+ if ( !parEnable )
+ clmi.flags |= CMIF_GRAYED;
+
+ for ( int i=0; i < MENU_ITEMS_COUNT; i++ )
+ {
+ if ( msnMenuItems[i] == NULL )
+ continue;
+
+ MSN_CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )msnMenuItems[i], ( LPARAM )&clmi );
+ }
+
+ MSN_CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )msnBlockMenuItem, ( LPARAM )&clmi );
+}
+
+DWORD __stdcall MSN_GetByte( const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( NULL, msnProtocolName, valueName, parDefltValue );
+}
+
+char* __stdcall MSN_GetContactName( HANDLE hContact )
+{
+ return ( char* )MSN_CallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact), 0 );
+}
+
+TCHAR* __stdcall MSN_GetContactNameT( HANDLE hContact )
+{
+ return ( TCHAR* )MSN_CallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact), GCDNF_TCHAR );
+}
+
+DWORD __stdcall MSN_GetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue )
+{
+ return DBGetContactSettingDword( hContact, msnProtocolName, valueName, parDefltValue );
+}
+
+int __stdcall MSN_GetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len )
+{
+ DBVARIANT dbv;
+ dbv.pszVal = dest;
+ dbv.cchVal = dest_len;
+ dbv.type = DBVT_ASCIIZ;
+
+ DBCONTACTGETSETTING sVal;
+ sVal.pValue = &dbv;
+ sVal.szModule = msnProtocolName;
+ sVal.szSetting = valueName;
+ if ( MSN_CallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )hContact, ( LPARAM )&sVal ) != 0 )
+ return 1;
+
+ return ( dbv.type != DBVT_ASCIIZ );
+}
+
+WORD __stdcall MSN_GetWord( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingWord( hContact, msnProtocolName, valueName, parDefltValue );
+}
+
+void __fastcall MSN_FreeVariant( DBVARIANT* dbv )
+{
+ DBFreeVariant( dbv );
+}
+
+int __stdcall MSN_SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam )
+{
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = msnProtocolName;
+ ack.hContact = hContact;
+ ack.type = type;
+ ack.result = result;
+ ack.hProcess = hProcess;
+ ack.lParam = lParam;
+ return MSN_CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+DWORD __stdcall MSN_SetByte( const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( NULL, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetDword( HANDLE hContact, const char* valueName, DWORD parValue )
+{
+ return DBWriteContactSettingDword( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetString( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingString( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue )
+{
+ return DBWriteContactSettingTString( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetStringUtf( HANDLE hContact, const char* valueName, char* parValue )
+{
+ return DBWriteContactSettingStringUtf( hContact, msnProtocolName, valueName, parValue );
+}
+
+DWORD __stdcall MSN_SetWord( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingWord( hContact, msnProtocolName, valueName, parValue );
+}
+
+char* __stdcall MSN_Translate( const char* str )
+{
+ return Translate( str );
+}
diff --git a/miranda-wine/protocols/MSN/msn_svcs.cpp b/miranda-wine/protocols/MSN/msn_svcs.cpp
new file mode 100644
index 0000000..1faac95
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_svcs.cpp
@@ -0,0 +1,1404 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+
+#include "resource.h"
+
+void __cdecl MSNServerThread( ThreadData* info );
+void MSN_ChatStart(ThreadData* info);
+
+void msnftp_sendAcceptReject( filetransfer *ft, bool acc );
+
+HANDLE msnBlockMenuItem = NULL;
+extern char* profileURL;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnAddToList - adds contact to the server list
+
+static HANDLE AddToListByEmail( const char *email, DWORD flags )
+{
+ char urlEmail[ 255 ], *szProto;
+ UrlEncode( email, urlEmail, sizeof( urlEmail ));
+ HANDLE hContact;
+
+ //check not already on list
+ for ( hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ hContact != NULL;
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )hContact, 0 ))
+ {
+ szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( szProto != NULL && !strcmp( szProto, msnProtocolName )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail )))
+ continue;
+
+ if ( strcmp( tEmail, email ))
+ continue;
+
+ if ( !( flags & PALF_TEMPORARY ) && DBGetContactSettingByte( hContact, "CList", "NotOnList", 1 )) {
+ DBDeleteContactSetting( hContact, "CList", "NotOnList" );
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+LBL_AddContact:
+ if ( msnLoggedIn ) {
+ MSN_AddUser( hContact, urlEmail, LIST_FL );
+ MSN_AddUser( hContact, urlEmail, LIST_BL + LIST_REMOVE );
+ MSN_AddUser( hContact, urlEmail, LIST_AL );
+ }
+ else hContact = NULL;
+ }
+
+ return hContact;
+ } }
+
+ //not already there: add
+ hContact = ( HANDLE )MSN_CallService( MS_DB_CONTACT_ADD, 0, 0 );
+ MSN_CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )msnProtocolName );
+ MSN_SetString( hContact, "e-mail", email );
+
+ if ( !( flags & PALF_TEMPORARY ))
+ goto LBL_AddContact;
+
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 );
+ return hContact;
+}
+
+static int MsnAddToList(WPARAM wParam,LPARAM lParam)
+{
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)lParam;
+
+ if ( psr->cbSize != sizeof( PROTOSEARCHRESULT ))
+ return NULL;
+
+ return ( int )AddToListByEmail( psr->email, wParam );
+}
+
+static int MsnAddToListByEvent(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ if (( dbei.cbBlob = MSN_CallService( MS_DB_EVENT_GETBLOBSIZE, lParam, 0 )) == (DWORD)(-1))
+ return 0;
+
+ dbei.pBlob=(PBYTE) alloca(dbei.cbBlob);
+ if ( MSN_CallService(MS_DB_EVENT_GET, lParam, ( LPARAM )&dbei)) return 0;
+ if ( strcmp(dbei.szModule, msnProtocolName)) return 0;
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST) return 0;
+
+ char* nick = (char *) (dbei.pBlob + sizeof(DWORD) + sizeof(HANDLE));
+ char* firstName = nick + strlen(nick) + 1;
+ char* lastName = firstName + strlen(firstName) + 1;
+ char* email = lastName + strlen(lastName) + 1;
+
+ return ( int ) AddToListByEmail( email, 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnAuthAllow - called after successful authorization
+
+static int MsnAuthAllow(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 1;
+
+ DBEVENTINFO dbei;
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = MSN_CallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == -1 )
+ return 1;
+
+ dbei.pBlob = ( PBYTE )alloca( dbei.cbBlob );
+ if ( MSN_CallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+
+ if ( strcmp( dbei.szModule, msnProtocolName ))
+ return 1;
+
+ char* nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+ char* firstName = nick + strlen( nick ) + 1;
+ char* lastName = firstName + strlen( firstName ) + 1;
+ char* email = lastName + strlen( lastName ) + 1;
+
+ char urlNick[388],urlEmail[130];
+
+ UrlEncode( UTF8( nick ), urlNick, sizeof( urlNick ));
+ UrlEncode( email, urlEmail, sizeof( urlEmail ));
+
+ AddToListByEmail( email, 0 );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnAuthDeny - called after unsuccessful authorization
+
+static int MsnAuthDeny(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 1;
+
+ DBEVENTINFO dbei;
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+
+ if (( dbei.cbBlob = MSN_CallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == -1 )
+ return 1;
+
+ dbei.pBlob = ( PBYTE )alloca( dbei.cbBlob );
+ if ( MSN_CallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+
+ if ( strcmp( dbei.szModule, msnProtocolName ))
+ return 1;
+
+ char* nick = ( char* )( dbei.pBlob + sizeof( DWORD )*2 );
+ char* firstName = nick + strlen( nick ) + 1;
+ char* lastName = firstName + strlen( firstName ) + 1;
+ char* email = lastName + strlen( lastName ) + 1;
+
+ char urlNick[388],urlEmail[130];
+
+ UrlEncode( UTF8(nick), urlNick, sizeof( urlNick ));
+ UrlEncode( email, urlEmail, sizeof( urlEmail ));
+
+ MSN_AddUser( NULL, urlEmail, LIST_BL );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnBasicSearch - search contacts by e-mail
+
+static int MsnBasicSearch(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn || msnSearchID != -1 )
+ return 0;
+
+ char tEmail[ 256 ];
+ if ( !MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail )) {
+ if ( !stricmp(( char* )lParam, tEmail )) {
+ MSN_ShowError( "You cannot add yourself to the contact list" );
+ return 0;
+ } }
+
+ UrlEncode(( char* )lParam, tEmail, sizeof( tEmail ));
+ return msnSearchID = msnNsThread->sendPacket( "ADC", "BL N=%s", tEmail );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Block command callback function
+
+static int MsnBlockCommand( WPARAM wParam, LPARAM lParam )
+{
+ if ( msnLoggedIn ) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, tEmail, sizeof( tEmail )))
+ MSN_SetWord(( HANDLE )wParam, "ApparentMode", ( Lists_IsInList( LIST_BL, tEmail )) ? 0 : ID_STATUS_OFFLINE );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnContactDeleted - called when a contact is deleted from list
+
+static int MsnContactDeleted( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn ) //should never happen for MSN contacts
+ return 0;
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( szProto == NULL || strcmp( szProto, msnProtocolName ))
+ return 0;
+
+ HANDLE hContact = ( HANDLE )wParam;
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail ))) {
+ MSN_AddUser( hContact, tEmail, LIST_FL | LIST_REMOVE );
+ MSN_AddUser( hContact, tEmail, LIST_AL | LIST_REMOVE );
+
+ if ( !Lists_IsInList( LIST_RL, tEmail )) {
+ MSN_AddUser( hContact, tEmail, LIST_BL | LIST_REMOVE );
+ Lists_Remove( 0xFF, tEmail );
+ }
+ else {
+ MSN_AddUser( hContact, tEmail, LIST_BL );
+ Lists_Remove( LIST_FL, tEmail );
+ } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnDbSettingChanged - look for contact's settings changes
+
+static int MsnDbSettingChanged(WPARAM wParam,LPARAM lParam)
+{
+ HANDLE hContact = ( HANDLE )wParam;
+ DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam;
+
+ if ( !msnLoggedIn )
+ return 0;
+
+ if ( hContact == NULL && MyOptions.ManageServer && !strcmp( cws->szModule, "CListGroups" )) {
+ int iNumber = atol( cws->szSetting );
+ LPCSTR szId = MSN_GetGroupByNumber( iNumber );
+ if ( szId == NULL ) {
+ if ( cws->value.type == DBVT_ASCIIZ )
+ MSN_AddServerGroup( cws->value.pszVal+1 );
+ return 0;
+ }
+
+ switch ( cws->value.type ) {
+ case DBVT_DELETED: msnNsThread->sendPacket( "RMG", szId ); break;
+ case DBVT_UTF8: MSN_RenameServerGroup( iNumber, szId, cws->value.pszVal+1 ); break;
+ case DBVT_ASCIIZ: MSN_RenameServerGroup( iNumber, szId, UTF8( cws->value.pszVal+1 )); break;
+ }
+ return 0;
+ }
+
+ if ( !strcmp( cws->szSetting, "ApparentMode" )) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", hContact, tEmail, sizeof( tEmail ))) {
+ int isBlocked = Lists_IsInList( LIST_BL, tEmail );
+
+ if ( !isBlocked && cws->value.wVal == ID_STATUS_OFFLINE ) {
+ MSN_AddUser( hContact, tEmail, LIST_AL + LIST_REMOVE );
+ MSN_AddUser( hContact, tEmail, LIST_BL );
+ }
+ else if ( isBlocked && cws->value.wVal == 0 ) {
+ MSN_AddUser( hContact, tEmail, LIST_BL + LIST_REMOVE );
+ MSN_AddUser( hContact, tEmail, LIST_AL );
+ } } }
+
+ if ( !strcmp( cws->szModule, "CList" ) && MyOptions.ManageServer ) {
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto == NULL || strcmp( szProto, msnProtocolName ))
+ return 0;
+
+ if ( !strcmp( cws->szSetting, "Group" )) {
+ switch( cws->value.type ) {
+ case DBVT_DELETED: MSN_MoveContactToGroup( hContact, NULL ); break;
+ case DBVT_ASCIIZ: MSN_MoveContactToGroup( hContact, UTF8(cws->value.pszVal)); break;
+ case DBVT_UTF8: MSN_MoveContactToGroup( hContact, cws->value.pszVal ); break;
+ }
+ return 0;
+ }
+
+ if ( !strcmp( cws->szSetting, "MyHandle" )) {
+ char szContactID[ 100 ], szNewNick[ 387 ];
+ if ( !MSN_GetStaticString( "ID", hContact, szContactID, sizeof( szContactID ))) {
+ if ( cws->value.type != DBVT_DELETED ) {
+ if ( cws->value.type == DBVT_UTF8 )
+ UrlEncode( cws->value.pszVal, szNewNick, sizeof( szNewNick ));
+ else
+ UrlEncode( UTF8(cws->value.pszVal), szNewNick, sizeof( szNewNick ));
+ msnNsThread->sendPacket( "SBP", "%s MFN %s", szContactID, szNewNick );
+ }
+ else {
+ MSN_GetStaticString( "e-mail", hContact, szNewNick, sizeof( szNewNick ));
+ msnNsThread->sendPacket( "SBP", "%s MFN %s", szContactID, szNewNick );
+ }
+ return 0;
+ } } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnEditProfile - goes to the Profile section at the Hotmail.com
+
+static int MsnEditProfile( WPARAM, LPARAM )
+{
+ char tUrl[ 4096 ];
+ mir_snprintf( tUrl, sizeof( tUrl ), "%s&did=1&t=%s&js=yes", profileURL, MSPAuth );
+ MSN_CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )tUrl );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileAllow - starts the file transfer
+
+static void __cdecl MsnFileAckThread( void* arg )
+{
+ filetransfer* ft = (filetransfer*)arg;
+ if ( !ft->inmemTransfer )
+ {
+ char filefull[ MAX_PATH ];
+ mir_snprintf( filefull, sizeof filefull, "%s\\%s", ft->std.workingDir, ft->std.currentFile );
+ replaceStr( ft->std.currentFile, filefull );
+
+ if ( MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, ( LPARAM )&ft->std ))
+ return;
+
+ if ( ft->wszFileName != NULL ) {
+ free( ft->wszFileName );
+ ft->wszFileName = NULL;
+ } }
+
+ bool fcrt = ft->create() != -1;
+
+ if ( ft->p2p_appID != 0)
+ p2p_sendStatus( ft, MSN_GetThreadByID( ft->mThreadId ), fcrt ? 200 : 603 );
+ else
+ msnftp_sendAcceptReject (ft, fcrt);
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+}
+
+int MsnFileAllow(WPARAM wParam, LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 0;
+
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ if (( ft->std.workingDir = strdup(( char* )ccs->lParam )) == NULL ) {
+ char szCurrDir[ MAX_PATH ];
+ GetCurrentDirectoryA( sizeof( szCurrDir ), szCurrDir );
+ ft->std.workingDir = strdup( szCurrDir );
+ }
+ else {
+ int len = strlen( ft->std.workingDir )-1;
+ if ( ft->std.workingDir[ len ] == '\\' )
+ ft->std.workingDir[ len ] = 0;
+ }
+
+ MSN_StartThread( MsnFileAckThread, ft );
+
+ return int( ft );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileCancel - cancels the active file transfer
+
+int MsnFileCancel(WPARAM wParam, LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ if ( ft->hWaitEvent != INVALID_HANDLE_VALUE )
+ SetEvent( ft->hWaitEvent );
+
+ ThreadData* thread = MSN_GetThreadByID( ft->mThreadId );
+ if (!ft->std.sending && ft->fileId == -1)
+ {
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus(ft, thread, 603);
+ else
+ msnftp_sendAcceptReject (ft, false);
+ }
+ else
+ {
+ if ( ft->p2p_appID != 0 )
+ p2p_sendCancel( thread, ft );
+ else
+ ft->bCanceled = true;
+ }
+
+ ft->std.files = NULL;
+ ft->std.totalFiles = 0;
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileDeny - rejects the file transfer request
+
+int MsnFileDeny( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn )
+ return 1;
+
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus( ft, MSN_GetThreadByID(ft->mThreadId), 603 );
+ else
+ msnftp_sendAcceptReject (ft, false);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnFileResume - renames a file
+
+int MsnFileResume( WPARAM wParam, LPARAM lParam )
+{
+ filetransfer* ft = ( filetransfer* )wParam;
+ if ( !msnLoggedIn || ft == NULL )
+ return 1;
+
+ PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam;
+ switch (pfr->action)
+ {
+ case FILERESUME_SKIP:
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus( ft, MSN_GetThreadByID( ft->mThreadId ), 603 );
+ else
+ msnftp_sendAcceptReject (ft, false);
+ break;
+
+ case FILERESUME_RENAME:
+ if ( ft->wszFileName != NULL ) {
+ free( ft->wszFileName );
+ ft->wszFileName = NULL;
+ }
+ replaceStr( ft->std.currentFile, pfr->szFilename );
+
+ default:
+ bool fcrt = ft->create() != -1;
+ if ( ft->p2p_appID != 0 )
+ p2p_sendStatus( ft, MSN_GetThreadByID( ft->mThreadId ), fcrt ? 200 : 603 );
+ else
+ msnftp_sendAcceptReject (ft, fcrt);
+
+ MSN_SendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0);
+ break;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetAvatarInfo - retrieve the avatar info
+
+static int MsnGetAvatarInfo(WPARAM wParam,LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ if ( !MyOptions.EnableAvatars || ( MSN_GetDword( AI->hContact, "FlagBits", 0 ) & 0x40000000 ) == 0 )
+ return GAIR_NOAVATAR;
+
+ char szContext[ MAX_PATH ];
+ if ( MSN_GetStaticString(( AI->hContact == NULL ) ? "PictObject" : "PictContext", AI->hContact, szContext, sizeof szContext ))
+ return GAIR_NOAVATAR;
+
+ MSN_GetAvatarFileName( AI->hContact, AI->filename, sizeof AI->filename );
+ AI->format = ( AI->hContact == NULL ) ? PA_FORMAT_PNG : PA_FORMAT_BMP;
+
+ if ( ::access( AI->filename, 0 ) == 0 ) {
+ char szSavedContext[ 256 ];
+ if ( !MSN_GetStaticString( "PictSavedContext", AI->hContact, szSavedContext, sizeof szSavedContext ))
+ if ( !strcmp( szSavedContext, szContext ))
+ return GAIR_SUCCESS;
+ }
+
+ if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL ) {
+ p2p_invite( AI->hContact, MSN_APPID_AVATAR );
+ return GAIR_WAITFOR;
+ }
+
+ return GAIR_NOAVATAR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetAwayMsg - reads the current status message for a user
+
+static void __cdecl MsnGetAwayMsgThread( HANDLE hContact )
+{
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( hContact, "CList", "StatusMsg", &dbv )) {
+ MSN_SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, ( LPARAM )dbv.pszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ else MSN_SendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE )1, ( LPARAM )0 );
+}
+
+static int MsnGetAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ MSN_StartThread( MsnGetAwayMsgThread, ccs->hContact );
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetCaps - obtain the protocol capabilities
+
+static int MsnGetCaps(WPARAM wParam,LPARAM lParam)
+{
+ switch( wParam ) {
+ case PFLAGNUM_1:
+ { int result = PF1_IM | PF1_SERVERCLIST | PF1_AUTHREQ | PF1_BASICSEARCH |
+ PF1_ADDSEARCHRES | PF1_SEARCHBYEMAIL | PF1_USERIDISEMAIL |
+ PF1_FILESEND | PF1_FILERECV | PF1_URLRECV | PF1_VISLIST;
+ if ( MyOptions.UseMSNP11 )
+ result |= PF1_MODEMSG;
+ return result;
+ }
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND |
+ PF2_ONTHEPHONE | PF2_OUTTOLUNCH | PF2_INVISIBLE;
+
+ case PFLAGNUM_3:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND |
+ PF2_ONTHEPHONE | PF2_OUTTOLUNCH;
+
+ case PFLAGNUM_4:
+ return PF4_SUPPORTTYPING | PF4_AVATARS;
+
+ case PFLAG_UNIQUEIDTEXT:
+ return ( int )MSN_Translate( "E-mail address" );
+
+ case PFLAG_UNIQUEIDSETTING:
+ return ( int )"e-mail";
+
+ case PFLAG_MAXLENOFMESSAGE:
+ return 1202;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetInfo - nothing to do, cause we cannot obtain information from the server
+
+HANDLE msnGetInfoContact = NULL;
+
+static int MsnGetInfo(WPARAM wParam,LPARAM lParam)
+{
+ if ( !msnLoggedIn )
+ return 0;
+
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ msnGetInfoContact = ccs->hContact;
+ msnNsThread->send( "PNG\r\n", 5 );
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetName - obtain the protocol name
+
+static int MsnGetName( WPARAM wParam, LPARAM lParam )
+{
+ lstrcpynA(( char* )lParam, msnProtocolName, wParam );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGetStatus - obtain the protocol status
+
+static int MsnGetStatus(WPARAM wParam,LPARAM lParam)
+{
+ return msnStatusMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnGotoInbox - goes to the Inbox folder at the Hotmail.com
+
+static int MsnGotoInbox( WPARAM, LPARAM )
+{
+ DWORD tThreadID;
+ CreateThread( NULL, 0, MsnShowMailThread, NULL, 0, &tThreadID );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnInviteCommand - invite command callback function
+
+static int MsnInviteCommand( WPARAM wParam, LPARAM lParam )
+{
+ ThreadData* tActiveThreads[ 64 ];
+ int tThreads = MSN_GetActiveThreads( tActiveThreads ), tChosenThread;
+// modified for chat
+
+
+ switch( tThreads ) {
+ case 0:
+ MessageBoxA(NULL, Translate("No active chat session is found."), Translate("MSN Chat"), MB_OK|MB_ICONINFORMATION);
+ return 0;
+
+ case 1:
+ tChosenThread = 0;
+ break;
+
+ default:
+ HMENU tMenu = ::CreatePopupMenu();
+
+ for ( int i=0; i < tThreads; i++ ) {
+ if (( long )tActiveThreads[i]->mJoinedContacts[0] < 0 ) {
+ char sessionName[ 255 ];
+ mir_snprintf( sessionName, sizeof( sessionName ), "%s%s",
+ Translate( "MSN Chat #" ), tActiveThreads[i]->mChatID );
+ ::AppendMenuA( tMenu, MF_STRING, ( UINT_PTR )( i+1 ), sessionName );
+ }
+ else ::AppendMenu( tMenu, MF_STRING, ( UINT_PTR )( i+1 ), MSN_GetContactNameT( *tActiveThreads[i]->mJoinedContacts ));
+ }
+
+ HWND tWindow = CreateWindow(_T("EDIT"),_T(""),0,1,1,1,1,NULL,NULL,hInst,NULL);
+
+ POINT pt;
+ ::GetCursorPos ( &pt );
+ tChosenThread = ::TrackPopupMenu( tMenu, TPM_NONOTIFY | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, tWindow, NULL );
+ ::DestroyMenu( tMenu );
+ ::DestroyWindow( tWindow );
+ if ( !tChosenThread )
+ return 0;
+
+ tChosenThread--;
+ }
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, tEmail, sizeof( tEmail ))) {
+ for ( int j=0; j < tActiveThreads[ tChosenThread ]->mJoinedCount; j++ ) {
+ // if the user is already in the chat session
+ if ( tActiveThreads[ tChosenThread ]->mJoinedContacts[j] == ( HANDLE )wParam ) {
+ MessageBoxA(NULL, Translate("User is already in the chat session."), Translate("MSN Chat"), MB_OK|MB_ICONINFORMATION);
+ return 0;
+ } }
+
+ tActiveThreads[ tChosenThread ]->sendPacket( "CAL", tEmail );
+
+ if ( msnHaveChatDll )
+ MSN_ChatStart(tActiveThreads[ tChosenThread ]);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnLoadIcon - obtain the protocol icon
+
+static int MsnLoadIcon(WPARAM wParam,LPARAM lParam)
+{
+ UINT id;
+
+ switch(wParam&0xFFFF) {
+ case PLI_PROTOCOL: id=IDI_MSN; break;
+ default: return (int)(HICON)NULL;
+ }
+
+ bool tIsSmall = ( wParam & PLIF_SMALL ) != 0;
+ return (int)LoadImage( hInst, MAKEINTRESOURCE(id), IMAGE_ICON,
+ GetSystemMetrics(tIsSmall ? SM_CXSMICON : SM_CXICON),
+ GetSystemMetrics(tIsSmall ? SM_CYSMICON : SM_CYICON), 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnRebuildContactMenu - gray or ungray the block menus according to contact's status
+
+static int MsnRebuildContactMenu( WPARAM wParam, LPARAM lParam )
+{
+ char szEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, szEmail, sizeof szEmail )) {
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( clmi );
+ clmi.pszName = MSN_Translate( ( Lists_IsInList( LIST_BL, szEmail ) ? "&Unblock" : "&Block" ));
+ clmi.flags = CMIM_NAME;
+ MSN_CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )msnBlockMenuItem, ( LPARAM )&clmi );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnRecvFile - creates a database event from the file request been received
+
+int MsnRecvFile( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ DBDeleteContactSetting( ccs->hContact, "CList", "Hidden" );
+
+ ThreadData* thread = MSN_GetThreadByContact( ccs->hContact );
+ if ( thread == NULL )
+ { msnNsThread->sendPacket( "XFR", "SB" );
+ return 0;
+ }
+
+ PROTORECVEVENT* pre = ( PROTORECVEVENT* )ccs->lParam;
+ char* szFile = pre->szMessage + sizeof( DWORD );
+ char* szDescr = szFile + strlen( szFile ) + 1;
+
+ DBEVENTINFO dbei;
+ memset( &dbei, 0, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = msnProtocolName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ( pre->flags & PREF_CREATEREAD ) ? DBEF_READ : 0;
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = sizeof( DWORD ) + strlen( szFile ) + strlen( szDescr ) + 2;
+ dbei.pBlob = ( PBYTE )pre->szMessage;
+ MSN_CallService( MS_DB_EVENT_ADD, ( WPARAM )ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnRecvMessage - creates a database event from the message been received
+
+static int MsnRecvMessage(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ PROTORECVEVENT* pre = ( PROTORECVEVENT* )ccs->lParam;
+
+ DBDeleteContactSetting( ccs->hContact, "CList", "Hidden" );
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = msnProtocolName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ( pre->flags & PREF_CREATEREAD ) ? DBEF_READ : 0;
+ if ( pre->flags & PREF_RTL )
+ dbei.flags |= DBEF_RTL;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen( pre->szMessage )+1;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob *= ( sizeof( wchar_t )+1 );
+
+ dbei.pBlob = ( PBYTE )pre->szMessage;
+ MSN_CallService( MS_DB_EVENT_ADD, ( WPARAM )ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendFile - initiates a file transfer
+
+static int MsnSendFile( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn )
+ return 0;
+
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ if ( MSN_GetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE )
+ return 0;
+
+ char** files = ( char** )ccs->lParam;
+ if ( files[1] != NULL ) {
+ MSN_ShowError( Translate( "MSN protocol allows only one file to be sent at a time" ));
+ return 0;
+ }
+
+ long tFileSize = 0;
+ { struct _stat statbuf;
+ if ( _stat( files[0], &statbuf ) == 0 )
+ tFileSize += statbuf.st_size;
+ }
+
+ filetransfer* sft = new filetransfer();
+ sft->std.totalFiles = 1;
+ sft->std.files = files;
+ sft->std.currentFile = strdup( files[0] );
+ sft->std.totalBytes = sft->std.currentFileSize = tFileSize;
+ sft->std.hContact = ccs->hContact;
+ sft->std.sending = 1;
+ sft->std.currentFileNumber = 0;
+
+ sft->fileId = _open( sft->std.currentFile, _O_BINARY | _O_RDONLY, _S_IREAD );
+ MSN_DebugLog( "Unable to open file '%s', error %d", sft->std.currentFile, errno );
+ if ( sft->fileId == -1 ) return NULL;
+
+ DWORD dwFlags = MSN_GetDword( ccs->hContact, "FlagBits", 0 );
+ if ( dwFlags & 0x70000000 )
+ p2p_invite( ccs->hContact, MSN_APPID_FILE, sft );
+ else {
+ ThreadData* thread = MSN_GetThreadByContact( ccs->hContact );
+ if ( thread != NULL ) {
+ thread->mMsnFtp = sft;
+ sft->mThreadId = thread->mUniqueID;
+ }
+ else msnNsThread->sendPacket( "XFR", "SB" );
+
+ char* pszFiles = strrchr( *files, '\\' ), msg[ 1024 ];
+ if ( pszFiles )
+ pszFiles++;
+ else
+ pszFiles = *files;
+
+ mir_snprintf( msg, sizeof( msg ),
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Application-Name: File Transfer\r\n"
+ "Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n"
+ "Invitation-Command: INVITE\r\n"
+ "Invitation-Cookie: %i\r\n"
+ "Application-File: %s\r\n"
+ "Application-FileSize: %i\r\n\r\n",
+ ( WORD )(((double)rand()/(double)RAND_MAX)*4294967295), UTF8(pszFiles), tFileSize );
+
+ if ( thread == NULL )
+ MsgQueue_Add( ccs->hContact, 'S', msg, -1, sft );
+ else
+ thread->sendMessage( 'S', msg, MSG_DISABLE_HDR );
+ }
+
+ MSN_SendBroadcast( ccs->hContact, ACKTYPE_FILE, ACKRESULT_SENTREQUEST, sft, 0 );
+ return (int)(HANDLE)sft;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendMessage - sends the message to a server
+
+struct TFakeAckParams
+{
+ inline TFakeAckParams( HANDLE p1, HANDLE p2, LONG p3, LPCSTR p4 ) :
+ hEvent( p1 ),
+ hContact( p2 ),
+ id( p3 ),
+ msg( p4 )
+ {}
+
+ HANDLE hEvent;
+ HANDLE hContact;
+ LONG id;
+ LPCSTR msg;
+};
+
+static DWORD CALLBACK sttFakeAck( LPVOID param )
+{
+ TFakeAckParams* tParam = ( TFakeAckParams* )param;
+ WaitForSingleObject( tParam->hEvent, INFINITE );
+
+ Sleep( 100 );
+ if ( tParam->msg == NULL )
+ MSN_SendBroadcast( tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )tParam->id, 0 );
+ else
+ MSN_SendBroadcast( tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE )tParam->id, LPARAM( tParam->msg ));
+
+ CloseHandle( tParam->hEvent );
+ delete tParam;
+ return 0;
+}
+
+static int MsnSendMessage( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ char *msg, *errMsg = NULL;
+
+ if ( ccs->wParam & PREF_UNICODE ) {
+ char* p = ( char* )ccs->lParam;
+ msg = Utf8EncodeUcs2(( wchar_t* )&p[ strlen(p)+1 ] );
+ }
+ else msg = Utf8Encode(( char* )ccs->lParam );
+
+ if ( strlen( msg ) > 1202 ) {
+ errMsg = MSN_Translate( "Message is too long: MSN messages are limited by 1202 UTF8 chars" );
+LBL_Error:
+ free( msg );
+
+ HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ DWORD dwThreadId;
+ CloseHandle( CreateThread( NULL, 0, sttFakeAck, new TFakeAckParams( hEvent, ccs->hContact, 999999, errMsg ), 0, &dwThreadId ));
+ SetEvent( hEvent );
+ return 999999;
+ }
+
+ int seq, msgType = ( MyOptions.SlowSend ) ? 'A' : 'N';
+ int rtlFlag = ( ccs->wParam & PREF_RTL ) ? MSG_RTL : 0;
+ ThreadData* thread = MSN_GetThreadByContact( ccs->hContact );
+ if ( thread == NULL )
+ {
+ WORD wStatus = MSN_GetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE );
+ if ( wStatus == ID_STATUS_OFFLINE || msnStatusMode == ID_STATUS_INVISIBLE ) {
+ errMsg = MSN_Translate( "MSN protocol does not support offline messages" );
+ goto LBL_Error;
+ }
+
+ if ( MsgQueue_CheckContact( ccs->hContact ) == NULL )
+ msnNsThread->sendPacket( "XFR", "SB" );
+
+ seq = MsgQueue_Add( ccs->hContact, msgType, msg, 0, 0, rtlFlag );
+ }
+ else
+ { if ( thread->mJoinedCount == 0 )
+ seq = MsgQueue_Add( ccs->hContact, msgType, msg, 0, 0, rtlFlag );
+ else {
+ seq = thread->sendMessage( msgType, msg, rtlFlag );
+
+ if ( seq == -1 ) {
+ seq = MsgQueue_Add( ccs->hContact, msgType, msg, 0, 0, rtlFlag );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ else if ( !MyOptions.SlowSend ) {
+ HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ DWORD dwThreadId;
+ CloseHandle( CreateThread( NULL, 0, sttFakeAck, new TFakeAckParams( hEvent, ccs->hContact, seq, 0 ), 0, &dwThreadId ));
+ SetEvent( hEvent );
+ } } }
+
+ free( msg );
+ return seq;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendNudge - Sending a nudge
+
+static int MsnSendNudge( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn ) return 0;
+
+ HANDLE hContact = ( HANDLE )wParam;
+ char msg[ 1024 ];
+
+ mir_snprintf( msg, sizeof( msg ),"N 69\r\nMIME-Version: 1.0\r\n"
+ "Content-Type: text/x-msnmsgr-datacast\r\n\r\n"
+ "ID: 1\r\n\r\n");
+
+ ThreadData* thread = MSN_GetThreadByContact( hContact );
+
+ if ( thread == NULL ) {
+ if ( MsgQueue_CheckContact( hContact ) == NULL )
+ {
+ MsgQueue_Add( hContact, 'N', msg, -1 );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ }
+ else
+ thread->sendPacket( "MSG",msg);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSendNetMeeting - Netmeeting callback function
+
+static int MsnSendNetMeeting( WPARAM wParam, LPARAM lParam )
+{
+ if ( !msnLoggedIn ) return 0;
+
+ ThreadData* thread = MSN_GetThreadByContact( HANDLE(wParam) );
+
+ if ( thread == NULL ) {
+ MessageBoxA( NULL, MSN_Translate( "You must be talking to start Netmeeting" ), "MSN Protocol", MB_OK | MB_ICONERROR );
+ return 0;
+ }
+
+ char msg[ 1024 ];
+
+ mir_snprintf( msg, sizeof( msg ),
+ "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n\r\n"
+ "Application-Name: NetMeeting\r\n"
+ "Application-GUID: {44BBA842-CC51-11CF-AAFA-00AA00B6015C}\r\n"
+ "Session-Protocol: SM1\r\n"
+ "Invitation-Command: INVITE\r\n"
+ "Invitation-Cookie: %i\r\n"
+ "Session-ID: {1A879604-D1B8-11D7-9066-0003FF431510}\r\n\r\n",
+ ( WORD )(((double)rand()/(double)RAND_MAX)*4294967295));
+
+ thread->sendMessage( 'N', msg, MSG_DISABLE_HDR );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetApparentMode - controls contact visibility
+
+static int MsnSetApparentMode( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ if ( ccs->wParam && ccs->wParam != ID_STATUS_OFFLINE )
+ return 1;
+
+ WORD oldMode = MSN_GetWord( ccs->hContact, "ApparentMode", 0 );
+ if ( ccs->wParam != oldMode )
+ MSN_SetWord( ccs->hContact, "ApparentMode", ( WORD )ccs->wParam );
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetAvatar - sets an avatar without UI
+
+static int MsnSetAvatar( WPARAM wParam, LPARAM lParam )
+{
+ HBITMAP hBitmap = ( HBITMAP )MSN_CallService( MS_UTILS_LOADBITMAP, 0, lParam );
+ if ( hBitmap == NULL )
+ return 1;
+
+ if (( hBitmap = MSN_StretchBitmap( hBitmap )) == NULL )
+ return 2;
+
+ MSN_SaveBitmapAsAvatar( hBitmap, (char *) lParam );
+ DeleteObject( hBitmap );
+ if ( msnLoggedIn )
+ MSN_SetServerStatus( msnStatusMode );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetAvatar - sets an avatar without UI
+
+static int MsnSetAvatarUI( WPARAM wParam, LPARAM lParam )
+{
+ char szFileName[ MAX_PATH ];
+ if ( MSN_EnterBitmapFileName( szFileName ) != ERROR_SUCCESS )
+ return 1;
+
+ return MsnSetAvatar( 0, ( LPARAM )szFileName );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetAwayMsg - sets the current status message for a user
+
+static int MsnSetAwayMsg(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+
+ for ( i=0; i < MSN_NUM_MODES; i++ )
+ if ( msnModeMsgs[i].m_mode == (int)wParam )
+ break;
+
+ if ( i == MSN_NUM_MODES )
+ return 1;
+
+ replaceStr( msnModeMsgs[i].m_msg, ( char* )lParam );
+
+ if ( (int)wParam == msnDesiredStatus )
+ MSN_SendStatusMessage(( char* )lParam );
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// SetNickname - sets a nick name without UI
+
+static int MsnSetNickName( WPARAM wParam, LPARAM lParam )
+{
+ MSN_SendNickname(( char* )lParam );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// SetNicknameCommand - sets nick name
+
+static BOOL CALLBACK DlgProcSetNickname(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg )
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSN )));
+ SendMessage( GetDlgItem( hwndDlg, IDC_NICKNAME ), EM_LIMITTEXT, 129, 0 );
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingTString( NULL, msnProtocolName, "Nick", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_NICKNAME, dbv.ptszVal );
+ MSN_FreeVariant( &dbv );
+ }
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(wParam)
+ {
+ case IDOK:
+ if ( msnLoggedIn ) {
+ TCHAR str[ 130 ];
+ GetDlgItemText( hwndDlg, IDC_NICKNAME, str, SIZEOF( str ));
+ MSN_SendNicknameT( str );
+ }
+
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ return FALSE;
+}
+
+static int SetNicknameUI( WPARAM wParam, LPARAM lParam )
+{
+ HWND hwndSetNickname = CreateDialog(hInst, MAKEINTRESOURCE( IDD_SETNICKNAME ), NULL, DlgProcSetNickname );
+
+ SetForegroundWindow( hwndSetNickname );
+ SetFocus( hwndSetNickname );
+ ShowWindow( hwndSetNickname, SW_SHOW );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnSetStatus - set the plugin's connection status
+
+static int MsnSetStatus( WPARAM wParam, LPARAM lParam )
+{
+ msnDesiredStatus = wParam;
+ MSN_DebugLog( "PS_SETSTATUS(%d,0)", wParam );
+
+ if ( msnDesiredStatus == ID_STATUS_OFFLINE )
+ {
+ MSN_GoOffline();
+ }
+ else if (!msnLoggedIn && !(msnStatusMode>=ID_STATUS_CONNECTING && msnStatusMode<ID_STATUS_CONNECTING+MAX_CONNECT_RETRIES))
+ {
+ ThreadData* newThread = new ThreadData;
+
+ WORD tServerPort = MSN_GetWord( NULL, "MSNMPort", 1863 );
+
+ char tServer[ sizeof( newThread->mServer ) ];
+ if ( MSN_GetStaticString( "LoginServer", NULL, tServer, sizeof( tServer )))
+ strcpy( tServer, MSN_DEFAULT_LOGIN_SERVER );
+
+ mir_snprintf( newThread->mServer, sizeof( newThread->mServer ), "%s:%i", tServer, tServerPort );
+ newThread->mServer[ sizeof(newThread->mServer)-1 ] = 0;
+
+ newThread->mType = SERVER_DISPATCH;
+ newThread->mIsMainThread = true;
+ { int oldMode = msnStatusMode;
+ msnStatusMode = ID_STATUS_CONNECTING;
+ MSN_SendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE )oldMode, msnStatusMode );
+ }
+ newThread->startThread(( pThreadFunc )MSNServerThread );
+ }
+ else MSN_SetServerStatus( msnDesiredStatus );
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnUserIsTyping - notify another contact that we're typing a message
+
+extern char sttHeaderStart[];
+
+static int MsnUserIsTyping(WPARAM wParam, LPARAM lParam)
+{
+ if ( !msnLoggedIn || lParam == PROTOTYPE_SELFTYPING_OFF )
+ return 0;
+
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ if ( MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof tEmail ))
+ return 0;
+
+ HANDLE hContact = ( HANDLE )wParam;
+ WORD wStatus = MSN_GetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ if ( wStatus == ID_STATUS_OFFLINE || msnStatusMode == ID_STATUS_INVISIBLE )
+ return 0;
+
+ char tCommand[ 1024 ];
+ mir_snprintf( tCommand, sizeof( tCommand ),
+ "Content-Type: text/x-msmsgscontrol\r\n"
+ "TypingUser: %s\r\n\r\n\r\n", tEmail );
+
+ ThreadData* T = MSN_GetThreadByContact( hContact );
+ if ( T == NULL ) {
+ if ( MsgQueue_CheckContact( hContact ) == NULL ) {
+ MsgQueue_Add( hContact, 'U', tCommand, -1 );
+ msnNsThread->sendPacket( "XFR", "SB" );
+ }
+ }
+ else T->sendMessage( 'U', tCommand, MSG_DISABLE_HDR );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnViewProfile - view a contact's profile at http://members.msn.com
+
+static char sttUrlPrefix[] = "http://members.msn.com/";
+
+static int MsnViewProfile( WPARAM wParam, LPARAM lParam )
+{
+ char tUrl[ MSN_MAX_EMAIL_LEN + sizeof sttUrlPrefix ];
+ strcpy( tUrl, sttUrlPrefix );
+
+ if ( !MSN_GetStaticString( "e-mail", ( HANDLE )wParam, tUrl + sizeof sttUrlPrefix - 1, MSN_MAX_EMAIL_LEN ))
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )tUrl );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnViewServiceStatus - display MSN services status
+
+static int MsnViewServiceStatus( WPARAM wParam, LPARAM lParam )
+{
+ MSN_CallService( MS_UTILS_OPENURL, 1, ( LPARAM )"http://messenger.msn.com/Status.aspx" );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Services initialization and destruction
+
+static HANDLE hHookSettingChanged = NULL;
+static HANDLE hHookContactDeleted = NULL;
+static HANDLE hHookRebuildCMenu = NULL;
+
+int LoadMsnServices( void )
+{
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Main menu initialization
+
+ char servicefunction[ 100 ];
+ strcpy( servicefunction, msnProtocolName );
+ char* tDest = servicefunction + strlen( servicefunction );
+ CLISTMENUITEM mi;
+
+ if ( !MSN_GetByte( "DisableSetNickname", 0 ))
+ {
+ strcpy( tDest, MS_SET_NICKNAME_UI );
+ CreateServiceFunction( servicefunction, SetNicknameUI );
+
+ memset( &mi, 0, sizeof( mi ));
+ mi.popupPosition = 500085000;
+ mi.pszPopupName = msnProtocolName;
+ mi.cbSize = sizeof( mi );
+ mi.position = 2000060000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSN ));
+ mi.pszName = MSN_Translate( "Set &Nickname" );
+ mi.pszService = servicefunction;
+ msnMenuItems[ 0 ] = ( HANDLE )MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_GOTO_INBOX );
+ CreateServiceFunction( servicefunction, MsnGotoInbox );
+
+ mi.position = 2000060001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_INBOX ));
+ mi.pszName = MSN_Translate( "Display Hotmail &Inbox" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_EDIT_PROFILE );
+ CreateServiceFunction( servicefunction, MsnEditProfile );
+
+ mi.position = 2000060002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_PROFILE ));
+ mi.pszName = MSN_Translate( "Edit MSN &Profile" );
+ mi.pszService = servicefunction;
+ msnMenuItems[ 1 ] = ( HANDLE )MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_VIEW_STATUS );
+ CreateServiceFunction( servicefunction, MsnViewServiceStatus );
+
+ mi.position = 2000060003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_SERVICES ));
+ mi.pszName = MSN_Translate( "View MSN Services &Status" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+
+ strcpy( tDest, MS_SET_AVATAR_UI );
+ CreateServiceFunction( servicefunction, MsnSetAvatarUI );
+
+ mi.position = 2000060004;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_AVATAR ));
+ mi.pszName = MSN_Translate( "Set &Avatar" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi );
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Contact menu initialization
+
+ strcpy( tDest, MSN_BLOCK );
+ CreateServiceFunction( servicefunction, MsnBlockCommand );
+
+ memset( &mi, 0, sizeof( mi ));
+ mi.cbSize = sizeof( mi );
+ mi.position = -500050000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_MSNBLOCK ));
+ mi.pszContactOwner = msnProtocolName;
+ mi.pszName = MSN_Translate( "&Block" );
+ mi.pszService = servicefunction;
+ msnBlockMenuItem = ( HANDLE )MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ strcpy( tDest, MSN_INVITE );
+ CreateServiceFunction( servicefunction, MsnInviteCommand );
+
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.position = -500050001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_INVITE ));
+ mi.pszName = MSN_Translate( "&Invite to chat" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ strcpy( tDest, MSN_NETMEETING );
+ CreateServiceFunction( servicefunction, MsnSendNetMeeting );
+
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.position = -500050002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_NETMEETING ));
+ mi.pszName = MSN_Translate( "&Start Netmeeting" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ strcpy( tDest, MSN_VIEW_PROFILE );
+ CreateServiceFunction( servicefunction, MsnViewProfile );
+
+ mi.flags = 0;
+ mi.position = -500050003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_PROFILE ));
+ mi.pszName = MSN_Translate( "&View Profile" );
+ mi.pszService = servicefunction;
+ MSN_CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ MSN_EnableMenuItems( FALSE );
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Service creation
+
+ hHookContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, MsnContactDeleted );
+ hHookSettingChanged = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, MsnDbSettingChanged );
+ hHookRebuildCMenu = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, MsnRebuildContactMenu );
+
+ MSN_CreateProtoServiceFunction( PS_ADDTOLIST, MsnAddToList );
+ MSN_CreateProtoServiceFunction( PS_ADDTOLISTBYEVENT, MsnAddToListByEvent );
+ MSN_CreateProtoServiceFunction( PS_AUTHALLOW, MsnAuthAllow );
+ MSN_CreateProtoServiceFunction( PS_AUTHDENY, MsnAuthDeny );
+ MSN_CreateProtoServiceFunction( PS_BASICSEARCH, MsnBasicSearch );
+ MSN_CreateProtoServiceFunction( PS_FILERESUME, MsnFileResume );
+ MSN_CreateProtoServiceFunction( PS_GETAVATARINFO, MsnGetAvatarInfo );
+ MSN_CreateProtoServiceFunction( PS_GETCAPS, MsnGetCaps );
+ MSN_CreateProtoServiceFunction( PS_GETNAME, MsnGetName );
+ MSN_CreateProtoServiceFunction( PS_GETSTATUS, MsnGetStatus );
+ MSN_CreateProtoServiceFunction( PS_LOADICON, MsnLoadIcon );
+ MSN_CreateProtoServiceFunction( PS_SEARCHBYEMAIL, MsnBasicSearch );
+ MSN_CreateProtoServiceFunction( PS_SETSTATUS, MsnSetStatus );
+
+ MSN_CreateProtoServiceFunction( PSR_FILE, MsnRecvFile );
+ MSN_CreateProtoServiceFunction( PSR_MESSAGE, MsnRecvMessage );
+
+ MSN_CreateProtoServiceFunction( PSS_FILE, MsnSendFile );
+ MSN_CreateProtoServiceFunction( PSS_FILEALLOW, MsnFileAllow );
+ MSN_CreateProtoServiceFunction( PSS_FILECANCEL, MsnFileCancel );
+ MSN_CreateProtoServiceFunction( PSS_FILEDENY, MsnFileDeny );
+ MSN_CreateProtoServiceFunction( PSS_GETINFO, MsnGetInfo );
+ MSN_CreateProtoServiceFunction( PSS_MESSAGE, MsnSendMessage );
+ MSN_CreateProtoServiceFunction( PSS_SETAPPARENTMODE, MsnSetApparentMode );
+ MSN_CreateProtoServiceFunction( PSS_USERISTYPING, MsnUserIsTyping );
+
+ if ( MyOptions.UseMSNP11 ) {
+ MSN_CreateProtoServiceFunction( PSS_GETAWAYMSG, MsnGetAwayMsg );
+ MSN_CreateProtoServiceFunction( PS_SETAWAYMSG, MsnSetAwayMsg );
+ }
+
+ MSN_CreateProtoServiceFunction( MSN_SET_AVATAR, MsnSetAvatar );
+ MSN_CreateProtoServiceFunction( MSN_SET_NICKNAME, MsnSetNickName );
+ MSN_CreateProtoServiceFunction( MSN_SEND_NUDGE, MsnSendNudge );
+ return 0;
+}
+
+void UnloadMsnServices( void )
+{
+ if ( hHookSettingChanged )
+ UnhookEvent( hHookSettingChanged );
+
+ if ( hHookContactDeleted )
+ UnhookEvent( hHookContactDeleted );
+
+ if ( hHookRebuildCMenu )
+ UnhookEvent( hHookRebuildCMenu );
+}
diff --git a/miranda-wine/protocols/MSN/msn_switchboard.cpp b/miranda-wine/protocols/MSN/msn_switchboard.cpp
new file mode 100644
index 0000000..4e96339
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_switchboard.cpp
@@ -0,0 +1,53 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+int __stdcall MSN_ContactJoined( ThreadData* parInfo, HANDLE hContact )
+{
+ for ( int i=0; i < parInfo->mJoinedCount; i++ )
+ if ( parInfo->mJoinedContacts[i] == hContact )
+ return i+1;
+
+ int ret = ++parInfo->mJoinedCount;
+ parInfo->mJoinedContacts = ( HANDLE* )realloc( parInfo->mJoinedContacts, sizeof( HANDLE )*ret );
+ parInfo->mJoinedContacts[ ret-1 ] = hContact;
+ return ret;
+}
+
+int __stdcall MSN_ContactLeft( ThreadData* parInfo, HANDLE hContact )
+{
+ int i;
+
+ for ( i=0; i < parInfo->mJoinedCount; i++ )
+ if ( parInfo->mJoinedContacts[ i ] == hContact )
+ break;
+
+ if ( i == parInfo->mJoinedCount )
+ return i;
+
+ int ret = --parInfo->mJoinedCount;
+ memmove( parInfo->mJoinedContacts + i, parInfo->mJoinedContacts+i+1, sizeof( HANDLE )*( ret-i ));
+ parInfo->mJoinedContacts = ( HANDLE* )realloc( parInfo->mJoinedContacts, sizeof( HANDLE )*ret );
+ return ret;
+}
diff --git a/miranda-wine/protocols/MSN/msn_threads.cpp b/miranda-wine/protocols/MSN/msn_threads.cpp
new file mode 100644
index 0000000..7ce9ad2
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_threads.cpp
@@ -0,0 +1,723 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <direct.h>
+
+int MSN_HandleCommands(ThreadData *info,char *cmdString);
+int MSN_HandleErrors(ThreadData *info,char *cmdString);
+int MSN_HandleMSNFTP( ThreadData *info, char *cmdString );
+
+extern LONG (WINAPI *MyInterlockedIncrement)(PLONG pVal);
+extern unsigned long sl;
+
+HANDLE hKeepAliveThreadEvt = NULL;
+
+bool DoingNudge = false;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Keep-alive thread for the main connection
+
+int msnPingTimeout = 45, msnPingTimeoutCurrent = 45;
+
+void __cdecl msn_keepAliveThread( void* )
+{
+ msnPingTimeout = msnPingTimeoutCurrent;
+
+ while( TRUE )
+ {
+ while ( --msnPingTimeout > 0 ) {
+ if ( ::WaitForSingleObject( hKeepAliveThreadEvt, 1000 ) != WAIT_TIMEOUT ) {
+ ::CloseHandle( hKeepAliveThreadEvt ); hKeepAliveThreadEvt = NULL;
+ MSN_DebugLog( "Closing keep-alive thread" );
+ return;
+ } }
+
+ msnPingTimeout = msnPingTimeoutCurrent = 45;
+
+ /*
+ * if proxy is not used, every connection uses select() to send PNG
+ */
+
+ if ( msnLoggedIn && !MyOptions.UseGateway )
+ if ( MSN_GetByte( "KeepAlive", 0 ))
+ msnNsThread->send( "PNG\r\n", 5 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN redirector detection thread - refreshes the information about the redirector
+
+static bool sttRedirectorWasChecked = false;
+
+void __cdecl msn_RedirectorThread( ThreadData* info )
+{
+ extern int MSN_CheckRedirector();
+ MSN_CheckRedirector();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN server thread - read and process commands from a server
+
+void __cdecl MSNServerThread( ThreadData* info )
+{
+ if ( !sttRedirectorWasChecked ) {
+ sttRedirectorWasChecked = true;
+ MSN_StartThread(( pThreadFunc )msn_RedirectorThread, NULL );
+ }
+
+ NETLIBOPENCONNECTION tConn = { 0 };
+ tConn.cbSize = sizeof( tConn );
+ tConn.flags = NLOCF_V2;
+
+ char* tPortDelim = strrchr( info->mServer, ':' );
+ if ( tPortDelim != NULL )
+ *tPortDelim = '\0';
+
+ if ( MyOptions.UseGateway && !MyOptions.UseProxy ) {
+ tConn.szHost = MSN_DEFAULT_GATEWAY;
+ tConn.wPort = 80;
+ }
+ else {
+ tConn.szHost = info->mServer;
+ tConn.wPort = MSN_DEFAULT_PORT;
+
+ if ( tPortDelim != NULL ) {
+ int tPortNumber;
+ if ( sscanf( tPortDelim+1, "%d", &tPortNumber ) == 1 )
+ tConn.wPort = ( WORD )tPortNumber;
+ } }
+
+ MSN_DebugLog( "Thread started: server='%s', type=%d", tConn.szHost, info->mType );
+
+ info->s = ( HANDLE )MSN_CallService( MS_NETLIB_OPENCONNECTION, ( WPARAM )hNetlibUser, ( LPARAM )&tConn );
+ if ( info->s == NULL ) {
+ MSN_DebugLog( "Connection Failed (%d)", WSAGetLastError() );
+
+ switch ( info->mType ) {
+ case SERVER_NOTIFICATION:
+ case SERVER_DISPATCH:
+ MSN_SendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NOSERVER );
+ MSN_GoOffline();
+ break;
+ }
+
+ return;
+ }
+
+ if ( MyOptions.UseGateway )
+ MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( info->s ), 2 );
+
+ MSN_DebugLog( "Connected with handle=%08X", info->s );
+
+ if ( info->mType == SERVER_DISPATCH || info->mType == SERVER_NOTIFICATION ) {
+ if ( MyOptions.UseMSNP11 )
+ info->sendPacket( "VER", "MSNP11 MSNP10 CVR0" );
+ else
+ info->sendPacket( "VER", "MSNP10 MSNP9 CVR0" );
+ }
+ else if ( info->mType == SERVER_SWITCHBOARD ) {
+ char tEmail[ MSN_MAX_EMAIL_LEN ];
+ MSN_GetStaticString( "e-mail", NULL, tEmail, sizeof( tEmail ));
+ info->sendPacket( info->mCaller ? "USR" : "ANS", "%s %s", tEmail, info->mCookie );
+ }
+ else if ( info->mType == SERVER_FILETRANS && info->mCaller == 0 ) {
+ info->send( "VER MSNFTP\r\n", 12 );
+ }
+
+ if ( info->mIsMainThread ) {
+ MSN_EnableMenuItems( TRUE );
+
+ sl = time(NULL); //for hotmail
+
+ msnPingTimeout = msnPingTimeoutCurrent;
+
+ msnNsThread = info;
+ if (hKeepAliveThreadEvt == NULL) {
+ hKeepAliveThreadEvt = ::CreateEvent( NULL, TRUE, FALSE, NULL );
+ MSN_StartThread(( pThreadFunc )msn_keepAliveThread, NULL );
+ } }
+
+ MSN_DebugLog( "Entering main recv loop" );
+ info->mBytesInData = 0;
+ while ( TRUE ) {
+ int handlerResult;
+
+ int recvResult = info->recv( info->mData + info->mBytesInData, sizeof( info->mData ) - info->mBytesInData );
+ if ( recvResult == SOCKET_ERROR ) {
+ MSN_DebugLog( "Connection %08p [%d] was abortively closed", info->s, GetCurrentThreadId());
+ break;
+ }
+
+ if ( !recvResult ) {
+ MSN_DebugLog( "Connection %08p [%d] was gracefully closed", info->s, GetCurrentThreadId());
+ break;
+ }
+
+ info->mBytesInData += recvResult;
+
+ if ( info->mCaller == 1 && info->mType == SERVER_FILETRANS ) {
+ handlerResult = MSN_HandleMSNFTP( info, info->mData );
+ if ( handlerResult )
+ break;
+ }
+ else {
+ while( TRUE ) {
+ char* peol = strchr(info->mData,'\r');
+ if ( peol == NULL )
+ break;
+
+ if ( info->mBytesInData < peol-info->mData+2 )
+ break; //wait for full line end
+
+ char msg[ sizeof(info->mData) ];
+ memcpy( msg, info->mData, peol-info->mData ); msg[ peol-info->mData ] = 0;
+
+ if ( *++peol != '\n' )
+ MSN_DebugLog( "Dodgy line ending to command: ignoring" );
+ else
+ peol++;
+
+ info->mBytesInData -= peol - info->mData;
+ memmove( info->mData, peol, info->mBytesInData );
+ MSN_DebugLog( "RECV:%s", msg );
+
+ if ( !isalnum( msg[0] ) || !isalnum(msg[1]) || !isalnum(msg[2]) || (msg[3] && msg[3]!=' ')) {
+ MSN_DebugLog( "Invalid command name" );
+ continue;
+ }
+
+ if ( info->mType != SERVER_FILETRANS ) {
+ if ( isdigit(msg[0]) && isdigit(msg[1]) && isdigit(msg[2])) //all error messages
+ handlerResult = MSN_HandleErrors( info, msg );
+ else
+ handlerResult = MSN_HandleCommands( info, msg );
+ }
+ else handlerResult = MSN_HandleMSNFTP( info, msg );
+
+ if ( handlerResult )
+ goto LBL_Exit;
+ } }
+
+ if ( info->mBytesInData == sizeof( info->mData )) {
+ MSN_DebugLog( "sizeof(data) is too small: the longest line won't fit" );
+ break;
+ } }
+
+LBL_Exit:
+ if ( info->mIsMainThread ) {
+ MSN_GoOffline();
+ msnNsThread = NULL;
+ if ( hKeepAliveThreadEvt )
+ SetEvent( hKeepAliveThreadEvt );
+ }
+ else if ( info->mType == SERVER_SWITCHBOARD ) {
+ if ( info->mJoinedContacts != NULL )
+ free( info->mJoinedContacts );
+ }
+
+ MSN_DebugLog( "Thread [%d] ending now", GetCurrentThreadId() );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Added by George B. Hazan (ghazan@postman.ru)
+// The following code is required to abortively stop all started threads upon exit
+
+static ThreadData* sttThreads[ MAX_THREAD_COUNT ]; // up to MAX_THREAD_COUNT threads
+static CRITICAL_SECTION sttLock;
+
+void __stdcall MSN_InitThreads()
+{
+ memset( sttThreads, 0, sizeof( sttThreads ));
+ InitializeCriticalSection( &sttLock );
+}
+
+void __stdcall MSN_CloseConnections()
+{
+ int i;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( i=0; i < MAX_THREAD_COUNT; i++ ) {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ switch (T->mType) {
+ case SERVER_DISPATCH :
+ case SERVER_NOTIFICATION :
+ case SERVER_SWITCHBOARD :
+ if (T->s != NULL)
+ T->sendPacket( "OUT", NULL );
+ break;
+
+ case SERVER_P2P_DIRECT :
+ if (p2p_sessionRegistered(T->mP2pSession)) {
+ filetransfer *ft = T->mP2pSession;
+ if ( ft->hWaitEvent != INVALID_HANDLE_VALUE )
+ SetEvent( ft->hWaitEvent );
+
+ if ( ft->p2p_appID != 0 )
+ p2p_sendCancel( T, ft );
+
+ ft->std.files = NULL;
+ ft->std.totalFiles = 0;
+ }
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+void __stdcall MSN_CloseThreads()
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ ) {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL || T->s == NULL )
+ continue;
+
+ SOCKET s = MSN_CallService( MS_NETLIB_GETSOCKET, LPARAM( T->s ), 0 );
+ if ( s != INVALID_SOCKET )
+ shutdown( s, 2 );
+ }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+void Threads_Uninit( void )
+{
+ DeleteCriticalSection( &sttLock );
+}
+
+ThreadData* __stdcall MSN_GetThreadByContact( HANDLE hContact )
+{
+ EnterCriticalSection( &sttLock );
+
+ ThreadData* T = NULL;
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mJoinedCount == 0 || T->mJoinedContacts == NULL || T->s == NULL )
+ continue;
+
+ if ( T->mJoinedContacts[0] == hContact )
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return T;
+}
+
+ThreadData* __stdcall MSN_GetOtherContactThread( ThreadData* thread )
+{
+ EnterCriticalSection( &sttLock );
+
+ ThreadData* T = NULL;
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mJoinedCount == 0 || T->mJoinedContacts == NULL || T->s == NULL )
+ continue;
+
+ if ( T != thread && T->mJoinedContacts[0] == thread->mJoinedContacts[0] )
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return T;
+}
+
+ThreadData* __stdcall MSN_GetUnconnectedThread( HANDLE hContact )
+{
+ EnterCriticalSection( &sttLock );
+
+ ThreadData* T = NULL;
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mInitialContact == hContact )
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return T;
+}
+
+int __stdcall MSN_GetActiveThreads( ThreadData** parResult )
+{
+ int tCount = 0;
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mType == SERVER_SWITCHBOARD && T->mJoinedCount != 0 && T->mJoinedContacts != NULL )
+ parResult[ tCount++ ] = T;
+ }
+
+ LeaveCriticalSection( &sttLock );
+ return tCount;
+}
+
+ThreadData* __stdcall MSN_GetThreadByConnection( HANDLE s )
+{
+ ThreadData* tResult = NULL;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->s == s )
+ { tResult = T;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+ return tResult;
+}
+
+ThreadData* __stdcall MSN_GetThreadByID( LONG id )
+{
+ ThreadData* tResult = NULL;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T != NULL && T->mUniqueID == id )
+ { tResult = T;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+ return tResult;
+}
+
+ThreadData* __stdcall MSN_GetThreadByPort( WORD wPort )
+{
+ ThreadData* tResult = NULL;
+
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ ThreadData* T = sttThreads[ i ];
+ if ( T == NULL )
+ continue;
+
+ if ( T->mP2pSession != NULL && T->mP2pSession->mIncomingPort == wPort ) {
+ tResult = T;
+ break;
+ }
+
+ if ( T->mMsnFtp != NULL && T->mMsnFtp->mIncomingPort == wPort ) {
+ tResult = T;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+ return tResult;
+}
+
+void __stdcall MSN_PingParentThread( ThreadData* parentThread, filetransfer* ft )
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ {
+ if ( sttThreads[ i ] == parentThread ) {
+ parentThread->mP2pSession = ft;
+ ft->p2p_sendmsgid = ++ft->p2p_msgid;
+ parentThread->mP2PInitTrid = p2p_sendPortion( ft, parentThread );
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// class ThreadData members
+
+static LONG sttThreadID = 1;
+
+ThreadData::ThreadData()
+{
+ memset( this, 0, sizeof ThreadData );
+ mUniqueID = MyInterlockedIncrement( &sttThreadID );
+ mGatewayTimeout = 2;
+ mWaitPeriod = 60;
+ mIsMainThread = false;
+}
+
+ThreadData::~ThreadData()
+{
+ if ( s != NULL ) {
+ MSN_DebugLog( "Closing connection handle %08X", s );
+ Netlib_CloseHandle( s );
+ }
+
+ if ( mMsnFtp != NULL ) {
+ delete mMsnFtp;
+ mMsnFtp = NULL;
+ }
+
+ if ( mUniqueID )
+ p2p_unregisterThreadSession( mUniqueID );
+
+ while (mFirstQueueItem != NULL)
+ {
+ TQueueItem* QI = mFirstQueueItem;
+ mFirstQueueItem = mFirstQueueItem->next;
+ free(QI);
+} }
+
+void ThreadData::applyGatewayData( HANDLE hConn, bool isPoll )
+{
+ char szHttpPostUrl[300];
+ getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), isPoll );
+
+ MSN_DebugLog( "applying '%s' to %08X [%d]", szHttpPostUrl, this, GetCurrentThreadId() );
+
+ NETLIBHTTPPROXYINFO nlhpi = {0};
+ nlhpi.cbSize = sizeof(nlhpi);
+ nlhpi.flags = NLHPIF_HTTP11;
+ nlhpi.szHttpGetUrl = NULL;
+ nlhpi.szHttpPostUrl = szHttpPostUrl;
+ nlhpi.firstPostSequence = 1;
+ MSN_CallService( MS_NETLIB_SETHTTPPROXYINFO, (WPARAM)hConn, (LPARAM)&nlhpi);
+}
+
+static char sttFormatString[] = "http://gateway.messenger.hotmail.com/gateway/gateway.dll?Action=open&Server=%s&IP=%s";
+
+void ThreadData::getGatewayUrl( char* dest, int destlen, bool isPoll )
+{
+ if ( mSessionID[0] == 0 ) {
+ if ( mType == SERVER_NOTIFICATION || mType == SERVER_DISPATCH )
+ mir_snprintf( dest, destlen, sttFormatString, "NS", "messenger.hotmail.com" );
+ else
+ mir_snprintf( dest, destlen, sttFormatString, "SB", mServer );
+ strcpy( mGatewayIP, MSN_DEFAULT_GATEWAY );
+ }
+ else mir_snprintf( dest, destlen, "http://%s/gateway/gateway.dll?%sSessionID=%s",
+ mGatewayIP, ( isPoll ) ? "Action=poll&" : "", mSessionID );
+}
+
+void ThreadData::processSessionData( const char* str )
+{
+ char tSessionID[40], tGateIP[ 40 ];
+
+ char* tDelim = ( char* )strchr( str, ';' );
+ if ( tDelim == NULL )
+ return;
+
+ *tDelim = 0; tDelim += 2;
+
+ if ( !sscanf( str, "SessionID=%s", tSessionID ))
+ return;
+
+ char* tDelim2 = strchr( tDelim, ';' );
+ if ( tDelim2 != NULL )
+ *tDelim2 = '\0';
+
+ if ( !sscanf( tDelim, "GW-IP=%s", tGateIP ))
+ return;
+
+// MSN_DebugLog( "msn_httpGatewayUnwrapRecv printed '%s','%s' to %08X (%08X)", tSessionID, tGateIP, s, this );
+ strcpy( mGatewayIP, tGateIP );
+ strcpy( mSessionID, tSessionID );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread start code
+
+static void sttRegisterThread( ThreadData* s )
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ if ( sttThreads[ i ] == NULL )
+ { sttThreads[ i ] = s;
+ break;
+ }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+static void sttUnregisterThread( ThreadData* s )
+{
+ EnterCriticalSection( &sttLock );
+
+ for ( int i=0; i < MAX_THREAD_COUNT; i++ )
+ { if ( sttThreads[ i ] == s )
+ { sttThreads[ i ] = NULL;
+ break;
+ } }
+
+ LeaveCriticalSection( &sttLock );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ ThreadData* arg;
+};
+
+static void __cdecl forkthread_r(struct FORK_ARG *fa)
+{
+ pThreadFunc callercode = fa->threadcode;
+ ThreadData* arg = fa->arg;
+ MSN_CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ sttRegisterThread( arg );
+ MSN_DebugLog( "Starting thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ SetEvent(fa->hEvent);
+ __try {
+ callercode(arg);
+ } __finally {
+ MSN_DebugLog( "Leaving thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ sttUnregisterThread( arg );
+ delete arg;
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ MSN_CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ }
+ return;
+}
+
+void ThreadData::startThread( pThreadFunc parFunc )
+{
+ FORK_ARG fa = { CreateEvent(NULL, FALSE, FALSE, NULL), parFunc, this };
+ unsigned long rc = _beginthread(( pThreadFunc )forkthread_r, 0, &fa );
+ if ((unsigned long) -1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ CloseHandle(fa.hEvent);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct FORK_ARG2 {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ void* arg;
+};
+
+static void __cdecl forkthread_r2(struct FORK_ARG2 *fa)
+{
+ pThreadFunc callercode = fa->threadcode;
+ void* arg = fa->arg;
+ MSN_CallService(MS_SYSTEM_THREAD_PUSH, 0, 0);
+ MSN_DebugLog( "Starting thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ SetEvent(fa->hEvent);
+
+ __try {
+ callercode(arg);
+ } __finally {
+ MSN_DebugLog( "Leaving thread %08X (%08X)", GetCurrentThreadId(), callercode );
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ MSN_CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ }
+ return;
+}
+
+void __stdcall MSN_StartThread( pThreadFunc parFunc, void* arg )
+{
+ FORK_ARG2 fa = { CreateEvent(NULL, FALSE, FALSE, NULL), parFunc, arg };
+ unsigned long rc = _beginthread(( pThreadFunc )forkthread_r2, 0, &fa );
+ if ((unsigned long) -1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+ CloseHandle(fa.hEvent);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// HReadBuffer members
+
+HReadBuffer::HReadBuffer( ThreadData* T, int iStart )
+{
+ owner = T;
+ buffer = ( BYTE* )T->mData;
+ totalDataSize = T->mBytesInData;
+ startOffset = iStart;
+}
+
+HReadBuffer::~HReadBuffer()
+{
+ owner->mBytesInData = totalDataSize - startOffset;
+ if ( owner->mBytesInData != 0 )
+ memmove( owner->mData, owner->mData + startOffset, owner->mBytesInData );
+}
+
+BYTE* HReadBuffer::surelyRead( int parBytes )
+{
+ if ( startOffset + parBytes > totalDataSize )
+ {
+ int tNewLen = totalDataSize - startOffset;
+ if ( tNewLen > 0 )
+ memmove( buffer, buffer + startOffset, tNewLen );
+ else
+ tNewLen = 0;
+
+ startOffset = 0;
+ totalDataSize = tNewLen;
+ }
+
+ int bufferSize = sizeof owner->mData;
+ if ( parBytes > bufferSize - startOffset ) {
+ MSN_DebugLog( "HReadBuffer::surelyRead: not enough memory, %d %d %d", parBytes, bufferSize, startOffset );
+ return NULL;
+ }
+
+ while( totalDataSize - startOffset < parBytes )
+ {
+ int recvResult = owner->recv(( char* )buffer + totalDataSize, bufferSize - totalDataSize );
+ if ( recvResult <= 0 )
+ return NULL;
+
+ totalDataSize += recvResult;
+ }
+
+ BYTE* result = buffer + startOffset; startOffset += parBytes;
+ return result;
+}
diff --git a/miranda-wine/protocols/MSN/msn_useropts.cpp b/miranda-wine/protocols/MSN/msn_useropts.cpp
new file mode 100644
index 0000000..24cc1fb
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_useropts.cpp
@@ -0,0 +1,287 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+This file uses the 'Webhost sample' code
+Copyright(C) 2002 Chris Becke (http://www.mvps.org/user32/webhost.cab)
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Loads PNG2DIB library to handle PNG images. If DLL isn't found or can't be loaded,
+// a special error dialog appears.
+
+static BOOL CALLBACK LoadPng2dibProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch( uMsg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ RECT tRect;
+ GetWindowRect( hwndDlg, &tRect );
+ HDC tHDC = GetDC( hwndDlg );
+ int tXXXX = GetDeviceCaps( tHDC, HORZRES );
+ int tYYYY = GetDeviceCaps( tHDC, VERTRES );
+ ReleaseDC( hwndDlg, tHDC );
+ SetWindowPos( hwndDlg, HWND_TOP, tXXXX/2 - ( tRect.right-tRect.left )/2 - 1, tYYYY/2 - ( tRect.bottom-tRect.top )/2 - 1, 0, 0, SWP_NOSIZE );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_BTN_INSTALL:
+ MSN_CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )"http://www.postman.ru/~ghazan/files/png2dib.mir" );
+ EndDialog( hwndDlg, 1 );
+ break;
+
+ case IDC_BTN_DOWNLOAD:
+ MSN_CallService( MS_UTILS_OPENURL, TRUE, ( LPARAM )"http://www.postman.ru/~ghazan/files/png2dib.zip" );
+ EndDialog( hwndDlg, 2 );
+ break;
+
+ case IDC_BTN_CANCEL:
+ EndDialog( hwndDlg, 3 );
+ break;
+ } } }
+
+ return FALSE;
+}
+
+BOOL __stdcall MSN_LoadPngModule()
+{
+ if ( !ServiceExists(MS_DIB2PNG) || !ServiceExists(MS_PNG2DIB)) {
+ DialogBox( hInst, MAKEINTRESOURCE( IDD_GET_PNG2DIB ), NULL, LoadPng2dibProc );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MSN contact option page dialog procedure.
+
+struct MsnDlgProcData
+{
+ HANDLE hContact;
+ HANDLE hEventHook;
+};
+
+#define HM_REBIND_AVATAR ( WM_USER + 1024 )
+
+BOOL CALLBACK MsnDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ MsnDlgProcData* pData = new MsnDlgProcData;
+ pData->hContact = ( HANDLE )lParam;
+ pData->hEventHook = HookEventMessage( ME_PROTO_ACK, hwndDlg, HM_REBIND_AVATAR );
+ SetWindowLong( hwndDlg, GWL_USERDATA, LONG( pData ));
+
+ char tBuffer[ MAX_PATH ];
+ if ( MSN_GetStaticString( "OnMobile", pData->hContact, tBuffer, sizeof tBuffer ))
+ strcpy( tBuffer, "N" );
+ SetDlgItemTextA( hwndDlg, IDC_MOBILE, tBuffer );
+
+ if ( MSN_GetStaticString( "OnMsnMobile", pData->hContact, tBuffer, sizeof tBuffer ))
+ strcpy( tBuffer, "N" );
+ SetDlgItemTextA( hwndDlg, IDC_MSN_MOBILE, tBuffer );
+
+ DWORD dwFlagBits = MSN_GetDword( pData->hContact, "FlagBits", 0 );
+ SetDlgItemTextA( hwndDlg, IDC_WEBMESSENGER, ( dwFlagBits & 0x200 ) ? "Y" : "N" );
+
+ if ( MyOptions.EnableAvatars ) {
+ MSN_GetAvatarFileName(( HANDLE )lParam, tBuffer, sizeof tBuffer );
+
+ if ( access( tBuffer, 0 )) {
+LBL_Reread: DBWriteContactSettingString( pData->hContact, "ContactPhoto", "File", tBuffer );
+ p2p_invite( pData->hContact, MSN_APPID_AVATAR );
+ return TRUE;
+ }
+
+ char tSavedContext[ 256 ], tNewContext[ 256 ];
+ if ( MSN_GetStaticString( "PictContext", pData->hContact, tNewContext, sizeof( tNewContext )) ||
+ MSN_GetStaticString( "PictSavedContext", pData->hContact, tSavedContext, sizeof( tSavedContext )))
+ goto LBL_Reread;
+
+ if ( stricmp( tNewContext, tSavedContext ))
+ goto LBL_Reread;
+
+ SendDlgItemMessageA( hwndDlg, IDC_MSN_PICT, STM_SETIMAGE, IMAGE_BITMAP,
+ ( LPARAM )LoadImageA( ::GetModuleHandle(NULL), tBuffer, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ));
+ } }
+ return TRUE;
+
+ case HM_REBIND_AVATAR:
+ { MsnDlgProcData* pData = ( MsnDlgProcData* )GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ ACKDATA* ack = ( ACKDATA* )lParam;
+ if ( ack->type == ACKTYPE_AVATAR && ack->hContact == pData->hContact ) {
+ if ( ack->result == ACKRESULT_SUCCESS ) {
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )ack->hProcess;
+ SendDlgItemMessageA( hwndDlg, IDC_MSN_PICT, STM_SETIMAGE, IMAGE_BITMAP,
+ ( LPARAM )LoadImageA( ::GetModuleHandle(NULL), AI->filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE ));
+ }
+ else if ( ack->result == ACKRESULT_STATUS )
+ p2p_invite( ack->hContact, MSN_APPID_AVATAR );
+ } }
+ break;
+
+ case WM_DESTROY:
+ MsnDlgProcData* pData = ( MsnDlgProcData* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ UnhookEvent( pData->hEventHook );
+ delete pData;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// AvatarDlgProc - MSN avatar option page dialog procedure.
+
+static HBITMAP hAvatar = NULL;
+
+static bool sttSetAvatar( HWND hwndDlg )
+{
+ char szFileName[ MAX_PATH ];
+ if ( MSN_EnterBitmapFileName( szFileName ) != ERROR_SUCCESS )
+ return false;
+
+ HBITMAP hBitmap = ( HBITMAP )MSN_CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szFileName );
+ if ( hBitmap == NULL )
+ return false;
+
+ if (( hBitmap = MSN_StretchBitmap( hBitmap )) == NULL )
+ return false;
+
+ if ( hAvatar != NULL ) {
+ DeleteObject( hAvatar );
+ hAvatar = NULL;
+ }
+
+ MSN_SaveBitmapAsAvatar( hAvatar = hBitmap, szFileName );
+
+ if ( msnLoggedIn )
+ MSN_SetServerStatus( msnStatusMode );
+
+ return true;
+}
+
+BOOL CALLBACK AvatarDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static RECT r;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+
+ hAvatar = NULL;
+ if ( MSN_GetByte( "EnableAvatars", 0 )) {
+ if ( MSN_LoadPngModule() ) {
+ char tBuffer[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, tBuffer, sizeof tBuffer );
+ hAvatar = ( HBITMAP )MSN_CallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )tBuffer );
+ if ( hAvatar != NULL )
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ }
+ else MSN_SetByte( "EnableAvatars", 0 );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED ) {
+ switch( LOWORD( wParam )) {
+ case IDC_SETAVATAR:
+ if ( sttSetAvatar( hwndDlg ))
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ break;
+
+ case IDC_DELETEAVATAR:
+ if ( hAvatar != NULL ) {
+ DeleteObject( hAvatar );
+ hAvatar = NULL;
+ }
+
+ char tFileName[ MAX_PATH ];
+ MSN_GetAvatarFileName( NULL, tFileName, sizeof tFileName );
+ DeleteFileA( tFileName );
+ DBDeleteContactSetting( NULL, msnProtocolName, "PictObject" );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ break;
+ } }
+ break;
+
+ case WM_DESTROY:
+ if ( hAvatar != NULL )
+ DeleteObject( hAvatar );
+ break;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MsnOnDetailsInit - initializes user info dialog pages.
+
+int MsnOnDetailsInit( WPARAM wParam, LPARAM lParam )
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hInst;
+
+ HANDLE hContact = ( HANDLE )lParam;
+ if ( hContact == NULL ) {
+ if ( MyOptions.EnableAvatars ) {
+ char szTitle[256];
+ mir_snprintf( szTitle, sizeof( szTitle ), "%s %s", msnProtocolName, MSN_Translate( "Avatar" ));
+
+ odp.pfnDlgProc = AvatarDlgProc;
+ odp.position = 1900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_SETAVATAR);
+ odp.pszTitle = szTitle;
+ MSN_CallService(MS_USERINFO_ADDPAGE, wParam, (LPARAM)&odp);
+ }
+ return 0;
+ }
+
+ char* szProto = ( char* )MSN_CallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM )hContact, 0 );
+ if ( lstrcmpA( szProto, msnProtocolName ))
+ return 0;
+
+ if ( MyOptions.EnableAvatars && MSN_GetDword( hContact, "FlagBits", 0 )) {
+ odp.pfnDlgProc = MsnDlgProc;
+ odp.position = -1900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_USEROPTS);
+ odp.pszTitle = Translate(msnProtocolName);
+ MSN_CallService(MS_USERINFO_ADDPAGE, wParam, (LPARAM)&odp);
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/MSN/msn_ws.cpp b/miranda-wine/protocols/MSN/msn_ws.cpp
new file mode 100644
index 0000000..274b4be
--- /dev/null
+++ b/miranda-wine/protocols/MSN/msn_ws.cpp
@@ -0,0 +1,324 @@
+/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright (c) 2003-5 George Hazan.
+Copyright (c) 2002-3 Richard Hughes (original version).
+
+Miranda IM: the free icq client for MS Windows
+Copyright (C) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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 "msn_global.h"
+
+static char sttGatewayHeader[] =
+ "POST %s HTTP/1.1\r\n"
+ "Accept: */*\r\n"
+ "Content-Type: text/xml; charset=utf-8\r\n"
+ "Content-Length: %d\r\n"
+ "User-Agent: %s\r\n"
+ "Host: %s\r\n"
+ "Connection: Keep-Alive\r\n"
+ "Cache-Control: no-cache\r\n\r\n";
+
+//=======================================================================================
+
+int ThreadData::send( char* data, int datalen )
+{
+ if ( this == NULL )
+ return 0;
+
+ NETLIBBUFFER nlb = { data, datalen, 0 };
+
+ mWaitPeriod = 60;
+
+ if ( MyOptions.UseGateway && !( mType == SERVER_FILETRANS && mP2pSession != NULL )) {
+ mGatewayTimeout = 2;
+
+ if ( !MyOptions.UseProxy ) {
+ TQueueItem* tNewItem = ( TQueueItem* )malloc( datalen + sizeof( void* ) + sizeof( int ) + 1 );
+ tNewItem->datalen = datalen;
+ memcpy( tNewItem->data, data, datalen );
+ tNewItem->data[datalen] = 0;
+
+ TQueueItem* p = mFirstQueueItem;
+ if ( p != NULL ) {
+ while ( p->next != NULL )
+ p = p->next;
+
+ p ->next = tNewItem;
+ }
+ else mFirstQueueItem = tNewItem;
+
+ tNewItem->next = NULL;
+ return TRUE;
+ }
+
+ MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), mGatewayTimeout );
+ }
+
+ int rlen = MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( rlen == SOCKET_ERROR ) {
+ // should really also check if sendlen is the same as datalen
+ MSN_DebugLog( "Send failed: %d", WSAGetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//=======================================================================================
+// Receving data
+//=======================================================================================
+
+int ThreadData::recv_dg( char* data, long datalen )
+{
+ if ( mReadAheadBuffer != NULL ) {
+ int tBytesToCopy = ( datalen >= mEhoughData ) ? mEhoughData : datalen;
+ memcpy( data, mReadAheadBuffer, tBytesToCopy );
+ mEhoughData -= tBytesToCopy;
+ if ( mEhoughData == 0 ) {
+ free( mReadAheadBuffer );
+ mReadAheadBuffer = NULL;
+ }
+ else memmove( mReadAheadBuffer, mReadAheadBuffer + tBytesToCopy, mEhoughData );
+
+ return tBytesToCopy;
+ }
+
+ bool bCanPeekMsg = true;
+
+LBL_RecvAgain:
+ int ret = 0;
+ {
+ NETLIBSELECT tSelect = {0};
+ tSelect.cbSize = sizeof( tSelect );
+ tSelect.dwTimeout = 1000;
+ tSelect.hReadConns[ 0 ] = ( HANDLE )s;
+
+ for ( int i=0; i < mGatewayTimeout || !bCanPeekMsg; i++ ) {
+ if ( bCanPeekMsg ) {
+ TQueueItem* QI = mFirstQueueItem;
+ if ( QI != NULL )
+ {
+ char szHttpPostUrl[300];
+ getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), QI->datalen == 0 );
+
+ char* tBuffer = ( char* )alloca( QI->datalen+400 );
+ int cbBytes = mir_snprintf( tBuffer, QI->datalen+400, sttGatewayHeader,
+ szHttpPostUrl, QI->datalen, MSN_USER_AGENT, mGatewayIP);
+ memcpy( tBuffer+cbBytes, QI->data, QI->datalen );
+ cbBytes += QI->datalen;
+ tBuffer[ cbBytes ] = 0;
+
+ NETLIBBUFFER nlb = { tBuffer, cbBytes, 0 };
+ ret = MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret == SOCKET_ERROR ) {
+ MSN_DebugLog( "Send failed: %d", WSAGetLastError() );
+ return 0;
+ }
+
+ mFirstQueueItem = QI->next;
+ free( QI );
+
+ ret = 1;
+ break;
+ } }
+
+ ret = MSN_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&tSelect );
+ if ( ret != 0 )
+ break;
+ // Timeout switchboard session if inactive
+ if ( !mIsMainThread && mJoinedCount <= 1 && --mWaitPeriod <= 0 )
+ {
+ if (mJoinedCount == 0 || p2p_getFirstSession(mJoinedContacts[0]) == NULL)
+ {
+ MSN_DebugLog( "Dropping the idle switchboard due to the 60 sec timeout" );
+ return 0;
+ }
+ else
+ mWaitPeriod = 60;
+ }
+ }
+ }
+
+ bCanPeekMsg = false;
+
+ if ( ret == 0 ) {
+ mGatewayTimeout += 2;
+ if ( mGatewayTimeout > 8 )
+ mGatewayTimeout = 8;
+
+ char szHttpPostUrl[300];
+ getGatewayUrl( szHttpPostUrl, sizeof( szHttpPostUrl ), true );
+
+ char szCommand[ 400 ];
+ int cbBytes = mir_snprintf( szCommand, sizeof( szCommand ),
+ sttGatewayHeader, szHttpPostUrl, 0, MSN_USER_AGENT, mGatewayIP);
+
+ NETLIBBUFFER nlb = { szCommand, cbBytes, 0 };
+ MSN_CallService( MS_NETLIB_SEND, ( WPARAM )s, ( LPARAM )&nlb );
+ goto LBL_RecvAgain;
+ }
+
+ NETLIBBUFFER nlb = { data, datalen, 0 };
+ ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret == 0 ) {
+ MSN_DebugLog( "Connection closed gracefully");
+ return 0;
+ }
+
+ if ( ret < 0 ) {
+ MSN_DebugLog( "Connection abortively closed, error %d", WSAGetLastError() );
+ return ret;
+ }
+
+ bCanPeekMsg = true;
+
+ char* p = strstr( data, "\r\n" );
+ if ( p == NULL ) {
+ MSN_DebugLog( "ACHTUNG! it's not a valid header: '%s'", data );
+ goto LBL_RecvAgain;
+ }
+
+ int status = 0;
+ sscanf( data, "HTTP/1.1 %d", &status );
+ if ( status == 100 )
+ goto LBL_RecvAgain;
+
+ int tContentLength = 0, hdrLen;
+ {
+ MimeHeaders tHeaders;
+ const char* rest = tHeaders.readFromBuffer( p+2 );
+ if ( *rest == '\r' )
+ rest += 2;
+
+ for ( int i=0; i < tHeaders.mCount; i++ )
+ {
+ MimeHeader& H = tHeaders.mVals[i];
+
+ if ( stricmp( H.name, "X-MSN-Messenger" ) == 0 ) {
+ if ( strstr( H.value, "Session=close" ) != 0 ) {
+ return 0;
+ }
+
+ processSessionData( H.value );
+ }
+
+ if ( stricmp( H.name, "Content-Length" ) == 0 )
+ tContentLength = atol( H.value );
+ }
+
+ hdrLen = int( rest - data );
+ }
+
+ if ( tContentLength == 0 )
+ goto LBL_RecvAgain;
+ else
+ {
+ mGatewayTimeout = 1;
+ mWaitPeriod = 60;
+ }
+
+ ret -= hdrLen;
+ if ( ret <= 0 ) {
+ nlb.buf = data;
+ nlb.len = datalen;
+ ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret <= 0 )
+ return ret;
+ }
+ else memmove( data, data+hdrLen, ret );
+
+ if ( tContentLength > ret ) {
+ tContentLength -= ret;
+
+ mReadAheadBuffer = ( char* )calloc( tContentLength+1, 1 );
+ mReadAheadBuffer[ tContentLength ] = 0;
+ mEhoughData = tContentLength;
+ nlb.buf = mReadAheadBuffer;
+
+ while ( tContentLength > 0 ) {
+ nlb.len = tContentLength;
+ int ret2 = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret2 <= 0 )
+ { free( mReadAheadBuffer );
+ mReadAheadBuffer = NULL;
+ return ret2;
+ }
+
+ tContentLength -= ret2;
+ nlb.buf += ret2;
+ } }
+
+ return ret;
+}
+
+int ThreadData::recv( char* data, long datalen )
+{
+ if ( MyOptions.UseGateway && !MyOptions.UseProxy )
+ if ( mType != SERVER_FILETRANS || mP2pSession == 0 )
+ return recv_dg( data, datalen );
+
+ NETLIBBUFFER nlb = { data, datalen, 0 };
+
+LBL_RecvAgain:
+ if ( !mIsMainThread && !MyOptions.UseGateway && !MyOptions.UseProxy ) {
+ mWaitPeriod = 60;
+ while ( --mWaitPeriod >= 0 ) {
+ NETLIBSELECT nls = { 0 };
+ nls.cbSize = sizeof( nls );
+ nls.dwTimeout = 1000;
+ nls.hReadConns[0] = s;
+ if ( MSN_CallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ) != 0 )
+ break;
+ }
+
+ if ( mWaitPeriod < 0 && mJoinedCount <= 1 ) {
+ if (mJoinedCount == 0 || p2p_getFirstSession(mJoinedContacts[0]) == NULL) {
+ MSN_DebugLog( "Dropping the idle switchboard due to the 60 sec timeout" );
+ return 0;
+ }
+ else mWaitPeriod = 60;
+ } }
+
+ int ret = MSN_CallService( MS_NETLIB_RECV, ( WPARAM )s, ( LPARAM )&nlb );
+ if ( ret == 0 ) {
+ MSN_DebugLog( "Connection closed gracefully" );
+ return 0;
+ }
+
+ if ( ret < 0 ) {
+ MSN_DebugLog( "Connection abortively closed, error %d", WSAGetLastError() );
+ return ret;
+ }
+
+ if ( MyOptions.UseGateway)
+ {
+ if ( ret == 1 && *data == 0 )
+ {
+ int tOldTimeout = MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), 2 );
+ tOldTimeout += 2;
+ if ( tOldTimeout > 8 )
+ tOldTimeout = 8;
+
+ MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), tOldTimeout );
+ goto LBL_RecvAgain;
+ }
+ else MSN_CallService( MS_NETLIB_SETPOLLINGTIMEOUT, WPARAM( s ), 1 );
+ }
+
+ return ret;
+}
diff --git a/miranda-wine/protocols/MSN/resource.h b/miranda-wine/protocols/MSN/resource.h
new file mode 100644
index 0000000..25ab3ed
--- /dev/null
+++ b/miranda-wine/protocols/MSN/resource.h
@@ -0,0 +1,111 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by msn.rc
+//
+#define IDI_MSN 1
+#define IDD_USEROPTS 105
+#define IDD_OPT_MSN_CONN 106
+#define IDD_HOTMAIL_OPT_POPUP 107
+#define IDI_MSNBLOCK 108
+#define IDI_INBOX 112
+#define IDI_INVITE 113
+#define IDI_NETMEETING 114
+#define IDI_PROFILE 115
+#define IDD_GET_PNG2DIB 118
+#define IDD_LISTSMGR 119
+#define IDI_LIST_FL 120
+#define IDI_LIST_AL 121
+#define IDI_LIST_BL 122
+#define IDI_LIST_RL 123
+#define IDI_AVATAR 125
+#define IDI_NUDGE 128
+#define IDI_SERVICES 129
+#define IDI_ICON2 130
+#define IDD_DIALOG1 131
+#define IDD_SETAVATAR 132
+#define IDD_OPT_MSNMAIN 184
+#define IDC_OPTIONSTAB 101
+#define IDD_OPT_MSN 185
+#define IDD_SETNICKNAME 226
+#define IDC_STMSNGROUP 1002
+#define IDC_EDIT1 1003
+#define IDC_USERTYPING 1004
+#define IDC_USEIEPROXY 1005
+#define IDC_ENABLE_AVATARS 1006
+#define IDC_USEWINCOLORS 1007
+#define IDC_ENABLE_NUDGE 1007
+#define IDC_MSN_PICT 1008
+#define IDC_NUDGE_MESSAGE 1008
+#define IDC_CUSTOM1 1009
+#define IDC_NUDGE_POPUP 1009
+#define IDC_USE_OWN_NICKNAME 1010
+#define IDC_BTN_INSTALL 1011
+#define IDC_NUDGE_CLIST 1011
+#define IDC_BTN_DOWNLOAD 1012
+#define IDC_NUDGE_CHAT 1012
+#define IDC_BTN_CANCEL 1013
+#define IDC_NUDGE_POPUP2 1013
+#define IDC_NUDGE_SOUND 1013
+#define IDC_MSNLISTS 1014
+#define IDC_LIST 1015
+#define IDC_ICON_FL 1016
+#define IDC_ICON_RL 1017
+#define IDC_ICON_AL 1018
+#define IDC_ICON_BL 1019
+#define IDC_PASSWORD 1020
+#define IDC_AVATAR 1021
+#define IDC_HANDLE 1022
+#define IDC_HANDLE2 1023
+#define IDC_SETAVATAR 1024
+#define IDC_DELETEAVATAR 1025
+#define IDC_BGCOLOUR 1026
+#define IDC_KEEPALIVE 1027
+#define IDC_TEXTCOLOUR 1028
+#define IDC_AWAY_AS_BRB 1029
+#define IDC_PREVIEW 1030
+#define IDC_PREVIEW2 1031
+#define IDC_ENABLE 1032
+#define IDC_SLOWSEND 1033
+#define IDC_MANAGEGROUPS 1034
+#define IDC_NOTIFY_ENDSESSION 1035
+#define IDC_CHECK1 1036
+#define IDC_USEOPENSSL 1036
+#define IDC_USEMSNP11 1037
+#define IDC_STMSNEXTRAGROUP 1037
+#define IDC_SENDFONTINFO 1046
+#define IDC_NOTIFY_USERTYPE 1047
+#define IDC_NICKNAME 1048
+#define IDC_DISABLEHOTJUNK 1049
+#define IDC_DEBUG 1050
+#define IDC_POPUP_TIMEOUT 1051
+#define IDC_POPUP_TIMEOUT2 1052
+#define IDC_NOTIFY_FIRSTMSG 1053
+#define IDC_DISABLE_ANOTHER_CONTACTS 1054
+#define IDC_ERRORS_USING_POPUPS 1056
+#define IDC_MAILER_APP 1057
+#define IDC_RUN_APP_ON_HOTMAIL 1058
+#define IDC_ENTER_MAILER_APP 1059
+#define IDC_MOBILE 1060
+#define IDC_MSN_MOBILE 1061
+#define IDC_WEBMESSENGER 1062
+#define IDC_LOGINSERVER 1171
+#define IDC_YOURHOST 1172
+#define IDC_MSNPORT 1174
+#define IDC_USEGATEWAY 1175
+#define IDC_DISABLEHOTMAIL 1301
+#define IDC_AUTOGETHOST 1302
+#define IDC_DISABLE_MAIN_MENU 1303
+#define IDC_NEWMSNACCOUNTLINK 1438
+#define IDC_RESETSERVER 1472
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 133
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1038
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/protocols/MSN/resource.rc b/miranda-wine/protocols/MSN/resource.rc
new file mode 100644
index 0000000..3e562dc
--- /dev/null
+++ b/miranda-wine/protocols/MSN/resource.rc
@@ -0,0 +1,2 @@
+#include "msn.rc"
+#include "version.rc"
diff --git a/miranda-wine/protocols/MSN/sha1.c b/miranda-wine/protocols/MSN/sha1.c
new file mode 100644
index 0000000..887c54a
--- /dev/null
+++ b/miranda-wine/protocols/MSN/sha1.c
@@ -0,0 +1,419 @@
+/*
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.c
+ *
+ * Description:
+ * This file implements the Secure Hashing Algorithm 1 as
+ * defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * The SHA-1, produces a 160-bit message digest for a given
+ * data stream. It should take about 2**n steps to find a
+ * message with the same digest as a given message and
+ * 2**(n/2) to find any two messages with the same digest,
+ * when n is the digest size in bits. Therefore, this
+ * algorithm can serve as a means of providing a
+ * "fingerprint" for a message.
+ *
+ * Portability Issues:
+ * SHA-1 is defined in terms of 32-bit "words". This code
+ * uses <stdint.h> (included via "sha1.h" to define 32 and 8
+ * bit unsigned integer types. If your C compiler does not
+ * support 32 bit unsigned integers, this code is not
+ * appropriate.
+ *
+ * Caveats:
+ * SHA-1 is designed to work with messages less than 2^64 bits
+ * long. Although SHA-1 allows a message digest to be generated
+ * for messages of any number of bits less than 2^64, this
+ * implementation only works with messages with a length that is
+ * a multiple of the size of an 8-bit character.
+ *
+ */
+
+#include "sha1.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage(SHA1Context *);
+void SHA1ProcessMessageBlock(SHA1Context *);
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset(SHA1Context *context)
+{
+ if (!context)
+ {
+ return shaNull;
+ }
+
+ context->Length_Low = 0;
+ context->Length_High = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * Message_Digest array provided by the caller.
+ * NOTE: The first octet of hash is stored in the 0th element,
+ * the last octet of hash in the 19th element.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize])
+{
+ int i;
+
+ if (!context || !Message_Digest)
+ {
+ return shaNull;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+
+ if (!context->Computed)
+ {
+ SHA1PadMessage(context);
+ for(i=0; i<64; ++i)
+ {
+ /* message may be sensitive, clear it out */
+ context->Message_Block[i] = 0;
+ }
+ context->Length_Low = 0; /* and clear length */
+ context->Length_High = 0;
+ context->Computed = 1;
+
+ }
+
+ for(i = 0; i < SHA1HashSize; ++i)
+ {
+ Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2]
+ >> 8 * ( 3 - ( i & 0x03 ) ));
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update
+ * message_array: [in]
+ * An array of characters representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input( SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length)
+{
+ if (!length)
+ {
+ return shaSuccess;
+ }
+
+ if (!context || !message_array)
+ {
+ return shaNull;
+ }
+
+ if (context->Computed)
+ {
+ context->Corrupted = shaStateError;
+
+ return shaStateError;
+ }
+
+ if (context->Corrupted)
+ {
+ return context->Corrupted;
+ }
+ while(length-- && !context->Corrupted)
+ {
+ context->Message_Block[context->Message_Block_Index++] =
+ (*message_array & 0xFF);
+
+ context->Length_Low += 8;
+ if (context->Length_Low == 0)
+ {
+ context->Length_High++;
+ if (context->Length_High == 0)
+ {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if (context->Message_Block_Index == 64)
+ {
+ SHA1ProcessMessageBlock(context);
+ }
+
+ message_array++;
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock(SHA1Context *context)
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for(t = 0; t < 16; t++)
+ {
+ W[t] = context->Message_Block[t * 4] << 24;
+ W[t] |= context->Message_Block[t * 4 + 1] << 16;
+ W[t] |= context->Message_Block[t * 4 + 2] << 8;
+ W[t] |= context->Message_Block[t * 4 + 3];
+ }
+
+ for(t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for(t = 0; t < 20; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+
+ B = A;
+ A = temp;
+ }
+
+ for(t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 40; t < 60; t++)
+ {
+ temp = SHA1CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA1PadMessage
+ *
+
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad
+ * ProcessMessageBlock: [in]
+ * The appropriate SHA*ProcessMessageBlock function
+ * Returns:
+ * Nothing.
+ *
+ */
+
+void SHA1PadMessage(SHA1Context *context)
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if (context->Message_Block_Index > 55)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 64)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock(context);
+
+ while(context->Message_Block_Index < 56)
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while(context->Message_Block_Index < 56)
+ {
+
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = (uint8_t) (context->Length_High >> 24);
+ context->Message_Block[57] = (uint8_t) (context->Length_High >> 16);
+ context->Message_Block[58] = (uint8_t) (context->Length_High >> 8);
+ context->Message_Block[59] = (uint8_t) (context->Length_High);
+ context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24);
+ context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16);
+ context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8);
+ context->Message_Block[63] = (uint8_t) (context->Length_Low);
+
+ SHA1ProcessMessageBlock(context);
+} \ No newline at end of file
diff --git a/miranda-wine/protocols/MSN/sha1.h b/miranda-wine/protocols/MSN/sha1.h
new file mode 100644
index 0000000..553f542
--- /dev/null
+++ b/miranda-wine/protocols/MSN/sha1.h
@@ -0,0 +1,114 @@
+/*
+
+ Copyright (C) The Internet Society (2001). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.h
+ *
+ * Description:
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
+ *
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
+ *
+ * Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+//#include <stdint.h>
+typedef unsigned __int32 uint32_t;
+typedef unsigned char uint8_t;
+typedef __int32 int_least16_t;
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer (i.e., unsigned char)
+ * int_least16_t integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct SHA1Context
+{
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+
+ /* Index into message block array */
+ int_least16_t Message_Block_Index;
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ * Function Prototypes
+ */
+
+#if defined __cplusplus
+extern "C"
+{
+#endif
+
+ int SHA1Reset( SHA1Context *);
+ int SHA1Input( SHA1Context *,
+ const uint8_t *,
+ unsigned int);
+ int SHA1Result( SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize]);
+#if defined __cplusplus
+}
+#endif
+
+#endif
diff --git a/miranda-wine/protocols/MSN/version.h b/miranda-wine/protocols/MSN/version.h
new file mode 100644
index 0000000..def2e71
--- /dev/null
+++ b/miranda-wine/protocols/MSN/version.h
@@ -0,0 +1,3 @@
+#define __FILEVERSION_STRING 0,6,0,1
+#define __VERSION_STRING "0.6.0.1"
+#define __VERSION_DWORD 0x00060001
diff --git a/miranda-wine/protocols/MSN/version.rc b/miranda-wine/protocols/MSN/version.rc
new file mode 100644
index 0000000..61791aa
--- /dev/null
+++ b/miranda-wine/protocols/MSN/version.rc
@@ -0,0 +1,36 @@
+
+#include <windows.h>
+#include "version.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION __FILEVERSION_STRING
+ PRODUCTVERSION __FILEVERSION_STRING
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "CompanyName", " "
+ VALUE "FileDescription", "Miranda MSN Messenger plugin"
+ VALUE "FileVersion", __VERSION_STRING
+ VALUE "InternalName", "msn"
+ VALUE "LegalCopyright", "Copyright c 2002-2005 George Hazan"
+ VALUE "OriginalFilename", "msn.dll"
+ VALUE "ProductName", "Miranda"
+ VALUE "ProductVersion", __VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END