2 * @file miranda-plugin.c
6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define MIRANDA_VER 0x900
31 #include "sipe-common.h"
33 #include "newpluginapi.h"
34 #include "m_protosvc.h"
35 #include "m_protoint.h"
36 #include "m_protomod.h"
38 #include "m_database.h"
39 #include "m_options.h"
43 #include "m_langpack.h"
46 #include "sipe-backend.h"
47 #include "sipe-core.h"
48 #include "sipe-core-private.h"
50 #include "sipe-conf.h"
51 #include "sipe-utils.h"
52 #include "sipe-session.h"
53 #include "sipe-chat.h"
55 #include "miranda-private.h"
56 #include "miranda-resource.h"
58 HANDLE sipe_miranda_debug_netlibuser
= NULL
;
60 /* Sipe core activity <-> Miranda status mapping */
61 static const gchar
* const activity_to_miranda
[SIPE_ACTIVITY_NUM_TYPES
] = {
62 /* SIPE_ACTIVITY_UNSET */ "unset",
63 /* SIPE_ACTIVITY_ONLINE */ "online",
64 /* SIPE_ACTIVITY_INACTIVE */ "idle",
65 /* SIPE_ACTIVITY_BUSY */ "busy",
66 /* SIPE_ACTIVITY_BUSYIDLE */ "busyidle",
67 /* SIPE_ACTIVITY_DND */ "do-not-disturb",
68 /* SIPE_ACTIVITY_BRB */ "be-right-back",
69 /* SIPE_ACTIVITY_AWAY */ "away",
70 /* SIPE_ACTIVITY_LUNCH */ "out-to-lunch",
71 /* SIPE_ACTIVITY_OFFLINE */ "offline",
72 /* SIPE_ACTIVITY_ON_PHONE */ "on-the-phone",
73 /* SIPE_ACTIVITY_IN_CONF */ "in-a-conference",
74 /* SIPE_ACTIVITY_IN_MEETING */ "in-a-meeting",
75 /* SIPE_ACTIVITY_OOF */ "out-of-office",
76 /* SIPE_ACTIVITY_URGENT_ONLY */ "urgent-interruptions-only",
78 GHashTable
*miranda_to_activity
= NULL
;
79 #define MIRANDA_STATUS_TO_ACTIVITY(x) \
80 GPOINTER_TO_UINT(g_hash_table_lookup(miranda_to_activity, (x)))
82 static void sipe_miranda_activity_init(void)
84 sipe_activity index
= SIPE_ACTIVITY_UNSET
;
85 miranda_to_activity
= g_hash_table_new(g_str_hash
, g_str_equal
);
86 while (index
< SIPE_ACTIVITY_NUM_TYPES
) {
87 g_hash_table_insert(miranda_to_activity
,
88 (gpointer
) activity_to_miranda
[index
],
89 GUINT_TO_POINTER(index
));
94 gchar
*sipe_backend_version(void)
98 if (CallService(MS_SYSTEM_GETVERSIONTEXT
, sizeof(version
), (LPARAM
)version
)) {
99 strcpy(version
, "Unknown");
102 return g_strdup_printf("Miranda %s SipSimple " __DATE__
" " __TIME__
, version
);
105 static void sipe_miranda_activity_destroy(void)
107 g_hash_table_destroy(miranda_to_activity
);
108 miranda_to_activity
= NULL
;
114 * Global variables related to miranda core or UI
116 static BOOL (WINAPI
*pfnEnableThemeDialogTexture
)(HANDLE
, DWORD
) = 0;
118 PLUGINLINK
* pluginLink
;
119 struct MM_INTERFACE mmi
;
124 INT_PTR CALLBACK
DlgProcSipSimpleOptsAbout(HWND hwndDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
131 const SIPPROTO
*pr
= (const SIPPROTO
*)lParam
;
132 gchar
*about
= sipe_core_about();
135 TranslateDialogDefault(hwndDlg
);
137 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, lParam
);
139 tex
.flags
= ST_DEFAULT
;
142 // SendDlgItemMessage(hwndDlg, IDC_ABOUTSIPE, EM_SETTEXTEX, (WPARAM)&tex, (LPARAM)about_txt );
143 SendDlgItemMessage(hwndDlg
, IDC_ABOUTSIPE
, EM_SETTEXTEX
, (WPARAM
)&tex
, (LPARAM
)about
);
152 static INT_PTR CALLBACK
DlgProcSipSimpleOpts(HWND hwndDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
160 const SIPPROTO
*pr
= (const SIPPROTO
*)lParam
;
163 TranslateDialogDefault(hwndDlg
);
165 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, lParam
);
169 str
= DBGetString( NULL
, SIPSIMPLE_PROTOCOL_NAME
, "debuglog");
170 SetDlgItemTextA(hwndDlg
, IDC_DEBUGLOG
, str
);
171 SendDlgItemMessage(hwndDlg
, IDC_DEBUGLOG
, EM_SETLIMITTEXT
, 100, 0);
174 str
= sipe_miranda_getString(pr
, "username");
175 SetDlgItemTextA(hwndDlg
, IDC_HANDLE
, str
);
176 SendDlgItemMessage(hwndDlg
, IDC_HANDLE
, EM_SETLIMITTEXT
, 50, 0);
179 str
= sipe_miranda_getString(pr
, "login");
180 SetDlgItemTextA(hwndDlg
, IDC_LOGIN
, str
);
181 SendDlgItemMessage(hwndDlg
, IDC_LOGIN
, EM_SETLIMITTEXT
, 50, 0);
184 str
= sipe_miranda_getString(pr
, "password");
185 if (str
) CallService(MS_DB_CRYPT_DECODESTRING
, strlen(str
),(LPARAM
)str
);
186 SetDlgItemTextA(hwndDlg
, IDC_PASSWORD
, str
);
187 SendDlgItemMessage(hwndDlg
, IDC_PASSWORD
, EM_SETLIMITTEXT
, 16, 0);
190 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, CB_ADDSTRING
, 0, (LPARAM
)_T("Auto"));
191 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, CB_ADDSTRING
, 0, (LPARAM
)_T("SSL/TLS"));
192 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, CB_ADDSTRING
, 0, (LPARAM
)_T("TCP"));
194 str
= sipe_miranda_getString(pr
, "transport");
195 if (!str
|| !strcmp(str
, "auto"))
196 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, CB_SELECTSTRING
, -1, (LPARAM
)_T("Auto"));
197 else if (!strcmp(str
, "tls"))
198 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, CB_SELECTSTRING
, -1, (LPARAM
)_T("SSL/TLS"));
199 else if (!strcmp(str
, "tcp"))
200 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, CB_SELECTSTRING
, -1, (LPARAM
)_T("TCP"));
208 int code
= wParam
>> 16;
209 int id
= wParam
& 0xffff;
211 if (!lock
&& (code
== EN_CHANGE
|| code
== CBN_SELCHANGE
)) {
212 SendMessage(GetParent(hwndDlg
), PSM_CHANGED
, 0, 0);
219 if (((LPNMHDR
)lParam
)->code
== (UINT
)PSN_APPLY
)
224 const SIPPROTO
*pr
= (const SIPPROTO
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
226 GetDlgItemTextA(hwndDlg
, IDC_DEBUGLOG
, buf
, sizeof(buf
));
227 DBWriteContactSettingString(NULL
, SIPSIMPLE_PROTOCOL_NAME
, "debuglog", buf
);
229 GetDlgItemTextA(hwndDlg
, IDC_HANDLE
, buf
, sizeof(buf
));
230 sipe_miranda_setString(pr
, "username", buf
);
232 GetDlgItemTextA(hwndDlg
, IDC_LOGIN
, buf
, sizeof(buf
));
233 sipe_miranda_setString(pr
, "login", buf
);
235 GetDlgItemTextA(hwndDlg
, IDC_PASSWORD
, buf
, sizeof(buf
));
236 CallService(MS_DB_CRYPT_ENCODESTRING
, sizeof(buf
),(LPARAM
)buf
);
237 sipe_miranda_setString(pr
, "password", buf
);
239 SendDlgItemMessage(hwndDlg
, IDC_CONNTYPE
, WM_GETTEXT
, 100, (LPARAM
)tbuf
);
241 if (!_tcscmp(tbuf
, _T("Auto")))
242 sipe_miranda_setString(pr
, "transport", "auto");
243 else if (!_tcscmp(tbuf
, _T("SSL/TLS")))
244 sipe_miranda_setString(pr
, "transport", "tls");
245 else if (!_tcscmp(tbuf
, _T("TCP")))
246 sipe_miranda_setString(pr
, "transport", "tcp");
258 INT_PTR CALLBACK
DlgProcAccMgrUI(HWND hwndDlg
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
264 const SIPPROTO
*pr
= (const SIPPROTO
*)lParam
;
267 TranslateDialogDefault(hwndDlg
);
269 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, lParam
);
272 str
= sipe_miranda_getString(pr
, "username");
273 SetDlgItemTextA(hwndDlg
, IDC_HANDLE
, str
);
276 str
= sipe_miranda_getString(pr
, "login");
277 SetDlgItemTextA(hwndDlg
, IDC_LOGIN
, str
);
280 str
= sipe_miranda_getString(pr
, "password");
281 if (str
) CallService(MS_DB_CRYPT_DECODESTRING
, strlen(str
),(LPARAM
)str
);
282 SetDlgItemTextA(hwndDlg
, IDC_PASSWORD
, str
);
285 SendDlgItemMessage(hwndDlg
, IDC_HANDLE
, EM_SETLIMITTEXT
, 50, 0);
286 SendDlgItemMessage(hwndDlg
, IDC_LOGIN
, EM_SETLIMITTEXT
, 50, 0);
287 SendDlgItemMessage(hwndDlg
, IDC_PASSWORD
, EM_SETLIMITTEXT
, 16, 0);
293 if (HIWORD(wParam
) == EN_CHANGE
&& (HWND
)lParam
== GetFocus())
295 switch(LOWORD(wParam
))
300 SendMessage(GetParent(hwndDlg
), PSM_CHANGED
, 0, 0);
306 if (((LPNMHDR
)lParam
)->code
== (UINT
)PSN_APPLY
)
310 const SIPPROTO
*pr
= (const SIPPROTO
*)lParam
;
312 GetDlgItemTextA(hwndDlg
, IDC_HANDLE
, buf
, sizeof(buf
));
313 sipe_miranda_setString(pr
, "username", buf
);
315 GetDlgItemTextA(hwndDlg
, IDC_LOGIN
, buf
, sizeof(buf
));
316 sipe_miranda_setString(pr
, "login", buf
);
318 GetDlgItemTextA(hwndDlg
, IDC_PASSWORD
, buf
, sizeof(buf
));
319 CallService(MS_DB_CRYPT_ENCODESTRING
, sizeof(buf
),(LPARAM
)buf
);
320 sipe_miranda_setString(pr
, "password", buf
);
332 * Miranda service support functions
334 * Functions called by our service functions
336 static void set_if_defined(SIPPROTO
*pr
, GHashTable
*store
, HANDLE hContact
, sipe_buddy_info_fields field
, char *label
)
338 char *value
= (char *)g_hash_table_lookup(store
, (gpointer
)field
);
340 sipe_miranda_setContactStringUtf(pr
, hContact
, label
, value
);
343 static INT_PTR
StartChat(SIPPROTO
*pr
, WPARAM wParam
, LPARAM lParam
)
345 HANDLE hContact
= (HANDLE
)wParam
;
346 struct sipe_core_public
*sipe_public
= pr
->sip
;
347 struct sipe_core_private
*sipe_private
= SIPE_CORE_PRIVATE
;
350 if ( !DBGetContactSettingString( hContact
, pr
->proto
.m_szModuleName
, SIP_UNIQUEID
, &dbv
)) {
351 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007
))
353 sipe_conf_add(sipe_private
, dbv
.pszVal
);
355 else /* 2005- multiparty chat */
357 gchar
*self
= sip_uri_self(sipe_private
);
358 struct sip_session
*session
;
360 session
= sipe_session_add_chat(sipe_private
,
364 session
->chat_session
->backend
= sipe_backend_chat_create(SIPE_CORE_PUBLIC
,
365 session
->chat_session
,
366 session
->chat_session
->title
,
370 sipe_invite(sipe_private
, session
, dbv
.pszVal
, NULL
, NULL
, NULL
, FALSE
);
372 DBFreeVariant( &dbv
);
379 static void OnModulesLoaded(SIPPROTO
*pr
)
381 TCHAR descr
[MAX_PATH
];
382 NETLIBUSER nlu
= {0};
383 char service_name
[200];
385 CLISTMENUITEM mi
= {0};
387 SIPE_DEBUG_INFO_NOFORMAT("OnEvent::OnModulesLoaded");
389 nlu
.cbSize
= sizeof(nlu
);
390 nlu
.flags
= NUF_OUTGOING
| NUF_TCHAR
;
391 nlu
.szSettingsModule
= pr
->proto
.m_szModuleName
;
392 _sntprintf(descr
, SIZEOF(descr
), TranslateT("%s server connection"), pr
->proto
.m_tszUserName
);
393 nlu
.ptszDescriptiveName
= descr
;
395 pr
->m_hServerNetlibUser
= (HANDLE
)CallService(MS_NETLIB_REGISTERUSER
, 0, (LPARAM
)&nlu
);
397 mi
.cbSize
= sizeof( mi
);
398 mi
.pszContactOwner
= pr
->proto
.m_szModuleName
;
399 mi
.pszService
= service_name
;
401 mir_snprintf(service_name
, sizeof(service_name
), "%s%s", pr
->proto
.m_szModuleName
, "/StartChat");
402 CreateProtoService(pr
, "/StartChat",&StartChat
);
403 mi
.position
=-2000005060;
404 mi
.icolibItem
= NULL
; //GetIconHandle("block");
405 mi
.pszName
= LPGEN("&Start Chat");
406 mi
.flags
=0; //CMIF_ICONFROMICOLIB|CMIF_HIDDEN;
407 CallService(MS_CLIST_ADDCONTACTMENUITEM
,0,(LPARAM
)&mi
);
409 gcr
.cbSize
= sizeof(gcr
);
411 gcr
.pszModule
= pr
->proto
.m_szModuleName
;
412 gcr
.pszModuleDispName
= "Sip/Simple";
416 if (CallService(MS_GC_REGISTER
, 0, (LPARAM
)&gcr
))
418 SIPE_DEBUG_INFO_NOFORMAT("OnEvent::OnModulesLoaded Failed to register chat");
423 int OnOptionsInit(const SIPPROTO
*pr
, WPARAM wParam
, LPARAM lParam
)
425 OPTIONSDIALOGPAGE odp
= {0};
426 HMODULE hUxTheme
= 0;
428 if (IsWinVerXPPlus())
430 hUxTheme
= GetModuleHandleA("uxtheme.dll");
432 pfnEnableThemeDialogTexture
= (BOOL (WINAPI
*)(HANDLE
, DWORD
))GetProcAddress(hUxTheme
, "EnableThemeDialogTexture");
435 odp
.cbSize
= sizeof(odp
);
436 odp
.position
= -800000000;
437 odp
.hInstance
= hInst
;
438 odp
.ptszGroup
= LPGENT("Network");
439 odp
.dwInitParam
= (LPARAM
)pr
;
440 odp
.ptszTitle
= pr
->proto
.m_tszUserName
;
441 odp
.flags
= ODPF_BOLDGROUPS
| ODPF_TCHAR
;
443 odp
.ptszTab
= LPGENT("Account");
444 odp
.pszTemplate
= MAKEINTRESOURCEA(IDD_OPT_SIPSIMPLE
);
445 odp
.pfnDlgProc
= DlgProcSipSimpleOpts
;
446 CallService( MS_OPT_ADDPAGE
, wParam
, ( LPARAM
)&odp
);
448 odp
.ptszTab
= LPGENT("About");
449 odp
.pszTemplate
= MAKEINTRESOURCEA(IDD_OPT_SIPSIMPLE_ABOUT
);
450 odp
.pfnDlgProc
= DlgProcSipSimpleOptsAbout
;
451 CallService( MS_OPT_ADDPAGE
, wParam
, ( LPARAM
)&odp
);
455 odp
.ptszTab
= LPGENT("Features");
456 odp
.pszTemplate
= MAKEINTRESOURCEA(IDD_OPT_ICQFEATURES
);
457 odp
.pfnDlgProc
= DlgProcIcqFeaturesOpts
;
458 CallService( MS_OPT_ADDPAGE
, wParam
, ( LPARAM
)&odp
);
460 odp
.ptszTab
= LPGENT("Privacy");
461 odp
.pszTemplate
= MAKEINTRESOURCEA(IDD_OPT_ICQPRIVACY
);
462 odp
.pfnDlgProc
= DlgProcIcqPrivacyOpts
;
463 CallService( MS_OPT_ADDPAGE
, wParam
, ( LPARAM
)&odp
);
467 odp
.position
= 100000000;
468 odp
.pszTemplate
= MAKEINTRESOURCEA(IDD_OPT_POPUPS
);
469 odp
.groupPosition
= 900000000;
470 odp
.pfnDlgProc
= DlgProcIcqPopupOpts
;
471 odp
.ptszGroup
= LPGENT("Popups");
473 CallService( MS_OPT_ADDPAGE
, wParam
, ( LPARAM
)&odp
);
479 static void sipe_miranda_close( SIPPROTO
*pr
)
481 struct sipe_core_public
*sipe_public
= pr
->sip
;
484 sipe_core_deallocate(sipe_public
);
486 // sipe_purple_chat_destroy_rejoin(purple_private);
487 // g_free(purple_private);
491 static void set_buddies_offline(const SIPPROTO
* pr
)
495 hContact
= (HANDLE
)CallService(MS_DB_CONTACT_FINDFIRST
, 0, 0);
497 char* szProto
= (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO
, (WPARAM
)hContact
, 0);
498 if (szProto
!= NULL
&& !lstrcmpA(szProto
, pr
->proto
.m_szModuleName
)) {
499 if (DBGetContactSettingByte(hContact
, pr
->proto
.m_szModuleName
, "ChatRoom", 0) == 0)
500 DBWriteContactSettingWord(hContact
, pr
->proto
.m_szModuleName
, "Status", ID_STATUS_OFFLINE
);
502 hContact
= (HANDLE
)CallService(MS_DB_CONTACT_FINDNEXT
, (WPARAM
)hContact
, 0);
506 static void sipe_miranda_login(SIPPROTO
*pr
) {
507 gchar
*username
= sipe_miranda_getString(pr
, "username");
508 gchar
*login
= sipe_miranda_getString(pr
, "login");
509 gchar
*email
= sipe_miranda_getString(pr
, "email");
510 gchar
*email_url
= sipe_miranda_getString(pr
, "email_url");
511 gchar
**domain_user
= g_strsplit_set(login
, "/\\", 2);
514 char *tmp
= (char*)mir_calloc(1024);
516 if (sipe_miranda_getStaticString(pr
, NULL
, "password", tmp
, 1024 )) tmp
[0] = '\0';
517 CallService(MS_DB_CRYPT_DECODESTRING
, sizeof(tmp
),(LPARAM
)tmp
);
518 password
= g_strdup(tmp
);
521 pr
->sip
= sipe_core_allocate(username
,
522 domain_user
[0], domain_user
[1],
528 pr
->sip
->backend_private
= pr
;
534 g_strfreev(domain_user
);
538 /* FIXME: Flag connection error */
542 //sipe_miranda_chat_setup_rejoin(pr);
545 // if (purple_account_get_bool(account, "krb5", FALSE))
546 // SIPE_CORE_FLAG_SET(KRB5);
548 // /* @TODO: is this correct?
549 // "sso" is only available when Kerberos support is compiled in */
550 // if (purple_account_get_bool(account, "sso", TRUE))
551 // SIPE_CORE_FLAG_SET(SSO);
553 /* Set display name */
554 sipe_miranda_setStringUtf(pr
, "Nick", pr
->sip
->sip_name
);
556 /* Update connection progress */
557 pr
->proto
.m_iStatus
= ID_STATUS_CONNECTING
;
558 SendBroadcast(pr
, NULL
, ACKTYPE_STATUS
, ACKRESULT_SUCCESS
, (HANDLE
)pr
->proto
.m_iStatus
, ID_STATUS_CONNECTING
);
561 username_split = g_strsplit(purple_account_get_string(account, "server", ""), ":", 2);
562 if (sipe_strequal(transport, "auto")) {
563 type = (username_split[0] == NULL) ?
564 SIPE_TRANSPORT_AUTO : SIPE_TRANSPORT_TLS;
565 } else if (sipe_strequal(transport, "tls")) {
566 type = SIPE_TRANSPORT_TLS;
568 type = SIPE_TRANSPORT_TCP;
571 sipe_core_transport_sip_connect(pr->sip,
574 username_split[0] ? username_split[1] : NULL);
575 g_strfreev(username_split);
577 sipe_core_transport_sip_connect(pr
->sip
,
584 miranda_sipe_get_info_cb(struct sipe_core_public
*sipe_public
, const char* uri
, GHashTable
*results
, void* data
)
586 SIPPROTO
*pr
= sipe_public
->backend_private
;
587 HANDLE hContact
= (HANDLE
) data
;
590 const char *id
, *value
;
592 g_hash_table_iter_init( &iter
, results
);
593 while (g_hash_table_iter_next (&iter
, (gpointer
*)&id
, (gpointer
*)&value
)) {
594 SIPE_DEBUG_INFO("miranda_sipe_get_info_cb: user info field <%d> = <%s>", id
, value
? value
: "(none)");
596 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_EMAIL
, "e-mail");
597 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_CITY
, "City");
598 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_STATE
, "State");
599 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_COUNTRY
, "Country");
600 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_COMPANY
, "Company");
601 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_JOB_TITLE
, "CompanyPosition");
602 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_WORK_PHONE
, "CompanyPhone");
603 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_STREET
, "CompanyStreet");
604 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_ZIPCODE
, "CompanyZIP");
605 set_if_defined(pr
, results
, hContact
, SIPE_BUDDY_INFO_DEPARTMENT
, "CompanyDepartment");
607 SendBroadcast(pr
, hContact
, ACKTYPE_GETINFO
, ACKRESULT_SUCCESS
, (HANDLE
) 1, (LPARAM
) 0);
611 void sipsimple_search_contact_cb( GList
*columns
, GList
*results
, GHashTable
*opts
, void *data
)
613 SIPPROTO
*pr
= (SIPPROTO
*)data
;
615 HANDLE hProcess
= g_hash_table_lookup(opts
, "searchid");
616 PROTOSEARCHRESULT psr
= { 0 };
618 psr
.cbSize
= sizeof(psr
);
623 col
= (GList
*)row
->data
;
624 psr
.nick
= (PROTOCHAR
*)col
->data
;
626 col
= g_list_next(col
);
627 psr
.lastName
= (PROTOCHAR
*)col
->data
;
629 col
= g_list_next(col
);
632 col
= g_list_next(col
);
635 col
= g_list_next(col
);
636 psr
.email
= (PROTOCHAR
*)col
->data
;
638 row
= g_list_next(row
);
639 SendBroadcast(pr
, NULL
, ACKTYPE_SEARCH
, ACKRESULT_DATA
, hProcess
, (LPARAM
) & psr
);
642 SendBroadcast(pr
, NULL
, ACKTYPE_SEARCH
, ACKRESULT_SUCCESS
, hProcess
, 0);
646 static int OnGroupChange( const SIPPROTO
*pr
, WPARAM w
, LPARAM l
)
648 CLISTGROUPCHANGE
*gi
= (CLISTGROUPCHANGE
*)l
;
649 HANDLE hContact
= (HANDLE
)w
;
653 /* No contact => it's a group add/rename/remove */
656 /* No old name => add */
661 /* No new name => delete */
662 else if (!gi
->pszNewName
)
664 SIPE_DEBUG_INFO("Removing group <l%s>", gi
->pszOldName
);
665 sipe_remove_group(pr
->sip
, TCHAR2CHAR(gi
->pszOldName
));
669 SIPE_DEBUG_INFO("Renaming group <%ls> to <%ls>", gi
->pszOldName
, gi
->pszNewName
);
670 sipe_rename_group(pr
->sip
, TCHAR2CHAR(gi
->pszOldName
), TCHAR2CHAR(gi
->pszNewName
));
674 if ( !DBGetContactSettingString( hContact
, pr
->proto
.m_szModuleName
, SIP_UNIQUEID
, &dbv
)) {
675 who
= g_strdup(dbv
.pszVal
);
676 DBFreeVariant( &dbv
);
678 if ( !DBGetContactSettingString( hContact
, "Clist", "Group", &dbv
)) {
679 SIPE_DEBUG_INFO("Moving buddy <%s> from group <%ls> to group <%ls>", who
, dbv
.pszVal
, gi
->pszNewName
);
680 sipe_core_buddy_group(pr
->sip
, who
, dbv
.pszVal
, TCHAR2CHAR(gi
->pszNewName
));
681 DBFreeVariant( &dbv
);
683 const gchar
*name
= TCHAR2CHAR(gi
->pszNewName
);
684 const gchar
*newname
;
686 SIPE_DEBUG_INFO("Really adding buddy <%s> to list in group <%ls>", who
, gi
->pszNewName
);
687 newname
= sipe_core_buddy_add(pr
->sip
, who
, name
);
689 if (!sipe_strequal(name
,newname
))
691 sipe_miranda_setContactString( pr
, hContact
, SIP_UNIQUEID
, newname
);
701 static int OnChatEvent(const SIPPROTO
*pr
, WPARAM w
, LPARAM l
)
703 GCHOOK
*hook
= (GCHOOK
*)l
;
704 GCDEST
*dst
= hook
->pDest
;
706 if (dst
->iType
== GC_USER_MESSAGE
) {
709 struct sipe_chat_session
*session
;
711 gcd
.pszModule
= pr
->proto
.m_szModuleName
;
712 gcd
.pszID
= dst
->pszID
;
713 gcd
.iType
= GC_EVENT_GETITEMDATA
;
715 gce
.cbSize
= sizeof(gce
);
719 if ((session
= CallService( MS_GC_EVENT
, 0, (LPARAM
)&gce
)) == NULL
)
721 SIPE_DEBUG_WARNING_NOFORMAT("Failed to get chat session");
725 sipe_core_chat_send(pr
->sip
, session
, hook
->pszText
);
727 } else if (dst
->iType
== GC_USER_PRIVMESS
) {
733 int OnPreBuildContactMenu(const SIPPROTO
*pr
, WPARAM wParam
, LPARAM lParam
)
735 HANDLE hContact
= (HANDLE
)wParam
;
740 INT_PTR
SvcCreateAccMgrUI(const SIPPROTO
*pr
, WPARAM wParam
, LPARAM lParam
)
742 return (INT_PTR
)CreateDialogParam(hInst
, MAKEINTRESOURCE(IDD_ACCMGRUI
), (HWND
)lParam
, DlgProcAccMgrUI
, (LPARAM
)pr
);
745 static void GetAwayMsgThread(SIPPROTO
*pr
, HANDLE hContact
)
748 gchar
*name
= sipe_miranda_getContactString(pr
, hContact
, SIP_UNIQUEID
);
753 SIPE_DEBUG_INFO("Could not find name for contact <%08x>", hContact
);
754 SendProtoAck(pr
, hContact
, 1, ACKRESULT_FAILED
, ACKTYPE_AWAYMSG
, NULL
);
758 status
= sipe_core_buddy_status(pr
->sip
,
760 SIPE_ACTIVITY_BUSYIDLE
,
761 "dummy test string");
764 tmp
= sipe_miranda_eliminate_html(status
, strlen(status
));
766 SendProtoAck(pr
, hContact
, 1, ACKRESULT_SUCCESS
, ACKTYPE_AWAYMSG
, tmp
);
774 * Miranda service functions
776 * The functions in our plugin that get called directly by core Miranda
778 static DWORD_PTR
GetCaps( SIPPROTO
*pr
, int type
, HANDLE hContact
)
782 return PF1_IM
| PF1_CHAT
| PF1_FILE
| PF1_MODEMSG
783 | PF1_SERVERCLIST
| PF1_AUTHREQ
| PF1_ADDED
784 | PF1_BASICSEARCH
| PF1_ADDSEARCHRES
785 | PF1_SEARCHBYEMAIL
| PF1_USERIDISEMAIL
790 return PF2_ONLINE
| PF2_INVISIBLE
| PF2_SHORTAWAY
791 | PF2_LONGAWAY
| PF2_LIGHTDND
| PF2_HEAVYDND
792 | PF2_OUTTOLUNCH
| PF2_ONTHEPHONE
| PF2_IDLE
;
795 return PF2_ONLINE
| PF2_INVISIBLE
| PF2_SHORTAWAY
796 | PF2_LONGAWAY
| PF2_LIGHTDND
| PF2_HEAVYDND
797 | PF2_OUTTOLUNCH
| PF2_ONTHEPHONE
| PF2_IDLE
;
800 return PF4_NOCUSTOMAUTH
| PF4_IMSENDUTF
| PF4_SUPPORTTYPING
806 case PFLAG_UNIQUEIDSETTING
:
807 return (DWORD_PTR
) SIP_UNIQUEID
;
810 SIPE_DEBUG_INFO("GetCaps: unknown type <%x>", type
);
817 static HICON
GetIcon( SIPPROTO
*pr
, int iconIndex
)
819 SIPE_DEBUG_INFO("GetIcon: unknown index <%x>", iconIndex
);
823 static int OnEvent( SIPPROTO
*pr
, PROTOEVENTTYPE eventType
, WPARAM wParam
, LPARAM lParam
)
825 SIPE_DEBUG_INFO("OnEvent: type <%x>", eventType
);
829 case EV_PROTO_ONLOAD
:
833 case EV_PROTO_ONREADYTOEXIT
:
836 case EV_PROTO_ONEXIT
:
839 case EV_PROTO_ONRENAME
:
842 case EV_PROTO_ONOPTIONS
:
843 return OnOptionsInit( pr
, wParam
, lParam
);
846 case EV_PROTO_ONERASE
:
854 static int SetStatus( SIPPROTO
*pr
, int iNewStatus
)
857 if (!pr
->m_hServerNetlibUser
) return 0;
858 if (pr
->proto
.m_iDesiredStatus
== iNewStatus
) return 0;
860 oldStatus
= pr
->proto
.m_iStatus
;
861 pr
->proto
.m_iDesiredStatus
= iNewStatus
;
863 SIPE_DEBUG_INFO("SetStatus: newstatus <%x>", iNewStatus
);
865 if (iNewStatus
== ID_STATUS_OFFLINE
) {
866 sipe_miranda_close(pr
);
867 set_buddies_offline(pr
);
868 pr
->proto
.m_iStatus
= iNewStatus
;
869 SendBroadcast(pr
, NULL
, ACKTYPE_STATUS
, ACKRESULT_SUCCESS
, (HANDLE
)oldStatus
, iNewStatus
);
871 gchar
*note
= sipe_miranda_getString(pr
, "note");
872 if (pr
->proto
.m_iStatus
== ID_STATUS_OFFLINE
) {
873 sipe_miranda_login(pr
);
875 pr
->proto
.m_iStatus
= pr
->proto
.m_iDesiredStatus
;
876 sipe_core_set_status(pr
->sip
, note
, MirandaStatusToSipe(iNewStatus
));
877 SendBroadcast(pr
, NULL
, ACKTYPE_STATUS
, ACKRESULT_SUCCESS
, (HANDLE
)oldStatus
, pr
->proto
.m_iStatus
);
883 //Will send an ack with:
884 //type=ACKTYPE_STATUS, result=ACKRESULT_SUCCESS, hProcess=(HANDLE)previousMode, lParam=newMode
885 //when the change completes. This ack is sent for all changes, not just ones
886 //caused by calling this function.
887 //Note that newMode can be ID_STATUS_CONNECTING<=newMode<ID_STATUS_CONNECTING+
888 //MAX_CONNECT_RETRIES to signify that it's connecting and it's the nth retry.
889 //Protocols are initially always in offline mode.
890 //Non-network-level protocol modules do not have the concept of a status and
891 //should leave this service unimplemented
892 //If a protocol doesn't support the specific status mode, it should pick the
898 static int UserIsTyping( SIPPROTO
*pr
, HANDLE hContact
, int type
)
900 SIPE_DEBUG_INFO("UserIsTyping: type <%x>", type
);
906 if ( !DBGetContactSettingString( hContact
, pr
->proto
.m_szModuleName
, SIP_UNIQUEID
, &dbv
)) {
907 name
= g_strdup(dbv
.pszVal
);
914 case PROTOTYPE_SELFTYPING_ON
:
915 sipe_core_user_feedback_typing(pr
->sip
, name
);
919 case PROTOTYPE_SELFTYPING_OFF
:
920 /* Not supported anymore? */
931 static HANDLE
AddToListByEvent( SIPPROTO
*pr
, int flags
, int iContact
, HANDLE hDbEvent
)
934 SIPE_DEBUG_INFO("AddToListByEvent: flags <%x> iContact <%x>", flags
, iContact
);
938 static int Authorize( SIPPROTO
*pr
, HANDLE hContact
)
941 SIPE_DEBUG_INFO_NOFORMAT("Authorize");
945 static int AuthDeny( SIPPROTO
*pr
, HANDLE hContact
, const PROTOCHAR
* szReason
)
948 SIPE_DEBUG_INFO("AuthDeny: reason <%s>", szReason
);
952 static int AuthRecv( SIPPROTO
*pr
, HANDLE hContact
, PROTORECVEVENT
* evt
)
955 SIPE_DEBUG_INFO_NOFORMAT("AuthRecv");
959 static int AuthRequest( SIPPROTO
*pr
, HANDLE hContact
, const PROTOCHAR
* szMessage
)
962 SIPE_DEBUG_INFO("AuthRequest: message <%s>", szMessage
);
966 static HANDLE
ChangeInfo( SIPPROTO
*pr
, int iInfoType
, void* pInfoData
)
969 SIPE_DEBUG_INFO("ChangeInfo: infotype <%x>", iInfoType
);
973 static HANDLE
FileAllow( SIPPROTO
*pr
, HANDLE hContact
, HANDLE hTransfer
, const PROTOCHAR
* szPath
)
976 SIPE_DEBUG_INFO("FileAllow: path <%s>", szPath
);
980 static int FileCancel( SIPPROTO
*pr
, HANDLE hContact
, HANDLE hTransfer
)
983 SIPE_DEBUG_INFO_NOFORMAT("FileCancel");
987 static int FileDeny( SIPPROTO
*pr
, HANDLE hContact
, HANDLE hTransfer
, const PROTOCHAR
* szReason
)
990 SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason
);
994 static int FileResume( SIPPROTO
*pr
, HANDLE hTransfer
, int* action
, const PROTOCHAR
** szFilename
)
997 SIPE_DEBUG_INFO("FileResume: action <%x>", action
);
1001 static int GetInfo( SIPPROTO
*pr
, HANDLE hContact
, int infoType
)
1005 SIPE_DEBUG_INFO("GetInfo: infotype <%x>", infoType
);
1007 if ( !DBGetContactSettingString( hContact
, pr
->proto
.m_szModuleName
, SIP_UNIQUEID
, &dbv
)) {
1008 sipe_get_info(pr
->sip
, dbv
.pszVal
, miranda_sipe_get_info_cb
, hContact
);
1009 DBFreeVariant( &dbv
);
1015 static HANDLE
SearchBasic( SIPPROTO
*pr
, const PROTOCHAR
* id
)
1020 static HWND
SearchAdvanced( SIPPROTO
*pr
, HWND owner
)
1026 static HWND
CreateExtendedSearchUI( SIPPROTO
*pr
, HWND owner
)
1032 static HANDLE
SearchByEmail( SIPPROTO
*pr
, const PROTOCHAR
* email
)
1034 GHashTable
*query
= g_hash_table_new(NULL
,NULL
);
1036 SIPE_DEBUG_INFO("SearchByEmail: email <%s>", email
);
1038 g_hash_table_insert(query
, "email", (gpointer
)email
);
1040 return (HANDLE
)sipe_search_contact_with_cb( pr
->sip
, query
, sipsimple_search_contact_cb
, pr
);
1044 static HANDLE
SearchByName( SIPPROTO
*pr
, const PROTOCHAR
* nick
, const PROTOCHAR
* firstName
, const PROTOCHAR
* lastName
)
1046 GHashTable
*query
= g_hash_table_new(NULL
,NULL
);
1048 SIPE_DEBUG_INFO("SearchByName: nick <%s> firstname <%s> lastname <%s>", nick
, firstName
, lastName
);
1050 g_hash_table_insert(query
, "givenName", (gpointer
)mir_t2a(firstName
));
1051 g_hash_table_insert(query
, "sn", (gpointer
)mir_t2a(lastName
));
1053 return (HANDLE
)sipe_search_contact_with_cb( pr
->sip
, query
, sipsimple_search_contact_cb
, pr
);
1056 static HANDLE
AddToList( SIPPROTO
*pr
, int flags
, PROTOSEARCHRESULT
* psr
)
1059 gchar
*nick
= g_strdup(mir_t2a(psr
->nick
));
1061 /* Prepend sip: if needed */
1062 if (strncmp("sip:", nick
, 4)) {
1064 nick
= sip_uri_from_name(tmp
);
1068 hContact
= sipe_backend_buddy_find(pr
->sip
, nick
, NULL
);
1074 hContact
= ( HANDLE
)CallService( MS_DB_CONTACT_ADD
, 0, 0 );
1075 CallService( MS_PROTO_ADDTOCONTACT
, (WPARAM
)hContact
, (LPARAM
)pr
->proto
.m_szModuleName
);
1076 sipe_miranda_setString( hContact
, SIP_UNIQUEID
, nick
); // name
1077 if (psr
->lastName
) sipe_miranda_setStringUtf( hContact
, "Nick", mir_t2a(psr
->lastName
) ); // server_alias
1083 static int SetAwayMsg( SIPPROTO
*pr
, int m_iStatus
, const PROTOCHAR
* msg
)
1085 const gchar
*note
= TCHAR2CHAR(msg
);
1087 SIPE_DEBUG_INFO("SetAwayMsg: status <%x> msg <%ls>", m_iStatus
, msg
);
1088 sipe_miranda_setString(pr
, "note", note
);
1090 sipe_core_set_status(pr
->sip
, note
, MirandaStatusToSipe(pr
->proto
.m_iStatus
));
1094 static HANDLE
GetAwayMsg( SIPPROTO
*pr
, HANDLE hContact
)
1096 ForkThread( pr
, ( SipSimpleThreadFunc
)&GetAwayMsgThread
, hContact
);
1100 static HANDLE
SendFile( SIPPROTO
*pr
, HANDLE hContact
, const PROTOCHAR
* szDescription
, PROTOCHAR
** ppszFiles
)
1103 SIPE_DEBUG_INFO("SendFile: desc <%ls>", szDescription
);
1109 * Main Miranda interface
1111 * The structures and functions that allow Miranda to recovnize and load
1115 /* Plugin information structure */
1116 PLUGININFOEX pluginInfo
= {
1117 sizeof(PLUGININFOEX
),
1118 "SIP/Simple Protocol",
1119 PLUGIN_MAKE_VERSION(9,12,19,12),
1120 "Support for SIP/Simple as used by Communicator 2007.",
1121 "Miranda support by Jochen De Smet, for core sipe support see homepage",
1122 "jochen.libsipe@leahnim.org",
1124 "https://sourceforge.net/projects/sipe",
1126 0, //doesn't replace anything built-in
1127 #if defined( _UNICODE )
1128 { 0x842395ed, 0x4e56, 0x40e5, { 0x94, 0x25, 0x28, 0x29, 0xd8, 0xab, 0xae, 0xa5 } } // {842395ED-4E56-40e5-9425-2829D8ABAEA5}
1130 { 0x1ef8af37, 0xdec1, 0x4757, { 0x89, 0x78, 0xe8, 0xad, 0xd0, 0xd8, 0x6e, 0x7f } } // {1EF8AF37-DEC1-4757-8978-E8ADD0D86E7F}
1134 __declspec(dllexport
) PLUGININFOEX
*MirandaPluginInfoEx(DWORD mirandaVersion
)
1136 // Only load for 0.8.0.29 or greater
1137 // We need the core stubs for PS_GETNAME and PS_GETSTATUS
1138 if (mirandaVersion
< PLUGIN_MAKE_VERSION(0, 9, 0, 0))
1142 "SIP/Simple plugin cannot be loaded. It requires Miranda IM 0.9.0.0 or later.",
1143 "SIP/Simple Plugin",
1144 MB_OK
| MB_ICONWARNING
| MB_SETFOREGROUND
| MB_TOPMOST
1152 static const MUUID interfaces
[] = {MIID_PROTOCOL
, MIID_LAST
};
1153 __declspec(dllexport
) const MUUID
* MirandaPluginInterfaces(void)
1158 static PROTO_INTERFACE
* sipsimpleProtoInit( const char* pszProtoName
, const TCHAR
* tszUserName
)
1160 SIPPROTO
*pr
= (SIPPROTO
*)mir_calloc(sizeof(SIPPROTO
));
1161 pr
->proto
.vtbl
= (PROTO_INTERFACE_VTBL
*)mir_calloc(sizeof(PROTO_INTERFACE_VTBL
));
1163 SIPE_DEBUG_INFO("protoname <%s> username <%ls>", pszProtoName
, tszUserName
);
1165 pr
->proto
.m_iVersion
= 2;
1166 pr
->proto
.m_szModuleName
= mir_strdup(pszProtoName
);
1167 pr
->proto
.m_tszUserName
= mir_tstrdup(tszUserName
);
1168 pr
->proto
.m_szProtoName
= mir_strdup(pszProtoName
);
1170 set_buddies_offline(pr
);
1172 /* Fill the function table */
1173 pr
->proto
.vtbl
->GetCaps
= GetCaps
;
1174 pr
->proto
.vtbl
->GetIcon
= GetIcon
;
1175 pr
->proto
.vtbl
->OnEvent
= OnEvent
;
1176 pr
->proto
.vtbl
->SetStatus
= SetStatus
;
1177 pr
->proto
.vtbl
->UserIsTyping
= UserIsTyping
;
1178 pr
->proto
.vtbl
->SendMsg
= sipe_miranda_SendMsg
;
1179 pr
->proto
.vtbl
->RecvMsg
= sipe_miranda_RecvMsg
;
1180 pr
->proto
.vtbl
->AddToListByEvent
= AddToListByEvent
;
1181 pr
->proto
.vtbl
->Authorize
= Authorize
;
1182 pr
->proto
.vtbl
->AuthDeny
= AuthDeny
;
1183 pr
->proto
.vtbl
->AuthRecv
= AuthRecv
;
1184 pr
->proto
.vtbl
->AuthRequest
= AuthRequest
;
1185 pr
->proto
.vtbl
->ChangeInfo
= ChangeInfo
;
1186 pr
->proto
.vtbl
->FileAllow
= FileAllow
;
1187 pr
->proto
.vtbl
->FileCancel
= FileCancel
;
1188 pr
->proto
.vtbl
->FileDeny
= FileDeny
;
1189 pr
->proto
.vtbl
->FileResume
= FileResume
;
1190 pr
->proto
.vtbl
->GetInfo
= GetInfo
;
1191 pr
->proto
.vtbl
->SearchBasic
= SearchBasic
;
1192 pr
->proto
.vtbl
->SearchAdvanced
= SearchAdvanced
;
1193 pr
->proto
.vtbl
->CreateExtendedSearchUI
= CreateExtendedSearchUI
;
1194 pr
->proto
.vtbl
->SearchByEmail
= SearchByEmail
;
1195 pr
->proto
.vtbl
->SearchByName
= SearchByName
;
1196 pr
->proto
.vtbl
->AddToList
= AddToList
;
1197 pr
->proto
.vtbl
->SetAwayMsg
= SetAwayMsg
;
1198 pr
->proto
.vtbl
->GetAwayMsg
= GetAwayMsg
;
1200 /* Setup services */
1201 CreateProtoService(pr
, PS_CREATEACCMGRUI
, &SvcCreateAccMgrUI
);
1203 HookProtoEvent(pr
, ME_OPT_INITIALISE
, &OnOptionsInit
);
1204 HookProtoEvent(pr
, ME_CLIST_GROUPCHANGE
, &OnGroupChange
);
1205 HookProtoEvent(pr
, ME_GC_EVENT
, &OnChatEvent
);
1206 HookProtoEvent(pr
, ME_CLIST_PREBUILDCONTACTMENU
, &OnPreBuildContactMenu
);
1208 return (PROTO_INTERFACE
*)pr
;
1211 static int sipsimpleProtoUninit( PROTO_INTERFACE
* _pr
)
1213 SIPPROTO
*pr
= (SIPPROTO
*)_pr
;
1215 Netlib_CloseHandle(pr
->m_hServerNetlibUser
);
1216 mir_free(pr
->proto
.m_szProtoName
);
1217 mir_free(pr
->proto
.m_szModuleName
);
1218 mir_free(pr
->proto
.m_tszUserName
);
1219 mir_free(pr
->proto
.vtbl
);
1225 __declspec(dllexport
) int Load(PLUGINLINK
*link
)
1227 PROTOCOLDESCRIPTOR pd
= {0};
1228 NETLIBUSER nlu
= {0};
1229 TCHAR descr
[MAX_PATH
];
1234 sipe_miranda_activity_init();
1238 /* Register the module */
1239 pd
.cbSize
= sizeof(pd
);
1240 pd
.szName
= SIPSIMPLE_PROTOCOL_NAME
;
1241 pd
.type
= PROTOTYPE_PROTOCOL
;
1242 pd
.fnInit
= sipsimpleProtoInit
;
1243 pd
.fnUninit
= sipsimpleProtoUninit
;
1244 CallService(MS_PROTO_REGISTERMODULE
, 0, (LPARAM
)&pd
);
1246 /* Protocolwide netlib user for logging */
1247 nlu
.cbSize
= sizeof(nlu
);
1248 nlu
.flags
= NUF_OUTGOING
| NUF_TCHAR
;
1249 nlu
.szSettingsModule
= SIPSIMPLE_PROTOCOL_NAME
;
1250 _sntprintf(descr
, SIZEOF(descr
), TranslateT("%ls logging connection"), CHAR2TCHAR(SIPSIMPLE_PROTOCOL_NAME
) );
1251 nlu
.ptszDescriptiveName
= descr
;
1253 sipe_miranda_debug_netlibuser
= (HANDLE
)CallService(MS_NETLIB_REGISTERUSER
, 0, (LPARAM
)&nlu
);
1258 __declspec(dllexport
) int Unload(void)
1260 Netlib_CloseHandle(sipe_miranda_debug_netlibuser
);
1261 sipe_miranda_activity_destroy();
1262 sipe_core_destroy();
1266 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
,DWORD fdwReason
,LPVOID lpvReserved
)