/* Plugin of Miranda IM for communicating with users of the AIM protocol. Copyright (c) 2008-2010 Boris Krasnovskiy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "aim.h" static HANDLE hServiceParseLink; extern OBJLIST g_Instances; static int SingleHexToDecimal(TCHAR c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static TCHAR* url_decode(TCHAR* str) { TCHAR* s = str, *d = str; while(*s) { if (*s == '%') { int digit1 = SingleHexToDecimal(s[1]); if (digit1 != -1) { int digit2 = SingleHexToDecimal(s[2]); if (digit2 != -1) { s += 3; *d++ = (TCHAR)((digit1 << 4) | digit2); continue; } } } *d++ = *s++; } *d = 0; return str; } static INT_PTR ServiceParseAimLink(WPARAM,LPARAM lParam) { if (lParam == 0) return 1; /* sanity check */ TCHAR *arg = (TCHAR*)lParam; /* skip leading prefix */ arg = _tcschr(arg, ':'); if (arg == NULL) return 1; /* parse failed */ for (++arg; *arg == '/'; ++arg); arg = NEWTSTR_ALLOCA(arg); if (g_Instances.getCount() == 0) return 0; CAimProto *proto = &g_Instances[0]; for (int i = 0; i < g_Instances.getCount(); ++i) { if (g_Instances[i].m_iStatus != ID_STATUS_OFFLINE && !IsStatusConnecting(g_Instances[i].m_iStatus)) { proto = &g_Instances[i]; break; } } if (proto == NULL) return 1; /* add user: aim:addbuddy?screenname=NICK&groupname=GROUP send message: aim:goim?screenname=NICK&message=MSG open chatroom: aim:gochat?roomname=ROOM&exchange=NUM */ /* add a contact to the list */ if (!_tcsnicmp(arg, _T("addbuddy?"), 9)) { TCHAR *tok, *tok2; char *sn = NULL, *group = NULL; for (tok = arg + 8; tok != NULL; tok = tok2) { tok2 = _tcschr(++tok, '&'); /* first token */ if (tok2) *tok2 = 0; if (!_tcsnicmp(tok, _T("screenname="), 11) && *(tok + 11) != 0) sn = mir_t2a(url_decode(tok + 11)); if (!_tcsnicmp(tok, _T("groupname="), 10) && *(tok + 10) != 0) group = mir_utf8encodeT(url_decode(tok + 10)); /* group is currently ignored */ } if (sn == NULL) { mir_free(group); return 1; } if (!proto->contact_from_sn(sn)) /* does not yet check if sn is current user */ { MCONTACT hContact = proto->contact_from_sn(sn, true); proto->add_contact_to_group(hContact, group && group[0] ? group : AIM_DEFAULT_GROUP); } mir_free(group); mir_free(sn); return 0; } /* send a message to a contact */ else if (!_tcsnicmp(arg, _T("goim?"), 5)) { TCHAR *tok, *tok2, *msg = NULL; char *sn = NULL; for (tok = arg + 4; tok != NULL; tok = tok2) { tok2 = _tcschr(++tok, '&'); /* first token */ if (tok2) *tok2=0; if (!_tcsnicmp(tok, _T("screenname="), 11) && *(tok + 11) != 0) sn = mir_t2a(url_decode(tok + 11)); if (!_tcsnicmp(tok, _T("message="), 8) && *(tok + 8) != 0) msg = url_decode(tok + 8); } if (sn == NULL) return 1; /* parse failed */ MCONTACT hContact = proto->contact_from_sn(sn, true, true); if (hContact) CallService(MS_MSG_SENDMESSAGET, hContact, (LPARAM)msg); mir_free(sn); return 0; } /* open a chatroom */ else if (!_tcsnicmp(arg, _T("gochat?"), 7)) { TCHAR *tok, *tok2; char *rm = NULL; int exchange = 0; for (tok = arg + 6; tok != NULL; tok = tok2) { tok2 = _tcschr(++tok, '&'); /* first token */ if (tok2) *tok2 = 0; if (!_tcsnicmp(tok, _T("roomname="), 9) && *(tok + 9) != 0) { rm = mir_t2a(url_decode(tok + 9)); for (char *ch = rm; *ch; ++ch) if (*ch == '+') *ch = ' '; } if (!_tcsnicmp(tok, _T("exchange="), 9)) exchange = _ttoi(tok + 9); } if (rm == NULL || exchange <= 0) { mir_free(rm); return 1; } chatnav_param* par = new chatnav_param(rm, (unsigned short)exchange); proto->ForkThread(&CAimProto::chatnav_request_thread, par); mir_free(rm); return 0; } return 1; /* parse failed */ } void aim_links_init(void) { static const char szService[] = "AIM/ParseAimLink"; hServiceParseLink = CreateServiceFunction(szService, ServiceParseAimLink); AssocMgr_AddNewUrlTypeT("aim:", TranslateT("AIM Link Protocol"), hInstance, IDI_AOL, szService, 0); } void aim_links_destroy(void) { DestroyServiceFunction(hServiceParseLink); }