conf: fix memory leak in process_incoming_invite_conf()
[siplcs.git] / src / miranda / sipe-miranda.c
blob6c412c26b1796d506cdd5f10e9a87938ff1d12ff
1 #define MIRANDA_VER 0x900
3 #include <windows.h>
4 #include <win2k.h>
5 #include <Richedit.h>
6 #include <process.h>
8 #include <glib.h>
10 #include "newpluginapi.h"
11 #include "m_protosvc.h"
12 #include "m_protoint.h"
13 #include "m_system.h"
14 #include "m_database.h"
15 #include "m_langpack.h"
16 #include "m_options.h"
17 #include "m_clist.h"
18 #include "m_chat.h"
19 #include "m_netlib.h"
20 #include "m_protomod.h"
22 #include "libsipe.h"
23 #include "sipe-core.h"
24 #include "sipe.h"
25 #include "sipe-core-private.h"
26 #include "sipe-backend.h"
27 #include "sipe-utils.h"
28 #include "sipe-conf.h"
29 #include "sipe-chat.h"
30 #include "sipe-session.h"
31 #include "miranda-private.h"
32 #include "miranda-resource.h"
34 #define _NI(string) _debuglog( __FILE__, __FUNCTION__, "(%d) ##NOT IMPLEMENTED## %s\n", __LINE__, #string )
36 /* Status identifiers (see also: sipe_status_types()) */
37 #define SIPE_STATUS_ID_UNKNOWN "unset" /* Unset (primitive) */
38 #define SIPE_STATUS_ID_OFFLINE "offline" /* Offline (primitive) */
39 #define SIPE_STATUS_ID_AVAILABLE "available" /* Online */
40 /* PURPLE_STATUS_UNAVAILABLE: */
41 #define SIPE_STATUS_ID_BUSY "busy" /* Busy */
42 #define SIPE_STATUS_ID_BUSYIDLE "busyidle" /* BusyIdle */
43 #define SIPE_STATUS_ID_DND "do-not-disturb" /* Do Not Disturb */
44 #define SIPE_STATUS_ID_IN_MEETING "in-a-meeting" /* In a meeting */
45 #define SIPE_STATUS_ID_IN_CONF "in-a-conference" /* In a conference */
46 #define SIPE_STATUS_ID_ON_PHONE "on-the-phone" /* On the phone */
47 #define SIPE_STATUS_ID_INVISIBLE "invisible" /* Appear Offline */
48 /* PURPLE_STATUS_AWAY: */
49 #define SIPE_STATUS_ID_IDLE "idle" /* Idle/Inactive */
50 #define SIPE_STATUS_ID_BRB "be-right-back" /* Be Right Back */
51 #define SIPE_STATUS_ID_AWAY "away" /* Away (primitive) */
52 /** Reuters status (user settable) */
53 #define SIPE_STATUS_ID_LUNCH "out-to-lunch" /* Out To Lunch */
54 /* ??? PURPLE_STATUS_EXTENDED_AWAY */
55 /* ??? PURPLE_STATUS_MOBILE */
56 /* ??? PURPLE_STATUS_TUNE */
58 /* Plugin information structure */
59 PLUGININFOEX pluginInfo = {
60 sizeof(PLUGININFOEX),
61 "SIP/Simple Protocol",
62 PLUGIN_MAKE_VERSION(9,12,19,12),
63 "Support for SIP/Simple as used by Communicator 2007.",
64 "Miranda support by Jochen De Smet, for core sipe support see homepage",
65 "jochen.libsipe@leahnim.org",
66 "(C)2009-2010",
67 "https://sourceforge.net/projects/sipe",
68 UNICODE_AWARE,
69 0, //doesn't replace anything built-in
70 #if defined( _UNICODE )
71 { 0x842395ed, 0x4e56, 0x40e5, { 0x94, 0x25, 0x28, 0x29, 0xd8, 0xab, 0xae, 0xa5 } } // {842395ED-4E56-40e5-9425-2829D8ABAEA5}
72 #else
73 { 0x1ef8af37, 0xdec1, 0x4757, { 0x89, 0x78, 0xe8, 0xad, 0xd0, 0xd8, 0x6e, 0x7f } } // {1EF8AF37-DEC1-4757-8978-E8ADD0D86E7F}
74 #endif
77 /* Miranda interface globals */
78 #define ENTRY_SIG 0x88442211
80 HINSTANCE hInst;
81 PLUGINLINK* pluginLink;
82 struct MM_INTERFACE mmi;
83 static NETLIBSELECTEX m_select = {0};
84 static GHashTable *m_readhash = NULL;
85 static GHashTable *m_writehash = NULL;
86 static GList *m_entries = NULL;
87 static HANDLE wake_up_semaphore = NULL;
89 static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
91 /* Misc functions */
92 TCHAR _tcharbuf[32768];
93 TCHAR* CHAR2TCHAR( const char *chr ) {
94 #ifdef UNICODE
95 mbstowcs( _tcharbuf, chr, strlen(chr)+1 );
96 return _tcharbuf;
97 #else
98 return chr;
99 #endif
102 char _charbuf[32768];
103 char* TCHAR2CHAR( const TCHAR *tchr ) {
104 #ifdef UNICODE
105 wcstombs( _charbuf, tchr, wcslen(tchr)+1 );
106 return _charbuf;
107 #else
108 return tchr;
109 #endif
112 void CreateProtoService(const SIPPROTO *pr, const char* szService, SipSimpleServiceFunc serviceProc)
114 char str[ MAXMODULELABELLENGTH ];
116 mir_snprintf(str, sizeof(str), "%s%s", pr->proto.m_szModuleName, szService);
117 CreateServiceFunctionObj(str, (MIRANDASERVICEOBJ)*(void**)&serviceProc, pr);
120 HANDLE HookProtoEvent(const SIPPROTO *pr, const char* szEvent, SipSimpleEventFunc pFunc)
122 return HookEventObj(szEvent, (MIRANDAHOOKOBJ)*(void**)&pFunc, pr);
125 void ProtocolAckThread(struct miranda_sipe_ack_args* pArguments)
127 ProtoBroadcastAck(pArguments->pr->proto.m_szModuleName, pArguments->hContact, pArguments->nAckType, pArguments->nAckResult, pArguments->hSequence, pArguments->pszMessage);
129 if (pArguments->nAckResult == ACKRESULT_SUCCESS)
130 SIPE_DEBUG_INFO_NOFORMAT("ProtocolAckThread: Sent ACK");
131 else if (pArguments->nAckResult == ACKRESULT_FAILED)
132 SIPE_DEBUG_INFO_NOFORMAT("ProtocolAckThread: Sent NACK");
134 g_free((gpointer)pArguments->pszMessage);
135 g_free(pArguments);
138 void ForkThread( SIPPROTO *pr, SipSimpleThreadFunc pFunc, void* arg )
141 CloseHandle(( HANDLE )mir_forkthreadowner(( pThreadFuncOwner )*( void** )&pFunc, pr, arg, NULL ));
145 void SendProtoAck( SIPPROTO *pr, HANDLE hContact, DWORD dwCookie, int nAckResult, int nAckType, char* pszMessage)
147 struct miranda_sipe_ack_args* pArgs = (struct miranda_sipe_ack_args*)g_malloc(sizeof(struct miranda_sipe_ack_args)); // This will be freed in the new thread
148 pArgs->hContact = hContact;
149 pArgs->hSequence = (HANDLE)dwCookie;
150 pArgs->nAckResult = nAckResult;
151 pArgs->nAckType = nAckType;
152 pArgs->pszMessage = (LPARAM)g_strdup(pszMessage);
153 pArgs->pr = pr;
155 ForkThread( pr, ( SipSimpleThreadFunc )&ProtocolAckThread, pArgs );
158 void set_buddies_offline(const SIPPROTO* pr)
160 HANDLE hContact;
162 hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
163 while (hContact) {
164 char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
165 if (szProto != NULL && !lstrcmpA(szProto, pr->proto.m_szModuleName)) {
166 if (DBGetContactSettingByte(hContact, pr->proto.m_szModuleName, "ChatRoom", 0) == 0)
167 DBWriteContactSettingWord(hContact, pr->proto.m_szModuleName, "Status", ID_STATUS_OFFLINE);
169 hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
174 const char *MirandaStatusToSipe(int status) {
176 switch (status)
178 case ID_STATUS_OFFLINE:
179 return SIPE_STATUS_ID_OFFLINE;
181 case ID_STATUS_ONLINE:
182 case ID_STATUS_FREECHAT:
183 return SIPE_STATUS_ID_AVAILABLE;
185 case ID_STATUS_ONTHEPHONE:
186 return SIPE_STATUS_ID_ON_PHONE;
188 case ID_STATUS_DND:
189 return SIPE_STATUS_ID_DND;
191 case ID_STATUS_NA:
192 return SIPE_STATUS_ID_AWAY;
194 case ID_STATUS_AWAY:
195 return SIPE_STATUS_ID_BRB;
197 case ID_STATUS_OUTTOLUNCH:
198 return SIPE_STATUS_ID_LUNCH;
200 case ID_STATUS_OCCUPIED:
201 return SIPE_STATUS_ID_BUSY;
203 case ID_STATUS_INVISIBLE:
204 return SIPE_STATUS_ID_INVISIBLE;
206 default:
207 return SIPE_STATUS_ID_UNKNOWN;
212 int SendBroadcast(SIPPROTO *pr, HANDLE hContact,int type,int result,HANDLE hProcess,LPARAM lParam)
214 ACKDATA ack={0};
216 ack.cbSize = sizeof(ACKDATA);
217 ack.szModule = pr->proto.m_szModuleName;
218 ack.hContact = hContact;
219 ack.type = type;
220 ack.result = result;
221 ack.hProcess = hProcess;
222 ack.lParam = lParam;
223 return CallService(MS_PROTO_BROADCASTACK,0,(LPARAM)&ack);
227 /* Protocol interface support functions */
228 void
229 _debuglog(const char *filename, const char *funcname, const char *fmt,...)
231 va_list va;
232 char szText[32768];
233 const char *tmp;
234 FILE *fh;
236 for ( tmp=filename ; *tmp ; tmp++ )
238 if ((*tmp == '/') || (*tmp == '\\')) filename=tmp+1;
241 va_start(va,fmt);
242 vsnprintf(szText,sizeof(szText),fmt,va);
243 va_end(va);
245 if (!fopen_s(&fh,"c:/sipsimple.log","a")) {
246 fprintf(fh, "[%d] %22s %s: %s", _getpid(), filename, funcname, szText);
247 fclose(fh);
251 typedef struct _time_entry
253 guint interval;
254 GSourceFunc function;
255 gpointer data;
256 HANDLE sem;
257 } time_entry;
259 static INT_PTR StartChat(SIPPROTO *pr, WPARAM wParam, LPARAM lParam)
261 HANDLE hContact = (HANDLE)wParam;
262 struct sipe_core_public *sipe_public = pr->sip;
263 struct sipe_core_private *sipe_private = SIPE_CORE_PRIVATE;
265 DBVARIANT dbv;
266 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
267 if (SIPE_CORE_PRIVATE_FLAG_IS(OCS2007))
269 sipe_conf_add(sipe_private, dbv.pszVal);
271 else /* 2005- multiparty chat */
273 gchar *self = sip_uri_self(sipe_private);
274 struct sip_session *session;
276 session = sipe_session_add_chat(sipe_private,
277 NULL,
278 TRUE,
279 self);
280 session->chat_session->backend = sipe_backend_chat_create(SIPE_CORE_PUBLIC,
281 session->chat_session,
282 session->chat_session->title,
283 self);
284 g_free(self);
286 sipe_invite(sipe_private, session, dbv.pszVal, NULL, NULL, NULL, FALSE);
288 DBFreeVariant( &dbv );
289 return TRUE;
292 return FALSE;
295 static void OnModulesLoaded(SIPPROTO *pr)
297 TCHAR descr[MAX_PATH];
298 NETLIBUSER nlu = {0};
299 char service_name[200];
300 GCREGISTER gcr;
301 CLISTMENUITEM mi = {0};
303 SIPE_DEBUG_INFO_NOFORMAT("OnEvent::OnModulesLoaded");
305 nlu.cbSize = sizeof(nlu);
306 nlu.flags = NUF_OUTGOING | NUF_TCHAR;
307 nlu.szSettingsModule = pr->proto.m_szModuleName;
308 _sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), pr->proto.m_tszUserName );
309 nlu.ptszDescriptiveName = descr;
311 pr->m_hServerNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
313 mi.cbSize = sizeof( mi );
314 mi.pszContactOwner = pr->proto.m_szModuleName;
315 mi.pszService = service_name;
317 mir_snprintf(service_name, sizeof(service_name), "%s%s", pr->proto.m_szModuleName, "/StartChat");
318 CreateProtoService(pr, "/StartChat",&StartChat);
319 mi.position=-2000005060;
320 mi.icolibItem = NULL; //GetIconHandle("block");
321 mi.pszName = LPGEN("&Start Chat");
322 mi.flags=0; //CMIF_ICONFROMICOLIB|CMIF_HIDDEN;
323 CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
325 gcr.cbSize = sizeof(gcr);
326 gcr.dwFlags = 0;
327 gcr.pszModule = pr->proto.m_szModuleName;
328 gcr.pszModuleDispName = "Sip/Simple";
329 gcr.iMaxText = 0;
330 gcr.nColors = 0;
332 if (CallService(MS_GC_REGISTER, 0, (LPARAM)&gcr))
334 SIPE_DEBUG_INFO_NOFORMAT("OnEvent::OnModulesLoaded Failed to register chat");
339 static unsigned __stdcall
340 inputloop(void* data)
342 int cnt;
343 struct sipe_miranda_sel_entry *entry;
344 INT_PTR lstRes;
346 m_select.cbSize = sizeof(m_select);
347 m_select.dwTimeout = 6000;
349 while( m_select.hReadConns[0] || m_select.hWriteConns[0])
352 SIPE_DEBUG_INFO_NOFORMAT("About to run select");
353 lstRes = CallService(MS_NETLIB_SELECTEX, 0, (LPARAM)&m_select);
354 SIPE_DEBUG_INFO_NOFORMAT("Back from select");
355 if (lstRes < 0)
357 SIPE_DEBUG_INFO_NOFORMAT("Connection failed while waiting.");
358 break;
360 else if (lstRes == 0)
362 SIPE_DEBUG_INFO_NOFORMAT("Receive Timeout.");
363 lstRes = SOCKET_ERROR;
365 else
368 for ( cnt=0 ; m_select.hReadConns[cnt] ; cnt++ )
370 if (!m_select.hReadStatus[cnt]) continue;
371 SIPE_DEBUG_INFO("FD at position <%d> ready to read.", cnt);
372 entry = (struct sipe_miranda_sel_entry*)g_hash_table_lookup(m_readhash, (gconstpointer)m_select.hReadConns[cnt]);
373 if (!entry)
375 SIPE_DEBUG_INFO_NOFORMAT("ERROR: no read handler found.");
376 continue;
378 SIPE_DEBUG_INFO_NOFORMAT("About to call read function.");
379 entry->func( entry->user_data, (gint)m_select.hReadConns[cnt], SIPE_MIRANDA_INPUT_READ);
380 SIPE_DEBUG_INFO_NOFORMAT("read function returned.");
383 for ( cnt=0 ; m_select.hWriteConns[cnt] ; cnt++ )
385 if (!m_select.hWriteStatus[cnt]) continue;
386 SIPE_DEBUG_INFO("FD at position <%d> ready to write.", cnt);
387 entry = (struct sipe_miranda_sel_entry*)g_hash_table_lookup(m_writehash, (gconstpointer)m_select.hWriteConns[cnt]);
388 if (!entry)
390 SIPE_DEBUG_INFO_NOFORMAT("ERROR: no write handler found.");
391 continue;
393 SIPE_DEBUG_INFO_NOFORMAT("About to call write function.");
394 entry->func( entry->user_data, (gint)m_select.hWriteConns[cnt], SIPE_MIRANDA_INPUT_WRITE);
395 SIPE_DEBUG_INFO_NOFORMAT("write function returned.");
399 /* Free all removed entries */
400 while (m_entries) g_list_delete_link(m_entries, g_list_last(m_entries));
403 return 0;
406 /* libsipe interface functions */
407 static char*
408 miranda_sipe_get_current_status(struct sipe_core_private *sip, const char* name)
410 SIPPROTO *pr = sip->public.backend_private;
411 char *module = pr->proto.m_szModuleName;
412 HANDLE hContact;
414 if (!name)
415 return g_strdup(MirandaStatusToSipe(pr->proto.m_iStatus));
417 hContact = sipe_backend_find_buddy(sip, name, NULL);
418 return g_strdup(MirandaStatusToSipe(DBGetContactSettingWord( hContact, module, "Status", ID_STATUS_OFFLINE )));
421 struct sipe_miranda_sel_entry*
422 sipe_miranda_input_add(HANDLE fd, sipe_miranda_input_condition cond, sipe_miranda_input_function func, gpointer user_data)
424 int rcnt = 0;
425 int wcnt = 0;
426 struct sipe_miranda_sel_entry *entry;
428 if (!m_readhash)
429 m_readhash = g_hash_table_new(NULL, NULL);
431 if (!m_writehash)
432 m_writehash = g_hash_table_new(NULL, NULL);
434 if ((cond != SIPE_MIRANDA_INPUT_READ) && (cond != SIPE_MIRANDA_INPUT_WRITE))
436 SIPE_DEBUG_INFO("Invalid input condition <%d> cond.", cond);
437 return 0;
440 entry = g_new0(struct sipe_miranda_sel_entry,1);
441 entry->sig = ENTRY_SIG;
442 entry->func = func;
443 entry->user_data = user_data;
444 entry->fd = fd;
446 if (cond == SIPE_MIRANDA_INPUT_READ)
448 for ( rcnt=0 ; m_select.hReadConns[rcnt] && m_select.hReadConns[rcnt]!=(HANDLE)fd ; rcnt++ );
449 m_select.hReadConns[rcnt] = (HANDLE)fd;
450 g_hash_table_replace( m_readhash, (gpointer)fd, entry );
452 else if (cond == SIPE_MIRANDA_INPUT_WRITE)
454 for ( wcnt=0 ; m_select.hWriteConns[wcnt] && m_select.hWriteConns[wcnt]!=(HANDLE)fd ; wcnt++ );
455 m_select.hWriteConns[rcnt] = (HANDLE)fd;
456 g_hash_table_replace( m_writehash, (gpointer)fd, entry );
459 if (!(rcnt+wcnt))
460 CloseHandle((HANDLE) mir_forkthreadex( inputloop, NULL, 8192, NULL ));
462 SIPE_DEBUG_INFO_NOFORMAT("Added input handler.");
463 return entry;
466 gboolean
467 sipe_miranda_input_remove(struct sipe_miranda_sel_entry *entry)
469 int cnt;
471 if (!entry)
473 SIPE_DEBUG_INFO_NOFORMAT("Not a valid entry. NULL.");
474 return FALSE;
477 if (entry->sig != ENTRY_SIG)
479 SIPE_DEBUG_INFO("Not a valid entry. Sig is <%08x>.", entry->sig);
480 return FALSE;
483 if (g_hash_table_lookup(m_readhash, (gconstpointer)entry->fd) == entry)
485 for ( cnt=0 ; m_select.hReadConns[cnt] && m_select.hReadConns[cnt]!=(HANDLE)entry->fd ; cnt++ );
486 for ( ; m_select.hReadConns[cnt] ; cnt++ ) m_select.hReadConns[cnt] = m_select.hReadConns[cnt+1];
487 g_hash_table_remove(m_readhash, (gconstpointer)entry->fd);
490 if (g_hash_table_lookup(m_writehash, (gconstpointer)entry->fd) == entry)
492 for ( cnt=0 ; m_select.hWriteConns[cnt] && m_select.hWriteConns[cnt]!=(HANDLE)entry->fd ; cnt++ );
493 for ( ; m_select.hWriteConns[cnt] ; cnt++ ) m_select.hWriteConns[cnt] = m_select.hWriteConns[cnt+1];
494 g_hash_table_remove(m_writehash, (gconstpointer)entry->fd);
497 /* Add it to the list of entries that can be freed after the next select
498 * loop in the thread that's handling the actual select
500 g_list_append( m_entries, entry );
502 return TRUE;
505 static void*
506 miranda_sipe_request_authorization(struct sipe_core_private *sip, const char *who, const char *alias,
507 sipe_request_authorization_cb auth_cb, sipe_request_authorization_cb deny_cb, void *data)
509 SIPPROTO *pr = sip->public.backend_private;
510 CCSDATA ccs;
511 PROTORECVEVENT pre = {0};
512 HANDLE hContact;
513 char* szBlob;
514 char* pCurBlob;
516 hContact = sipe_backend_find_buddy( sip, who, NULL );
517 if (!hContact)
519 hContact = ( HANDLE )CallService( MS_DB_CONTACT_ADD, 0, 0 );
520 CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hContact,( LPARAM )pr->proto.m_szModuleName );
521 DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
522 sipe_miranda_setContactString( pr, hContact, SIP_UNIQUEID, who ); // name
523 sipe_miranda_setContactStringUtf( pr, hContact, "Nick", alias ); // server_alias
526 ccs.szProtoService = PSR_AUTH;
527 ccs.wParam = 0;
528 ccs.lParam = (LPARAM)&pre;
529 ccs.hContact=hContact = hContact;
531 pre.timestamp = time(NULL);
532 pre.lParam=sizeof(DWORD)+sizeof(HANDLE)+strlen(who)+1+strlen(alias)+1+1+5;
534 /*blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ)*/
535 pCurBlob=szBlob=(char *)_alloca(pre.lParam);
536 memset(pCurBlob, 0, sizeof(DWORD)); pCurBlob+=sizeof(DWORD);
537 memcpy(pCurBlob,&hContact,sizeof(HANDLE)); pCurBlob+=sizeof(HANDLE);
538 strcpy((char *)pCurBlob,who); pCurBlob+=strlen((char *)pCurBlob)+1;
539 *pCurBlob = '\0'; pCurBlob++;
540 strcpy((char *)pCurBlob,alias); pCurBlob+=strlen((char *)pCurBlob)+1;
541 *pCurBlob = '\0'; pCurBlob++;
542 *pCurBlob = '\0'; pCurBlob++;
543 pre.szMessage=(char *)szBlob;
545 CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);
547 /* TODO: Store callbacks somewhere since miranda has no way to pass them on */
548 return NULL;
551 static void
552 miranda_sipe_connection_cleanup(struct sipe_core_private *sip)
554 SIPPROTO *pr = sip->public.backend_private;
555 _NIF();
558 static void
559 miranda_sipe_notify_user(SIP_HANDLE sip, const char *name, sipe_message_flags flags, const gchar *message)
561 _NIF();
564 static void
565 __debuglog(sipe_debug_level level, const char *fmt,...)
567 va_list va;
568 char szText[32768];
569 FILE *fh;
570 char *str = DBGetString( NULL, SIPSIMPLE_PROTOCOL_NAME, "debuglog");
572 va_start(va,fmt);
573 vsnprintf(szText,sizeof(szText),fmt,va);
574 va_end(va);
576 if (!str)
577 str = mir_strdup("c:/sipsimple.log");
579 if (!fopen_s(&fh, str, "a")) {
580 fprintf(fh, "<[%d]> %s", _getpid(), szText);
581 fclose(fh);
583 mir_free(str);
587 /****************************************************************************
588 * Struct that defines our interface with libsipe
589 ****************************************************************************/
590 /* Protocol interface functions */
591 HANDLE AddToListByEvent( SIPPROTO *pr, int flags, int iContact, HANDLE hDbEvent )
593 _NIF();
594 SIPE_DEBUG_INFO("AddToListByEvent: flags <%x> iContact <%x>", flags, iContact);
595 return NULL;
598 int Authorize( SIPPROTO *pr, HANDLE hContact )
600 _NIF();
601 SIPE_DEBUG_INFO_NOFORMAT("Authorize");
602 return 0;
605 int AuthDeny( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szReason )
607 _NIF();
608 SIPE_DEBUG_INFO("AuthDeny: reason <%s>", szReason);
609 return 0;
612 int AuthRecv( SIPPROTO *pr, HANDLE hContact, PROTORECVEVENT* evt )
614 _NIF();
615 SIPE_DEBUG_INFO_NOFORMAT("AuthRecv");
616 return 0;
619 int AuthRequest( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szMessage )
621 _NIF();
622 SIPE_DEBUG_INFO("AuthRequest: message <%s>", szMessage);
623 return 0;
626 HANDLE ChangeInfo( SIPPROTO *pr, int iInfoType, void* pInfoData )
628 _NIF();
629 SIPE_DEBUG_INFO("ChangeInfo: infotype <%x>", iInfoType);
630 return NULL;
633 HANDLE FileAllow( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath )
635 _NIF();
636 SIPE_DEBUG_INFO("FileAllow: path <%s>", szPath);
637 return NULL;
640 int FileCancel( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer )
642 _NIF();
643 SIPE_DEBUG_INFO_NOFORMAT("FileCancel");
644 return 0;
647 int FileDeny( SIPPROTO *pr, HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason )
649 _NIF();
650 SIPE_DEBUG_INFO("FileDeny: reason <%s>", szReason);
651 return 0;
654 int FileResume( SIPPROTO *pr, HANDLE hTransfer, int* action, const PROTOCHAR** szFilename )
656 _NIF();
657 SIPE_DEBUG_INFO("FileResume: action <%x>", action);
658 return 0;
661 static void set_if_defined(SIPPROTO *pr, GHashTable *store, HANDLE hContact, sipe_info_fields field, char *label)
663 char *value = (char *)g_hash_table_lookup(store, (gpointer)field);
664 if (value)
665 sipe_miranda_setContactStringUtf(pr, hContact, label, value);
668 static gboolean
669 miranda_sipe_get_info_cb(struct sipe_core_public *sipe_public, const char* uri, GHashTable *results, void* data )
671 SIPPROTO *pr = sipe_public->backend_private;
672 HANDLE hContact = (HANDLE) data;
674 GHashTableIter iter;
675 const char *id, *value;
677 g_hash_table_iter_init( &iter, results);
678 while (g_hash_table_iter_next (&iter, (gpointer *)&id, (gpointer *)&value)) {
679 SIPE_DEBUG_INFO("miranda_sipe_get_info_cb: user info field <%d> = <%s>", id, value ? value : "(none)");
681 set_if_defined(pr, results, hContact, SIPE_INFO_EMAIL, "e-mail");
682 set_if_defined(pr, results, hContact, SIPE_INFO_CITY, "City");
683 set_if_defined(pr, results, hContact, SIPE_INFO_STATE, "State");
684 set_if_defined(pr, results, hContact, SIPE_INFO_COUNTRY, "Country");
685 set_if_defined(pr, results, hContact, SIPE_INFO_COMPANY, "Company");
686 set_if_defined(pr, results, hContact, SIPE_INFO_JOB_TITLE, "CompanyPosition");
687 set_if_defined(pr, results, hContact, SIPE_INFO_WORK_PHONE, "CompanyPhone");
688 set_if_defined(pr, results, hContact, SIPE_INFO_STREET, "CompanyStreet");
689 set_if_defined(pr, results, hContact, SIPE_INFO_ZIPCODE, "CompanyZIP");
690 set_if_defined(pr, results, hContact, SIPE_INFO_DEPARTMENT, "CompanyDepartment");
692 SendBroadcast(pr, hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE) 1, (LPARAM) 0);
693 return TRUE;
696 int GetInfo( SIPPROTO *pr, HANDLE hContact, int infoType )
698 DBVARIANT dbv;
700 SIPE_DEBUG_INFO("GetInfo: infotype <%x>", infoType);
702 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
703 sipe_get_info(pr->sip, dbv.pszVal, miranda_sipe_get_info_cb, hContact);
704 DBFreeVariant( &dbv );
707 return 0;
710 void sipsimple_search_contact_cb( GList *columns, GList *results, GHashTable *opts, void *data )
712 SIPPROTO *pr = (SIPPROTO *)data;
713 GList *row, *col;
714 HANDLE hProcess = g_hash_table_lookup(opts, "searchid");
715 PROTOSEARCHRESULT psr = { 0 };
717 psr.cbSize = sizeof(psr);
719 row = results;
720 while (row)
722 col = (GList*)row->data;
723 psr.nick = (PROTOCHAR*)col->data;
725 col = g_list_next(col);
726 psr.lastName = (PROTOCHAR*)col->data;
728 col = g_list_next(col);
729 /* company */
731 col = g_list_next(col);
732 /* country */
734 col = g_list_next(col);
735 psr.email = (PROTOCHAR*)col->data;
737 row = g_list_next(row);
738 SendBroadcast(pr, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, hProcess, (LPARAM) & psr);
741 SendBroadcast(pr, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, hProcess, 0);
745 HANDLE SearchBasic( SIPPROTO *pr, const PROTOCHAR* id )
747 return NULL;
750 HWND SearchAdvanced( SIPPROTO *pr, HWND owner )
752 _NIF();
753 return NULL;
756 HWND CreateExtendedSearchUI( SIPPROTO *pr, HWND owner )
758 _NIF();
759 return NULL;
762 HANDLE SearchByEmail( SIPPROTO *pr, const PROTOCHAR* email )
764 GHashTable *query = g_hash_table_new(NULL,NULL);
766 SIPE_DEBUG_INFO("SearchByEmail: email <%s>", email);
768 g_hash_table_insert(query, "email", (gpointer)email);
770 return (HANDLE)sipe_search_contact_with_cb( pr->sip, query, sipsimple_search_contact_cb, pr);
774 HANDLE SearchByName( SIPPROTO *pr, const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName)
776 GHashTable *query = g_hash_table_new(NULL,NULL);
778 SIPE_DEBUG_INFO("SearchByName: nick <%s> firstname <%s> lastname <%s>", nick, firstName, lastName);
780 g_hash_table_insert(query, "givenName", (gpointer)mir_t2a(firstName));
781 g_hash_table_insert(query, "sn", (gpointer)mir_t2a(lastName));
783 return (HANDLE)sipe_search_contact_with_cb( pr->sip, query, sipsimple_search_contact_cb, pr);
786 HANDLE AddToList( SIPPROTO *pr, int flags, PROTOSEARCHRESULT* psr )
788 HANDLE hContact;
789 gchar *nick = g_strdup(mir_t2a(psr->nick));
791 /* Prepend sip: if needed */
792 if (strncmp("sip:", nick, 4)) {
793 gchar *tmp = nick;
794 nick = sip_uri_from_name(tmp);
795 g_free(tmp);
798 hContact = sipe_backend_find_buddy(pr->sip, nick, NULL);
799 if (hContact) {
800 g_free(nick);
801 return hContact;
804 hContact = ( HANDLE )CallService( MS_DB_CONTACT_ADD, 0, 0 );
805 CallService( MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)pr->proto.m_szModuleName );
806 sipe_miranda_setString( hContact, SIP_UNIQUEID, nick ); // name
807 if (psr->lastName) sipe_miranda_setStringUtf( hContact, "Nick", mir_t2a(psr->lastName) ); // server_alias
809 g_free(nick);
810 return hContact;
813 int RecvMsg(SIPPROTO *pr, HANDLE hContact, PROTORECVEVENT* pre)
815 // // stop contact from typing - some clients do not sent stop notify
816 // if (CheckContactCapabilities(hContact, CAPF_TYPING))
817 // CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, PROTOTYPE_CONTACTTYPING_OFF);
818 // char *msg = EliminateHtml( pre->szMessage, strlen(pre->szMessage));
819 // mir_free(pre->szMessage);
820 // pre->szMessage = msg;
822 CCSDATA ccs = { hContact, PSR_MESSAGE, 0, ( LPARAM )pre };
823 return CallService( MS_PROTO_RECVMSG, 0, ( LPARAM )&ccs );
826 int SendMsg( SIPPROTO *pr, HANDLE hContact, int flags, const char* msg )
828 DBVARIANT dbv;
830 SIPE_DEBUG_INFO("SendMsg: flags <%x> msg <%s>", flags, msg);
832 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
833 // SendProtoAck( pr, hContact, 1, ACKRESULT_SENTREQUEST, ACKTYPE_MESSAGE, NULL );
834 sipe_im_send(pr->sip, dbv.pszVal, msg, SIPE_MESSAGE_SEND);
835 SendProtoAck( pr, hContact, 1, ACKRESULT_SUCCESS, ACKTYPE_MESSAGE, NULL );
836 DBFreeVariant(&dbv);
837 } else {
838 SendProtoAck( pr, hContact, 1, ACKRESULT_FAILED, ACKTYPE_MESSAGE, NULL );
840 return 1;
843 int UserIsTyping( SIPPROTO *pr, HANDLE hContact, int type )
845 SIPE_DEBUG_INFO("UserIsTyping: type <%x>", type);
846 if (hContact)
848 DBVARIANT dbv;
849 char *name;
851 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
852 name = g_strdup(dbv.pszVal);
853 DBFreeVariant(&dbv);
854 } else {
855 return 1;
858 switch (type) {
859 case PROTOTYPE_SELFTYPING_ON:
860 sipe_core_user_feedback_typing(pr->sip, name);
861 g_free(name);
862 return 0;
864 case PROTOTYPE_SELFTYPING_OFF:
865 /* Not supported anymore? */
866 g_free(name);
867 return 0;
870 g_free(name);
873 return 1;
876 static void sipe_miranda_login(SIPPROTO *pr) {
877 gchar *username = sipe_miranda_getString(pr, "username");
878 gchar *login = sipe_miranda_getString(pr, "login");
879 gchar *email = sipe_miranda_getString(pr, "email");
880 gchar *email_url = sipe_miranda_getString(pr, "email_url");
881 gchar **domain_user = g_strsplit_set(login, "/\\", 2);
882 const gchar *errmsg;
883 gchar *password;
884 char *tmp = (char*)mir_calloc(1024);
886 if (sipe_miranda_getStaticString(pr, NULL, "password", tmp, 1024 )) tmp[0] = '\0';
887 CallService(MS_DB_CRYPT_DECODESTRING, sizeof(tmp),(LPARAM)tmp);
888 password = g_strdup(tmp);
889 mir_free(tmp);
891 pr->sip = sipe_core_allocate(username,
892 domain_user[0], domain_user[1],
893 password,
894 email,
895 email_url,
896 &errmsg);
898 pr->sip->backend_private = pr;
900 mir_free(username);
901 mir_free(login);
902 mir_free(email);
903 mir_free(email_url);
904 g_strfreev(domain_user);
905 g_free(password);
907 if (!pr->sip) {
908 /* FIXME: Flag connection error */
909 return;
912 //sipe_miranda_chat_setup_rejoin(pr);
914 #ifdef HAVE_LIBKRB5
915 // if (purple_account_get_bool(account, "krb5", FALSE))
916 // SIPE_CORE_FLAG_SET(KRB5);
917 #endif
918 // /* @TODO: is this correct?
919 // "sso" is only available when Kerberos support is compiled in */
920 // if (purple_account_get_bool(account, "sso", TRUE))
921 // SIPE_CORE_FLAG_SET(SSO);
923 /* Set display name */
924 sipe_miranda_setStringUtf(pr, "Nick", pr->sip->sip_name);
926 /* Update connection progress */
927 pr->proto.m_iStatus = ID_STATUS_CONNECTING;
928 SendBroadcast(pr, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)pr->proto.m_iStatus, ID_STATUS_CONNECTING);
931 username_split = g_strsplit(purple_account_get_string(account, "server", ""), ":", 2);
932 if (sipe_strequal(transport, "auto")) {
933 type = (username_split[0] == NULL) ?
934 SIPE_TRANSPORT_AUTO : SIPE_TRANSPORT_TLS;
935 } else if (sipe_strequal(transport, "tls")) {
936 type = SIPE_TRANSPORT_TLS;
937 } else {
938 type = SIPE_TRANSPORT_TCP;
941 sipe_core_transport_sip_connect(pr->sip,
942 type,
943 username_split[0],
944 username_split[0] ? username_split[1] : NULL);
945 g_strfreev(username_split);
947 sipe_core_transport_sip_connect(pr->sip,
948 SIPE_TRANSPORT_AUTO,
949 NULL,
950 NULL);
953 static void sipe_miranda_close( SIPPROTO *pr)
955 struct sipe_core_public *sipe_public = pr->sip;
957 if (sipe_public) {
958 sipe_core_deallocate(sipe_public);
960 // sipe_purple_chat_destroy_rejoin(purple_private);
961 // g_free(purple_private);
965 static int SetStatus( SIPPROTO *pr, int iNewStatus )
967 int oldStatus;
968 if (!pr->m_hServerNetlibUser) return 0;
969 if (pr->proto.m_iDesiredStatus == iNewStatus) return 0;
971 oldStatus = pr->proto.m_iStatus;
972 pr->proto.m_iDesiredStatus = iNewStatus;
974 SIPE_DEBUG_INFO("SetStatus: newstatus <%x>", iNewStatus);
976 if (iNewStatus == ID_STATUS_OFFLINE) {
977 sipe_miranda_close(pr);
978 set_buddies_offline(pr);
979 pr->proto.m_iStatus = iNewStatus;
980 SendBroadcast(pr, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, iNewStatus);
981 } else {
982 if (pr->proto.m_iStatus == ID_STATUS_OFFLINE) {
983 sipe_miranda_login(pr);
984 pr->proto.m_iStatus = pr->proto.m_iDesiredStatus;
985 sipe_set_status(pr->sip, MirandaStatusToSipe(iNewStatus));
986 SendBroadcast(pr, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, pr->proto.m_iStatus);
987 } else {
988 pr->proto.m_iStatus = iNewStatus;
989 sipe_set_status(pr->sip, MirandaStatusToSipe(iNewStatus));
990 SendBroadcast(pr, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)pr->proto.m_iStatus, iNewStatus);
996 //Will send an ack with:
997 //type=ACKTYPE_STATUS, result=ACKRESULT_SUCCESS, hProcess=(HANDLE)previousMode, lParam=newMode
998 //when the change completes. This ack is sent for all changes, not just ones
999 //caused by calling this function.
1000 //Note that newMode can be ID_STATUS_CONNECTING<=newMode<ID_STATUS_CONNECTING+
1001 //MAX_CONNECT_RETRIES to signify that it's connecting and it's the nth retry.
1002 //Protocols are initially always in offline mode.
1003 //Non-network-level protocol modules do not have the concept of a status and
1004 //should leave this service unimplemented
1005 //If a protocol doesn't support the specific status mode, it should pick the
1008 return 0;
1011 static DWORD_PTR GetCaps( SIPPROTO *pr, int type, HANDLE hContact )
1013 switch (type) {
1014 case PFLAGNUM_1:
1015 return PF1_IM | PF1_CHAT | PF1_USERIDISEMAIL | PF1_SEARCHBYNAME
1016 | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES;
1018 case PFLAGNUM_2:
1019 return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND
1020 | PF2_OUTTOLUNCH | PF2_ONTHEPHONE;
1022 case PFLAGNUM_3:
1023 return 0;
1025 case PFLAGNUM_4:
1026 return PF4_NOCUSTOMAUTH | PF4_IMSENDUTF | PF4_SUPPORTTYPING;
1028 case PFLAGNUM_5:
1029 return 0;
1031 case PFLAG_UNIQUEIDSETTING:
1032 return (DWORD_PTR) SIP_UNIQUEID;
1033 break;
1034 default:
1035 SIPE_DEBUG_INFO("GetCaps: unknown type <%x>", type);
1039 return 0;
1042 static HICON GetIcon( SIPPROTO *pr, int iconIndex )
1044 SIPE_DEBUG_INFO("GetIcon: unknown index <%x>", iconIndex);
1045 return NULL;
1048 int RecvContacts( SIPPROTO *pr, HANDLE hContact, PROTORECVEVENT* evt )
1050 _NIF();
1051 return 0;
1054 int RecvFile( SIPPROTO *pr, HANDLE hContact, PROTOFILEEVENT* evt )
1056 _NIF();
1057 return 0;
1060 int RecvUrl( SIPPROTO *pr, HANDLE hContact, PROTORECVEVENT* evt )
1062 _NIF();
1063 return 0;
1066 int SendContacts( SIPPROTO *pr, HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList )
1068 _NIF();
1069 SIPE_DEBUG_INFO("SendContacts: flags <%x> ncontacts <%x>", flags, nContacts);
1070 return 0;
1073 HANDLE SendFile( SIPPROTO *pr, HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles )
1075 _NIF();
1076 SIPE_DEBUG_INFO("SendFile: desc <%s>", szDescription);
1077 return 0;
1080 int SendUrl( SIPPROTO *pr, HANDLE hContact, int flags, const char* url )
1082 _NIF();
1083 SIPE_DEBUG_INFO("SendUrl: iflags <%x> url <%s>", flags, url);
1084 return 0;
1087 int SetApparentMode( SIPPROTO *pr, HANDLE hContact, int mode )
1089 _NIF();
1090 SIPE_DEBUG_INFO("SetApparentMode: mode <%x>", mode);
1091 return 0;
1094 HANDLE GetAwayMsg( SIPPROTO *pr, HANDLE hContact )
1096 _NIF();
1097 SIPE_DEBUG_INFO_NOFORMAT("GetAwayMsg");
1098 return NULL;
1101 int RecvAwayMsg( SIPPROTO *pr, HANDLE hContact, int mode, PROTORECVEVENT* evt )
1103 _NIF();
1104 SIPE_DEBUG_INFO("RecvAwayMsg: mode <%x>", mode);
1105 return 0;
1108 int SendAwayMsg( SIPPROTO *pr, HANDLE hContact, HANDLE hProcess, const char* msg )
1110 _NIF();
1111 SIPE_DEBUG_INFO("SendAwayMsg: msg <%s>", msg);
1112 return 0;
1115 int SetAwayMsg( SIPPROTO *pr, int m_iStatus, const PROTOCHAR* msg )
1117 _NIF();
1118 SIPE_DEBUG_INFO("SetAwayMsg: status <%x> msg <%s>", m_iStatus, msg);
1119 return 0;
1122 INT_PTR CALLBACK DlgProcSipSimpleOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1124 static int lock=0;
1126 switch(msg)
1128 case WM_INITDIALOG:
1130 const SIPPROTO *pr = (const SIPPROTO *)lParam;
1131 char *str;
1133 TranslateDialogDefault(hwndDlg);
1135 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
1137 lock++;
1139 str = DBGetString( NULL, SIPSIMPLE_PROTOCOL_NAME, "debuglog");
1140 SetDlgItemTextA(hwndDlg, IDC_DEBUGLOG, str);
1141 SendDlgItemMessage(hwndDlg, IDC_DEBUGLOG, EM_SETLIMITTEXT, 100, 0);
1142 mir_free(str);
1144 str = sipe_miranda_getString(pr, "username");
1145 SetDlgItemTextA(hwndDlg, IDC_HANDLE, str);
1146 SendDlgItemMessage(hwndDlg, IDC_HANDLE, EM_SETLIMITTEXT, 50, 0);
1147 mir_free(str);
1149 str = sipe_miranda_getString(pr, "login");
1150 SetDlgItemTextA(hwndDlg, IDC_LOGIN, str);
1151 SendDlgItemMessage(hwndDlg, IDC_LOGIN, EM_SETLIMITTEXT, 50, 0);
1152 mir_free(str);
1154 str = sipe_miranda_getString(pr, "password");
1155 if (str) CallService(MS_DB_CRYPT_DECODESTRING, strlen(str),(LPARAM)str);
1156 SetDlgItemTextA(hwndDlg, IDC_PASSWORD, str);
1157 SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, 16, 0);
1158 mir_free(str);
1160 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, CB_ADDSTRING, 0, (LPARAM)_T("Auto"));
1161 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, CB_ADDSTRING, 0, (LPARAM)_T("SSL/TLS"));
1162 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, CB_ADDSTRING, 0, (LPARAM)_T("TCP"));
1164 str = sipe_miranda_getString(pr, "transport");
1165 if (!str || !strcmp(str, "auto"))
1166 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, CB_SELECTSTRING, -1, (LPARAM)_T("Auto"));
1167 else if (!strcmp(str, "tls"))
1168 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, CB_SELECTSTRING, -1, (LPARAM)_T("SSL/TLS"));
1169 else if (!strcmp(str, "tcp"))
1170 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, CB_SELECTSTRING, -1, (LPARAM)_T("TCP"));
1172 lock--;
1173 return TRUE;
1176 case WM_COMMAND:
1178 int code = wParam >> 16;
1179 int id = wParam & 0xffff;
1181 if (!lock && (code == EN_CHANGE || code == CBN_SELCHANGE)) {
1182 SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
1184 return TRUE;
1187 case WM_NOTIFY:
1189 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
1191 char buf[100];
1192 TCHAR tbuf[100];
1194 const SIPPROTO *pr = (const SIPPROTO *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1196 GetDlgItemTextA(hwndDlg, IDC_DEBUGLOG, buf, sizeof(buf));
1197 DBWriteContactSettingString(NULL, SIPSIMPLE_PROTOCOL_NAME, "debuglog", buf);
1199 GetDlgItemTextA(hwndDlg, IDC_HANDLE, buf, sizeof(buf));
1200 sipe_miranda_setString(pr, "username", buf);
1202 GetDlgItemTextA(hwndDlg, IDC_LOGIN, buf, sizeof(buf));
1203 sipe_miranda_setString(pr, "login", buf);
1205 GetDlgItemTextA(hwndDlg, IDC_PASSWORD, buf, sizeof(buf));
1206 CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(buf),(LPARAM)buf);
1207 sipe_miranda_setString(pr, "password", buf);
1209 SendDlgItemMessage(hwndDlg, IDC_CONNTYPE, WM_GETTEXT, 100, (LPARAM)tbuf );
1211 if (!_tcscmp(tbuf, _T("Auto")))
1212 sipe_miranda_setString(pr, "transport", "auto");
1213 else if (!_tcscmp(tbuf, _T("SSL/TLS")))
1214 sipe_miranda_setString(pr, "transport", "tls");
1215 else if (!_tcscmp(tbuf, _T("TCP")))
1216 sipe_miranda_setString(pr, "transport", "tcp");
1218 return TRUE;
1220 return TRUE;
1225 return FALSE;
1228 static const char *about_txt =
1229 "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fswiss\\fcharset0 Arial;}{\\f1\\fnil\fcharset2 Symbol;}}"
1230 "{\\*\\generator Msftedit 5.41.15.1507;}\\viewkind4\\uc1\\pard\\b\\f0\\fs24 Sipe" SIPE_VERSION "\\fs20\\par"
1231 "\\b0\\par "
1232 "A third-party plugin implementing extended version of SIP/SIMPLE used by various products:\\par"
1233 "\\pard{\\pntext\\f1\\'B7\\tab}{\\*\\pn\\pnlvlblt\\pnf1\\pnindent0{\\pntxtb\'B7}}\\fi-720"
1234 "\\li720 MS Office Communications Server 2007 (R2)\\par"
1235 "{\\pntext\\f1\\'B7\\tab}MS Live Communications Server 2005/2003\\par"
1236 "{\\pntext\\f1\\'B7\\tab}Reuters Messaging\\par"
1237 "\\pard\\par "
1238 "Home: http://sipe.sourceforge.net\\par "
1239 "Support: http://sourceforge.net/projects/sipe/forums/forum/68853\\par "
1240 "License: GPLv2\\par "
1241 "\\par"
1242 "\\b Authors:\\b0\\par"
1243 " - Anibal Avelar\\par"
1244 " - Gabriel Burt\\par"
1245 " - Stefan Becker\\par"
1246 " - pier11\\par"
1247 "}";
1249 INT_PTR CALLBACK DlgProcSipSimpleOptsAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1252 switch(msg)
1254 case WM_INITDIALOG:
1256 const SIPPROTO *pr = (const SIPPROTO *)lParam;
1257 SETTEXTEX tex;
1259 TranslateDialogDefault(hwndDlg);
1261 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
1263 tex.flags = ST_DEFAULT;
1264 tex.codepage = 437;
1266 SendDlgItemMessage(hwndDlg, IDC_ABOUTSIPE, EM_SETTEXTEX, (WPARAM)&tex, (LPARAM)about_txt );
1271 return FALSE;
1274 int OnOptionsInit(const SIPPROTO *pr, WPARAM wParam, LPARAM lParam)
1276 OPTIONSDIALOGPAGE odp = {0};
1277 HMODULE hUxTheme = 0;
1279 if (IsWinVerXPPlus())
1281 hUxTheme = GetModuleHandleA("uxtheme.dll");
1282 if (hUxTheme)
1283 pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
1286 odp.cbSize = sizeof(odp);
1287 odp.position = -800000000;
1288 odp.hInstance = hInst;
1289 odp.ptszGroup = LPGENT("Network");
1290 odp.dwInitParam = (LPARAM)pr;
1291 odp.ptszTitle = pr->proto.m_tszUserName;
1292 odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
1294 odp.ptszTab = LPGENT("Account");
1295 odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SIPSIMPLE);
1296 odp.pfnDlgProc = DlgProcSipSimpleOpts;
1297 CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
1299 odp.ptszTab = LPGENT("About");
1300 odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SIPSIMPLE_ABOUT);
1301 odp.pfnDlgProc = DlgProcSipSimpleOptsAbout;
1302 CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
1304 #if 0
1306 odp.ptszTab = LPGENT("Features");
1307 odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQFEATURES);
1308 odp.pfnDlgProc = DlgProcIcqFeaturesOpts;
1309 CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
1311 odp.ptszTab = LPGENT("Privacy");
1312 odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICQPRIVACY);
1313 odp.pfnDlgProc = DlgProcIcqPrivacyOpts;
1314 CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
1316 if (bPopUpService)
1318 odp.position = 100000000;
1319 odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_POPUPS);
1320 odp.groupPosition = 900000000;
1321 odp.pfnDlgProc = DlgProcIcqPopupOpts;
1322 odp.ptszGroup = LPGENT("Popups");
1323 odp.ptszTab = NULL;
1324 CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
1326 #endif
1327 return 0;
1330 static int OnEvent( SIPPROTO *pr, PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam )
1332 SIPE_DEBUG_INFO("OnEvent: type <%x>", eventType);
1334 switch (eventType)
1336 case EV_PROTO_ONLOAD:
1337 OnModulesLoaded(pr);
1338 break;
1340 case EV_PROTO_ONREADYTOEXIT:
1341 break;
1343 case EV_PROTO_ONEXIT:
1344 break;
1346 case EV_PROTO_ONRENAME:
1347 break;
1349 case EV_PROTO_ONOPTIONS:
1350 return OnOptionsInit( pr, wParam, lParam );
1351 break;
1353 case EV_PROTO_ONERASE:
1354 break;
1358 return 0;
1362 /* Dialogs */
1363 INT_PTR CALLBACK DlgProcAccMgrUI(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1365 switch(msg)
1367 case WM_INITDIALOG:
1369 const SIPPROTO *pr = (const SIPPROTO *)lParam;
1370 char *str;
1372 TranslateDialogDefault(hwndDlg);
1374 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
1377 str = sipe_miranda_getString(pr, "username");
1378 SetDlgItemTextA(hwndDlg, IDC_HANDLE, str);
1379 mir_free(str);
1381 str = sipe_miranda_getString(pr, "login");
1382 SetDlgItemTextA(hwndDlg, IDC_LOGIN, str);
1383 mir_free(str);
1385 str = sipe_miranda_getString(pr, "password");
1386 if (str) CallService(MS_DB_CRYPT_DECODESTRING, strlen(str),(LPARAM)str);
1387 SetDlgItemTextA(hwndDlg, IDC_PASSWORD, str);
1388 mir_free(str);
1390 SendDlgItemMessage(hwndDlg, IDC_HANDLE, EM_SETLIMITTEXT, 50, 0);
1391 SendDlgItemMessage(hwndDlg, IDC_LOGIN, EM_SETLIMITTEXT, 50, 0);
1392 SendDlgItemMessage(hwndDlg, IDC_PASSWORD, EM_SETLIMITTEXT, 16, 0);
1394 return TRUE;
1397 case WM_COMMAND:
1398 if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetFocus())
1400 switch(LOWORD(wParam))
1402 case IDC_HANDLE:
1403 case IDC_LOGIN:
1404 case IDC_PASSWORD:
1405 SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
1408 break;
1410 case WM_NOTIFY:
1411 if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
1413 char buf[100];
1415 const SIPPROTO *pr = (const SIPPROTO *)lParam;
1417 GetDlgItemTextA(hwndDlg, IDC_HANDLE, buf, sizeof(buf));
1418 sipe_miranda_setString(pr, "username", buf);
1420 GetDlgItemTextA(hwndDlg, IDC_LOGIN, buf, sizeof(buf));
1421 sipe_miranda_setString(pr, "login", buf);
1423 GetDlgItemTextA(hwndDlg, IDC_PASSWORD, buf, sizeof(buf));
1424 CallService(MS_DB_CRYPT_ENCODESTRING, sizeof(buf),(LPARAM)buf);
1425 sipe_miranda_setString(pr, "password", buf);
1427 return TRUE;
1429 break;
1432 return FALSE;
1435 /* Event handlers */
1436 int OnPreBuildContactMenu(const SIPPROTO *pr, WPARAM wParam, LPARAM lParam)
1438 HANDLE hContact = (HANDLE)wParam;
1440 return 0;
1443 int OnChatEvent(const SIPPROTO *pr, WPARAM w, LPARAM l )
1445 GCHOOK *hook = (GCHOOK*)l;
1446 GCDEST *dst = hook->pDest;
1448 if (dst->iType == GC_USER_MESSAGE) {
1449 GCDEST gcd = {0};
1450 GCEVENT gce = {0};
1451 struct sipe_chat_session *session;
1453 gcd.pszModule = pr->proto.m_szModuleName;
1454 gcd.pszID = dst->pszID;
1455 gcd.iType = GC_EVENT_GETITEMDATA;
1457 gce.cbSize = sizeof(gce);
1458 gce.pDest = &gcd;
1461 if ((session = CallService( MS_GC_EVENT, 0, (LPARAM)&gce )) == NULL)
1463 SIPE_DEBUG_WARNING_NOFORMAT("Failed to get chat session");
1464 return 0;
1467 sipe_core_chat_send(pr->sip, session, hook->pszText);
1468 return TRUE;
1469 } else if (dst->iType == GC_USER_PRIVMESS) {
1472 return FALSE;
1475 int OnGroupChange( const SIPPROTO *pr, WPARAM w, LPARAM l )
1477 CLISTGROUPCHANGE *gi = (CLISTGROUPCHANGE*)l;
1478 HANDLE hContact = (HANDLE)w;
1479 DBVARIANT dbv;
1480 char *who;
1482 /* No contact => it's a group add/rename/remove */
1483 if (!hContact)
1485 /* No old name => add */
1486 if (!gi->pszOldName)
1488 return 0;
1490 /* No new name => delete */
1491 else if (!gi->pszNewName)
1493 SIPE_DEBUG_INFO("Removing group <l%s>", gi->pszOldName);
1494 sipe_remove_group(pr->sip, TCHAR2CHAR(gi->pszOldName));
1495 return 0;
1498 SIPE_DEBUG_INFO("Renaming group <%ls> to <%ls>", gi->pszOldName, gi->pszNewName);
1499 sipe_rename_group(pr->sip, TCHAR2CHAR(gi->pszOldName), TCHAR2CHAR(gi->pszNewName));
1500 return 0;
1503 if ( !DBGetContactSettingString( hContact, pr->proto.m_szModuleName, SIP_UNIQUEID, &dbv )) {
1504 who = g_strdup(dbv.pszVal);
1505 DBFreeVariant( &dbv );
1507 if ( !DBGetContactSettingString( hContact, "Clist", "Group", &dbv )) {
1508 SIPE_DEBUG_INFO("Moving buddy <%s> from group <%ls> to group <%ls>", who, dbv.pszVal, gi->pszNewName);
1509 sipe_group_buddy(pr->sip, who, dbv.pszVal, TCHAR2CHAR(gi->pszNewName));
1510 DBFreeVariant( &dbv );
1511 } else {
1512 SIPE_DEBUG_INFO("Really adding buddy <%s> to list in group <%ls>", who, gi->pszNewName);
1513 sipe_add_buddy(pr->sip, who, TCHAR2CHAR(gi->pszNewName));
1516 g_free(who);
1519 return TRUE;
1522 INT_PTR SvcCreateAccMgrUI(const SIPPROTO *pr, WPARAM wParam, LPARAM lParam)
1524 return (INT_PTR)CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_ACCMGRUI), (HWND)lParam, DlgProcAccMgrUI, (LPARAM)pr);
1527 /* Main Miranda interface */
1528 __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion)
1530 // Only load for 0.8.0.29 or greater
1531 // We need the core stubs for PS_GETNAME and PS_GETSTATUS
1532 if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 9, 0, 0))
1534 MessageBoxA(
1535 NULL,
1536 "SIP/Simple plugin cannot be loaded. It requires Miranda IM 0.9.0.0 or later.",
1537 "SIP/Simple Plugin",
1538 MB_OK | MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST
1540 return NULL;
1543 return &pluginInfo;
1546 static const MUUID interfaces[] = {MIID_PROTOCOL, MIID_LAST};
1547 __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
1549 return interfaces;
1552 static PROTO_INTERFACE* sipsimpleProtoInit( const char* pszProtoName, const TCHAR* tszUserName )
1554 SIPPROTO *pr = (SIPPROTO *)mir_calloc(sizeof(SIPPROTO));
1555 pr->proto.vtbl = (PROTO_INTERFACE_VTBL*)mir_calloc(sizeof(PROTO_INTERFACE_VTBL));
1557 SIPE_DEBUG_INFO("protoname <%s> username <%ls>", pszProtoName, tszUserName);
1559 pr->proto.m_iVersion = 2;
1560 pr->proto.m_szModuleName = mir_strdup(pszProtoName);
1561 pr->proto.m_tszUserName = mir_tstrdup(tszUserName);
1562 pr->proto.m_szProtoName = mir_strdup(pszProtoName);
1564 set_buddies_offline(pr);
1566 /* Fill the function table */
1567 pr->proto.vtbl->GetCaps = GetCaps;
1568 pr->proto.vtbl->GetIcon = GetIcon;
1569 pr->proto.vtbl->OnEvent = OnEvent;
1570 pr->proto.vtbl->SetStatus = SetStatus;
1571 pr->proto.vtbl->UserIsTyping = UserIsTyping;
1572 pr->proto.vtbl->SendMsg = SendMsg;
1573 pr->proto.vtbl->RecvMsg = RecvMsg;
1574 pr->proto.vtbl->AddToListByEvent = AddToListByEvent;
1575 pr->proto.vtbl->Authorize = Authorize;
1576 pr->proto.vtbl->AuthDeny = AuthDeny;
1577 pr->proto.vtbl->AuthRecv = AuthRecv;
1578 pr->proto.vtbl->AuthRequest = AuthRequest;
1579 pr->proto.vtbl->ChangeInfo = ChangeInfo;
1580 pr->proto.vtbl->FileAllow = FileAllow;
1581 pr->proto.vtbl->FileCancel = FileCancel;
1582 pr->proto.vtbl->FileDeny = FileDeny;
1583 pr->proto.vtbl->FileResume = FileResume;
1584 pr->proto.vtbl->GetInfo = GetInfo;
1585 pr->proto.vtbl->SearchBasic = SearchBasic;
1586 pr->proto.vtbl->SearchAdvanced = SearchAdvanced;
1587 pr->proto.vtbl->CreateExtendedSearchUI = CreateExtendedSearchUI;
1588 pr->proto.vtbl->SearchByEmail = SearchByEmail;
1589 pr->proto.vtbl->SearchByName = SearchByName;
1590 pr->proto.vtbl->AddToList = AddToList;
1592 /* Setup services */
1593 CreateProtoService(pr, PS_CREATEACCMGRUI, &SvcCreateAccMgrUI );
1595 HookProtoEvent(pr, ME_OPT_INITIALISE, &OnOptionsInit);
1596 HookProtoEvent(pr, ME_CLIST_GROUPCHANGE, &OnGroupChange );
1597 HookProtoEvent(pr, ME_GC_EVENT, &OnChatEvent );
1598 HookProtoEvent(pr, ME_CLIST_PREBUILDCONTACTMENU, &OnPreBuildContactMenu );
1600 return (PROTO_INTERFACE*)pr;
1603 static int sipsimpleProtoUninit( PROTO_INTERFACE* _pr )
1605 SIPPROTO *pr = (SIPPROTO *)_pr;
1607 mir_free(pr->proto.m_szModuleName);
1608 mir_free(pr->proto.m_tszUserName);
1609 mir_free(pr->proto.vtbl);
1610 mir_free(pr);
1612 return 0;
1615 __declspec(dllexport) int Load(PLUGINLINK *link)
1617 PROTOCOLDESCRIPTOR pd = {0};
1619 pluginLink = link;
1621 sipe_core_init("");
1623 mir_getMMI( &mmi );
1625 // Register the module
1626 pd.cbSize = sizeof(pd);
1627 pd.szName = SIPSIMPLE_PROTOCOL_NAME;
1628 pd.type = PROTOTYPE_PROTOCOL;
1629 pd.fnInit = sipsimpleProtoInit;
1630 pd.fnUninit = sipsimpleProtoUninit;
1631 CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd);
1633 return 0;
1636 __declspec(dllexport) int Unload(void)
1638 sipe_core_destroy();
1639 return 0;
1642 BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
1644 hInst = hinstDLL;
1645 return TRUE;