/* Copyright (C) 2005 Ricardo Pescuma Domenecci This is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this file; see the file license.txt. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "commons.h" static char *StatusModeToDbSetting(int status,const char *suffix); ProtocolArray *protocols = NULL; void InitProtocolData() { PROTOACCOUNT **protos; int count; CallService(MS_PROTO_ENUMACCOUNTS, (WPARAM)&count, (LPARAM)&protos); protocols = new ProtocolArray(count); for (int i = 0; i < count; i++) { PROTOACCOUNT* acc = protos[i]; if (acc->szModuleName == NULL || acc->szModuleName[0] == '\0') continue; // Found a protocol Protocol *p = new Protocol(acc->szModuleName, acc->tszAccountName); if ( p->IsValid()) protocols->Add(p); else delete p; } } void DeInitProtocolData() { delete protocols; } // Protocol Class /////////////////////////////////////////////////////////////////////////////////////////// Protocol::Protocol(const char *aName, const TCHAR* descr) { lstrcpynA(name, aName, SIZEOF(name)); lstrcpyn(description, descr, SIZEOF(description)); data_changed = true; // Load services int caps = CallProtoService(name, PS_GETCAPS, PFLAGNUM_1, 0); if ((caps & PF1_IM) && !(!strcmp(aName, "MetaContacts") || !strcmp(aName, "NewsAggr"))) valid = true; else valid = false; if (!valid) return; can_have_listening_to = (ProtoServiceExists(name, PS_SET_LISTENINGTO) != 0); PF3 = CallProtoService(name, PS_GETCAPS, (WPARAM)PFLAGNUM_3, 0); caps = CallProtoService(name, PS_GETCAPS, PFLAGNUM_4, 0); can_have_avatar = (caps & PF4_AVATARS) != 0; can_set_nick = ProtoServiceExists(name, PS_SETMYNICKNAME) != FALSE; // Initial value GetStatus(); GetStatusMsg(); GetNick(); GetAvatar(); } Protocol::~Protocol() { } void Protocol::lcopystr(TCHAR *dest, TCHAR *src, size_t maxlen) { if (lstrcmp(dest, src) != 0) { data_changed = true; lstrcpyn(dest, src, (DWORD)maxlen); } } bool Protocol::IsValid() { return valid; } int Protocol::GetStatus() { INT_PTR iStatus = CallProtoService(name, PS_GETSTATUS, 0, 0); if (iStatus == CALLSERVICE_NOTFOUND) return status = ID_STATUS_OFFLINE; if (iStatus != status) data_changed = true; status = (int)iStatus; // check if protocol supports custom status CUSTOM_STATUS css = { sizeof(css) }; TCHAR tszXStatusName[256], tszXStatusMessage[1024]; if ( ProtoServiceExists(name, PS_GETCUSTOMSTATUSEX)) { // check if custom status is set css.flags = CSSF_TCHAR | CSSF_MASK_STATUS | CSSF_MASK_NAME | CSSF_MASK_MESSAGE | CSSF_DEFAULT_NAME; css.status = &custom_status; css.ptszName = tszXStatusName; css.ptszMessage = tszXStatusMessage; if ( CallProtoService(name, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&css) != 0) tszXStatusMessage[0] = tszXStatusName[0] = 0, custom_status = 0; } else custom_status = 0; // if protocol supports custom status, but it is not set (custom_status will be -1), show normal status if (custom_status < 0) custom_status = 0; if (custom_status == 0) { TCHAR *tmp = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, GSMDF_TCHAR); lcopystr(status_name, tmp, SIZEOF(status_name)); } else { TCHAR *p = (tszXStatusName[0] != 0) ? TranslateTS(tszXStatusName) : TranslateT(""); if (tszXStatusMessage[0]) mir_sntprintf(status_name, SIZEOF(status_name), _T("%s: %s"), p, tszXStatusMessage); else lcopystr(status_name, p, SIZEOF(status_name)); } return status; } void Protocol::SetStatus(int aStatus) { TCHAR status_msg[256]; if (ServiceExists(MS_CS_SETSTATUSEX)) { // :'( // BEGIN From commomstatus.cpp (KeepStatus) int i, count, pCount; PROTOACCOUNT **accs; pCount = 0; ProtoEnumAccounts(&count, &accs); for (i=0; i < count; i++) { if ( CallProtoService(accs[i]->szModuleName,PS_GETCAPS,PFLAGNUM_2,0)==0) continue; pCount++; } // END From commomstatus.cpp (KeepStatus) PROTOCOLSETTINGEX **pse = (PROTOCOLSETTINGEX **) mir_calloc(pCount * sizeof(PROTOCOLSETTINGEX *)); for (i = 0; i < pCount; i++) { pse[i] = (PROTOCOLSETTINGEX *) mir_calloc(sizeof(PROTOCOLSETTINGEX)); pse[i]->szName = ""; } pse[0]->cbSize = sizeof(PROTOCOLSETTINGEX); pse[0]->status = aStatus; pse[0]->szName = name; GetStatusMsg(aStatus, status_msg, SIZEOF(status_msg)); pse[0]->szMsg = status_msg; CallService(MS_CS_SETSTATUSEX, (WPARAM) &pse, 0); for (i = 0; i < pCount; i++) mir_free(pse[i]); mir_free(pse); } else { CallProtoService(name, PS_SETSTATUS, aStatus, 0); if (CanSetStatusMsg(aStatus)) { TCHAR status_msg[MS_MYDETAILS_GETMYSTATUSMESSAGE_BUFFER_SIZE]; GetStatusMsg(aStatus, status_msg, SIZEOF(status_msg)); SetStatusMsg(aStatus, status_msg); } } } bool Protocol::CanGetStatusMsg() { return CanGetStatusMsg(status); } bool Protocol::CanGetStatusMsg(int aStatus) { return (CallProtoService(name, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) != 0 && (PF3 & Proto_Status2Flag(aStatus)); } bool Protocol::CanSetStatusMsg() { return CanSetStatusMsg(GetStatus()); // <- Simple away handled by this one } bool Protocol::CanSetStatusMsg(int aStatus) { return CanGetStatusMsg(aStatus); } void Protocol::GetStatusMsg(int aStatus, TCHAR *msg, size_t msg_size) { if ( !CanGetStatusMsg()) lcopystr(msg, _T(""), msg_size); else if (aStatus == status && ProtoServiceExists(name, PS_GETMYAWAYMSG)) { ptrT tmp((TCHAR*)CallProtoService(name, PS_GETMYAWAYMSG, 0, SGMA_TCHAR)); lcopystr(msg, tmp == NULL ? _T("") : tmp, msg_size); } else if (ServiceExists(MS_AWAYMSG_GETSTATUSMSG)) { ptrT tmp((TCHAR*)CallService(MS_AWAYMSG_GETSTATUSMSGT, (WPARAM)aStatus, 0)); lcopystr(msg, tmp == NULL ? _T("") : tmp, msg_size); } } TCHAR* Protocol::GetStatusMsg() { GetStatusMsg(status, status_message, SIZEOF(status_message)); return status_message; } void Protocol::SetStatusMsg(const TCHAR *message) { SetStatusMsg(GetStatus(), message); } void Protocol::SetStatusMsg(int aStatus, const TCHAR *message) { if ( !CanSetStatusMsg(aStatus)) return; CallProtoService(name, PS_SETAWAYMSGT, (WPARAM)aStatus, (LPARAM)message); } bool Protocol::HasAvatar() { GetAvatar(); return avatar_bmp != NULL; } bool Protocol::CanGetAvatar() { if ( !can_have_avatar) return false; if ( !ServiceExists(MS_AV_GETMYAVATAR)) return false; return true; } void Protocol::GetAvatar() { // See if can get one if ( !CanGetAvatar()) return; avatar_file[0] = '\0'; avatar_bmp = NULL; ace = NULL; // Get HBITMAP from cache ace = (avatarCacheEntry *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM) name); if (ace != NULL) avatar_bmp = ace->hbmPic; data_changed = true; } bool Protocol::CanGetNick() { return ServiceExists(MS_CONTACT_GETCONTACTINFO) != FALSE; } int Protocol::GetNickMaxLength() { if (ProtoServiceExists(name, PS_GETMYNICKNAMEMAXLENGTH)) { int ret = CallProtoService(name, PS_GETMYNICKNAMEMAXLENGTH, 0, 0); if (ret <= 0) ret = MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE; return ret; } else return MS_MYDETAILS_GETMYNICKNAME_BUFFER_SIZE; } TCHAR* Protocol::GetNick() { // See if can get one if ( !CanGetNick()) return NULL; // Get it CONTACTINFO ci = { 0 }; ci.cbSize = sizeof(ci); ci.hContact = NULL; ci.szProto = name; ci.dwFlag = CNF_DISPLAY; #ifdef UNICODE ci.dwFlag |= CNF_UNICODE; #endif if ( !CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) { // CNF_DISPLAY always returns a string type lcopystr(nickname, ci.pszVal, SIZEOF(nickname)); mir_free(ci.pszVal); } else lcopystr(nickname, _T(""), SIZEOF(nickname)); return nickname; } bool Protocol::CanSetNick() { return can_set_nick; } void Protocol::SetNick(const TCHAR *nick) { // See if can get one if ( !CanSetNick()) return; if (nick == NULL) return; // Get it CallProtoService(name, PS_SETMYNICKNAME, SMNN_TCHAR, (LPARAM)nick); } bool Protocol::CanSetAvatar() { return ServiceExists(MS_AV_SETMYAVATAR) != FALSE && ServiceExists(MS_AV_CANSETMYAVATAR) != FALSE && CallService(MS_AV_CANSETMYAVATAR, (WPARAM) name, 0); } void Protocol::SetAvatar(const TCHAR *file_name) { if ( !CanSetAvatar()) return; CallService(MS_AV_SETMYAVATART, (WPARAM) name, (LPARAM) file_name); } bool Protocol::CanGetListeningTo() { return can_have_listening_to; } bool Protocol::CanSetListeningTo() { return CanGetListeningTo() && ServiceExists(MS_LISTENINGTO_ENABLE); } bool Protocol::ListeningToEnabled() { return CanSetListeningTo() && CallService(MS_LISTENINGTO_ENABLED, (WPARAM) name, 0) != 0; } TCHAR * Protocol::GetListeningTo() { if ( !CanGetListeningTo()) { lcopystr(listening_to, _T(""), SIZEOF(listening_to)); return listening_to; } DBVARIANT dbv = {0}; if ( db_get_ts(NULL, name, "ListeningTo", &dbv)) { lcopystr(listening_to, _T(""), SIZEOF(listening_to)); return listening_to; } lcopystr(listening_to, dbv.ptszVal, SIZEOF(listening_to)); db_free(&dbv); return listening_to; } // ProtocolDataArray Class ///////////////////////////////////////////////////////////////////////////// ProtocolArray::ProtocolArray(int max_size) { buffer = (Protocol **) malloc(max_size * sizeof(Protocol*)); buffer_len = 0; GetDefaultNick(); GetDefaultAvatar(); } ProtocolArray::~ProtocolArray() { if (buffer != NULL) { for ( int i = 0 ; i < buffer_len ; i++ ) delete buffer[i]; free(buffer); } } int ProtocolArray::GetSize() { return buffer_len; } void ProtocolArray::Add(Protocol *p) { buffer[buffer_len] = p; buffer_len++; } Protocol * ProtocolArray::Get(int i) { if (i >= buffer_len) return NULL; else return buffer[i]; } Protocol * ProtocolArray::Get(const char *name) { if (name == NULL) return NULL; for ( int i = 0 ; i < buffer_len ; i++ ) { if (strcmp(name, buffer[i]->name) == 0) return buffer[i]; } return NULL; } bool ProtocolArray::CanSetStatusMsgPerProtocol() { return ServiceExists(MS_SA_CHANGESTATUSMSG) != 0; } void ProtocolArray::GetAvatars() { for ( int i = 0 ; i < buffer_len ; i++ ) { buffer[i]->GetAvatar(); } } void ProtocolArray::GetStatusMsgs() { for ( int i = 0 ; i < buffer_len ; i++ ) buffer[i]->GetStatusMsg(); } void ProtocolArray::GetStatuses() { for ( int i = 0 ; i < buffer_len ; i++ ) buffer[i]->GetStatus(); } int ProtocolArray::GetGlobalStatus() { int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); if (status == ID_STATUS_CONNECTING) status = ID_STATUS_OFFLINE; return status; } bool ProtocolArray::CanSetAvatars() { return ServiceExists(MS_AV_SETMYAVATART) != FALSE; } void ProtocolArray::SetAvatars(const TCHAR *file_name) { if ( !CanSetAvatars()) return; CallService(MS_AV_SETMYAVATART, NULL, (WPARAM) file_name); } void ProtocolArray::SetNicks(const TCHAR *nick) { if (nick == NULL || nick[0] == '\0') return; lstrcpyn(default_nick, nick, SIZEOF(default_nick)); db_set_ts(0, MODULE_NAME, SETTING_DEFAULT_NICK, nick); for ( int i = 0 ; i < buffer_len ; i++ ) buffer[i]->SetNick(default_nick); } void ProtocolArray::SetStatus(int aStatus) { CallService(MS_CLIST_SETSTATUSMODE, aStatus, 0); } void ProtocolArray::SetStatusMsgs(const TCHAR *message) { for (int i = ID_STATUS_OFFLINE ; i <= ID_STATUS_IDLE; i++) SetStatusMsgs(i, message); } void ProtocolArray::SetStatusMsgs(int status, const TCHAR *message) { db_set_ts(NULL,"SRAway",StatusModeToDbSetting(status,"Msg"),message); // Save default also if ( !db_get_b(NULL,"SRAway",StatusModeToDbSetting(status,"UsePrev"),0)) db_set_ts(NULL,"SRAway",StatusModeToDbSetting(status,"Default"),message); for ( int i = 0 ; i < buffer_len ; i++ ) if (buffer[i]->status == status) buffer[i]->SetStatusMsg(status, message); } void ProtocolArray::GetDefaultNick() { DBVARIANT dbv; if ( !db_get_ts(0, MODULE_NAME, SETTING_DEFAULT_NICK, &dbv)) { lstrcpyn(default_nick, dbv.ptszVal, SIZEOF(default_nick)); db_free(&dbv); } else default_nick[0] = '\0'; } void ProtocolArray::GetDefaultAvatar() { DBVARIANT dbv; if ( !db_get_ts(0, "ContactPhoto", "File", &dbv)) { lstrcpyn(default_avatar_file, dbv.ptszVal, SIZEOF(default_avatar_file)); db_free(&dbv); } else default_avatar_file[0] = '\0'; } TCHAR* ProtocolArray::GetDefaultStatusMsg() { return GetDefaultStatusMsg(CallService(MS_CLIST_GETSTATUSMODE, 0, 0)); } TCHAR* ProtocolArray::GetDefaultStatusMsg(int status) { default_status_message[0] = '\0'; if (ServiceExists(MS_AWAYMSG_GETSTATUSMSG)) { if (status == ID_STATUS_CONNECTING) status = ID_STATUS_OFFLINE; TCHAR *tmp = (TCHAR*) CallService(MS_AWAYMSG_GETSTATUSMSGT, (WPARAM)status, 0); if (tmp != NULL) { lstrcpyn(default_status_message, tmp, SIZEOF(default_status_message)); mir_free(tmp); } } return default_status_message; } bool ProtocolArray::CanSetListeningTo() { return ServiceExists(MS_LISTENINGTO_ENABLE) != 0; } bool ProtocolArray::ListeningToEnabled() { return CanSetListeningTo() && CallService(MS_LISTENINGTO_ENABLED, 0, 0) != 0; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // Helper functions static char *StatusModeToDbSetting(int status,const char *suffix) { char *prefix; static char str[64]; switch(status) { case ID_STATUS_AWAY: prefix="Away"; break; case ID_STATUS_NA: prefix="Na"; break; case ID_STATUS_DND: prefix="Dnd"; break; case ID_STATUS_OCCUPIED: prefix="Occupied"; break; case ID_STATUS_FREECHAT: prefix="FreeChat"; break; case ID_STATUS_ONLINE: prefix="On"; break; case ID_STATUS_OFFLINE: prefix="Off"; break; case ID_STATUS_INVISIBLE: prefix="Inv"; break; case ID_STATUS_ONTHEPHONE: prefix="Otp"; break; case ID_STATUS_OUTTOLUNCH: prefix="Otl"; break; case ID_STATUS_IDLE: prefix="Idl"; break; default: return NULL; } lstrcpyA(str,prefix); lstrcatA(str,suffix); return str; }