/* CmdLine plugin for Miranda IM Copyright © 2007 Cristian Libotean This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "commonheaders.h" #define STATE_UNKNOWN -1 #define STATE_OFF 0 #define STATE_ON 1 #define STATE_TOGGLE 2 #define PROXY_SOCKS4 1 #define PROXY_SOCKS5 2 #define PROXY_HTTP 3 #define PROXY_HTTPS 4 #define VALUE_UNKNOWN -1 #define VALUE_ERROR 0 #define VALUE_BYTE 1 #define VALUE_WORD 2 #define VALUE_DWORD 3 #define VALUE_STRING 4 #define VALUE_WIDE 5 __inline static int matches(char *command, char *lower) { return ((strcmp(lower, command) == 0) || (strcmp(lower, Translate(command)) == 0)); } int Get2StateValue(char *state) { char lower[512]; STRNCPY(lower, state, sizeof(lower)); _strlwr(lower); //if ((strcmp(lower, "enable") == 0) || (strcmp(lower, "show") == 0) || (strcmp(lower, "on") == 0)) if ((matches("enable", lower)) || (matches("show", lower)) || (matches("on", lower))) { return STATE_ON; } //if ((strcmp(lower, "disable") == 0) || (strcmp(lower, "hide") == 0) || (strcmp(lower, "off") == 0)) if ((matches("disable", lower)) || (matches("hide", lower)) || (matches("off", lower))) { return STATE_OFF; } //if (strcmp(lower, "toggle") == 0) if (matches("toggle", lower)) { return STATE_TOGGLE; } return STATE_UNKNOWN; } int AccountName2Protocol(const char *accountName, OUT char *uniqueProtocolName, size_t length) { int count; PROTOACCOUNT **accounts = NULL; ProtoEnumAccounts(&count, &accounts); STRNCPY(uniqueProtocolName, accountName, length); for (int i = 0; i < count; i++) { if (accounts[i]->bIsEnabled) { if (_stricmp(accountName, accounts[i]->tszAccountName) == 0) { STRNCPY(uniqueProtocolName, accounts[i]->szModuleName, length); return 0; } //the account name may be unicode, try comparing with an unicode string too char *account = mir_u2a((wchar_t *) accounts[i]->tszAccountName); if (_stricmp(accountName, account) == 0) { STRNCPY(uniqueProtocolName, accounts[i]->szModuleName, length); mir_free(account); return 0; } mir_free(account); } } return 1; } void HandleCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (command->ID) { case MIMCMD_STATUS: { HandleStatusCommand(command, argv, argc, reply); break; } case MIMCMD_AWAYMSG: { HandleAwayMsgCommand(command, argv, argc, reply); break; } // //case MIMCMD_XSTATUS: //{ // // break; //} case MIMCMD_POPUPS: { HandlePopupsCommand(command, argv, argc, reply); break; } case MIMCMD_SOUNDS: { HandleSoundsCommand(command, argv, argc, reply); break; } case MIMCMD_CLIST: { HandleClistCommand(command, argv, argc, reply); break; } case MIMCMD_QUIT: { HandleQuitCommand(command, argv, argc, reply); break; } case MIMCMD_EXCHANGE: { HandleExchangeCommand(command, argv, argc, reply); break; } case MIMCMD_YAMN: { HandleYAMNCommand(command, argv, argc, reply); break; } case MIMCMD_CALLSERVICE: { HandleCallServiceCommand(command, argv, argc, reply); break; } case MIMCMD_MESSAGE: { HandleMessageCommand(command, argv, argc, reply); break; } case MIMCMD_DATABASE: { HandleDatabaseCommand(command, argv, argc, reply); break; } case MIMCMD_PROXY: { HandleProxyCommand(command, argv, argc, reply); break; } case MIMCMD_CONTACTS: { HandleContactsCommand(command, argv, argc, reply); break; } case MIMCMD_HISTORY: { HandleHistoryCommand(command, argv, argc, reply); break; } case MIMCMD_VERSION: { HandleVersionCommand(command, argv, argc, reply); break; } case MIMCMD_SETNICKNAME: { HandleSetNicknameCommand(command, argv, argc, reply); break; } case MIMCMD_IGNORE: { HandleIgnoreCommand(command, argv, argc, reply); break; } default: { reply->code = MIMRES_NOTFOUND; mir_snprintf(reply->message, reply->cMessage, Translate("Command '%s' is not currently supported."), command->command); break; } } } void HandleWrongParametersCount(PCommand command, PReply reply) { reply->code = MIMRES_WRONGPARAMSCOUNT; mir_snprintf(reply->message, reply->cMessage, Translate("Wrong number of parameters for command '%s'."), command->command); } void HandleUnknownParameter(PCommand command, char *param, PReply reply) { reply->code = MIMRES_UNKNOWNPARAM; mir_snprintf(reply->message, reply->cMessage, Translate("Unknown parameter '%s' for command '%s'."), param, command->command); } int ParseValueParam(char *param, void *&result) { int ok = VALUE_UNKNOWN; if (strlen(param) > 0) { switch (*param) { case 's': { size_t len = strlen(param); //- 1 + 1 result = (char *) malloc(len * sizeof(char)); STRNCPY((char *) result, param + 1, len); ((char *) result)[len - 1] = 0; ok = VALUE_STRING; break; } case 'w': { size_t len = strlen(param); result = (WCHAR *) malloc(len * sizeof(WCHAR)); char *buffer = (char *) malloc(len * sizeof(WCHAR)); STRNCPY(buffer, param + 1, len); MultiByteToWideChar(CP_ACP, 0, buffer, -1, (WCHAR *) result, (int) len); free(buffer); ok = VALUE_WIDE; break; } case 'b': { result = (char *) malloc(sizeof(char)); long tmp; char *stop; tmp = strtol(param + 1, &stop, 10); * ((char *) result) = tmp; ok = (*stop == 0) ? VALUE_BYTE : VALUE_ERROR; break; } case 'i': { result = (int *) malloc(sizeof(int)); long tmp; char *stop; tmp = strtol(param + 1, &stop, 10); * ((int *) result) = tmp; ok = (*stop == 0) ? VALUE_WORD : VALUE_ERROR; break; } case 'd': { result = (long *) malloc(sizeof(long)); char *stop; * ((long *) result) = strtol(param + 1, &stop, 10); ok = (*stop == 0) ? VALUE_DWORD : VALUE_ERROR; break; } } } return ok; } int ParseStatusParam(char *status) { char *lower = NEWSTR_ALLOCA(status); _strlwr(lower); if ( !strcmp(lower, "offline")) return ID_STATUS_OFFLINE; if ( !strcmp(lower, "online")) return ID_STATUS_ONLINE; if ( !strcmp(lower, "away")) return ID_STATUS_AWAY; if ( !strcmp(lower, "dnd")) return ID_STATUS_DND; if ( !strcmp(lower, "na")) return ID_STATUS_NA; if ( !strcmp(lower, "occupied")) return ID_STATUS_OCCUPIED; if ( !strcmp(lower, "freechat")) return ID_STATUS_FREECHAT; if ( !strcmp(lower, "invisible")) return ID_STATUS_INVISIBLE; if ( !strcmp(lower, "onthephone")) return ID_STATUS_ONTHEPHONE; if ( !strcmp(lower, "outtolunch")) return ID_STATUS_OUTTOLUNCH; return 0; } char *PrettyStatusMode(int status, char *buffer, int size) { *buffer = 0; char *data = (char *) CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, status, 0); if (data) STRNCPY(buffer, data, size); return buffer; } void HandleStatusCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 2: { INT_PTR status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); char pretty[128]; PrettyStatusMode(status, pretty, sizeof(pretty)); const int cPerAccountStatus = 1024 * 5; char *perAccountStatus = (char *) malloc(cPerAccountStatus); perAccountStatus[0] = 0; int count; PROTOACCOUNT **accounts = NULL; char pn[128]; ProtoEnumAccounts(&count, &accounts); for (int i = 0; i < count; i++) { if (accounts[i]->bIsEnabled) { INT_PTR status = CallProtoService(accounts[i]->szModuleName, PS_GETSTATUS, 0, 0); PrettyStatusMode(status, pn, sizeof(pn)); strncat(perAccountStatus, "\n", cPerAccountStatus); char *account = mir_u2a((wchar_t *) accounts[i]->tszAccountName); strncat(perAccountStatus, account, cPerAccountStatus); mir_free(account); strncat(perAccountStatus, ": ", cPerAccountStatus); strncat(perAccountStatus, pn, cPerAccountStatus); } } reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Current global status: %s.%s"), pretty, perAccountStatus); free(perAccountStatus); break; } case 3: { int status = ParseStatusParam(argv[2]); if (status) { INT_PTR old = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); char po[128]; if (ServiceExists(MS_KS_ANNOUNCESTATUSCHANGE)) { announce_status_change(NULL, status, NULL); } PrettyStatusMode(old, po, sizeof(po)); CallService(MS_CLIST_SETSTATUSMODE, status, 0); char pn[128]; PrettyStatusMode(status, pn, sizeof(pn)); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Changed global status to '%s' (previous status was '%s')."), pn, po); } else{ HandleUnknownParameter(command, argv[2], reply); } break; } case 4: { int status = ParseStatusParam(argv[2]); if (status) { char protocol[128]; char *account = argv[3]; AccountName2Protocol(account, protocol, sizeof(protocol)); INT_PTR old = CallProtoService(protocol, PS_GETSTATUS, 0, 0); char po[128]; if (ServiceExists(MS_KS_ANNOUNCESTATUSCHANGE)) { announce_status_change(protocol, status, NULL); } PrettyStatusMode(old, po, sizeof(po)); INT_PTR res = CallProtoService(protocol, PS_SETSTATUS, status, 0); char pn[128]; PrettyStatusMode(status, pn, sizeof(pn)); switch (res) { case 0: { reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Changed '%s' status to '%s' (previous status was '%s')."), account, pn, po); break; } case CALLSERVICE_NOTFOUND: { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("'%s' doesn't seem to be a valid account."), account); break; } default: { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Failed to change status for account '%s' to '%s'."), account, pn); break; } } } else{ HandleUnknownParameter(command, argv[2], reply); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleAwayMsgCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 3: { char *awayMsg = argv[2]; int count = 0; PROTOACCOUNT **accounts = NULL; ProtoEnumAccounts(&count, &accounts); int i; INT_PTR status; INT_PTR res = 0; char *protocol; char buffer[1024]; char pn[128]; for (i = 0; i < count; i++) { if (accounts[i]->bIsEnabled) { protocol = accounts[i]->szModuleName; if ((CallProtoService(protocol, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) != 0) //if the protocol supports away messages { status = CallProtoService(protocol, PS_GETSTATUS, 0, 0); res = CallProtoService(protocol, PS_SETAWAYMSG, status, (LPARAM) awayMsg); PrettyStatusMode(status, pn, sizeof(pn)); if (res) { mir_snprintf(buffer, sizeof(buffer), Translate("Failed to set '%S' status message to '%s' (status is '%s')."), accounts[i]->tszAccountName , awayMsg, pn); } else{ mir_snprintf(buffer, sizeof(buffer), Translate("Successfully set '%S' status message to '%s' (status is '%s')."), accounts[i]->tszAccountName, awayMsg, pn); } } else{ mir_snprintf(buffer, sizeof(buffer), Translate("Account '%S' does not support away messages, skipping."), accounts[i]->tszAccountName); } if (i != 0) { strncat(reply->message, "\n", reply->cMessage); strncat(reply->message, buffer, reply->cMessage); } else{ STRNCPY(reply->message, buffer, reply->cMessage); } } } reply->code = MIMRES_SUCCESS; break; } case 4: { char *awayMsg = argv[2]; char protocol[128]; char *account = argv[3]; AccountName2Protocol(account, protocol, sizeof(protocol)); INT_PTR res = 0; char pn[128]; if ((res = CallProtoService(protocol, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) != 0) //if the protocol supports away messages { INT_PTR status = CallProtoService(protocol, PS_GETSTATUS, 0, 0); res = CallProtoService(protocol, PS_SETAWAYMSG, status, (LPARAM) awayMsg); PrettyStatusMode(status, pn, sizeof(pn)); } else{ if (CallProtoService(protocol, PS_GETSTATUS, 0, 0) == CALLSERVICE_NOTFOUND) { res = CALLSERVICE_NOTFOUND; } else { res = -2; } } switch (res) { case 0: { reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Changed '%s' status message to '%s' (status is '%s')."), account, awayMsg, pn); break; } case CALLSERVICE_NOTFOUND: { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("'%s' doesn't seem to be a valid account."), account); break; } case -2: { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Account '%s' does not support away messages, skipping."), account); break; } default: { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Failed to change status message for account '%s' to '%s' (status is '%s')."), account, awayMsg, pn); break; } } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void Set2StateReply(PReply reply, int state, int failure, char *successTrue, char *failureTrue, char *successFalse, char *failureFalse) { if (state) { if (failure) { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate(failureTrue)); } else{ reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate(successTrue)); } } else{ if (failure) { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate(failureFalse)); } else{ reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate(successFalse)); } } } void HandlePopupsCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 2: { int state = CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0); Set2StateReply(reply, state, 0, "Popups are currently enabled.", "", "Popups are currently disabled.", ""); break; } case 3: { int failure; int state = 0; int error = 0; switch (Get2StateValue(argv[2])) { case STATE_ON: { failure = CallService(MS_POPUP_QUERY, PUQS_ENABLEPOPUPS, 0); state = TRUE; break; } case STATE_OFF: { failure = CallService(MS_POPUP_QUERY, PUQS_DISABLEPOPUPS, 0); state = FALSE; break; } case STATE_TOGGLE: { int state = CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0); failure = CallService(MS_POPUP_QUERY, (state) ? PUQS_DISABLEPOPUPS : PUQS_ENABLEPOPUPS, 0); state = 1 - state; break; } default: { HandleUnknownParameter(command, argv[2], reply); error = 1; break; } } if (!error) { Set2StateReply(reply, state, failure, "Popups were enabled successfully.", "Popups could not be enabled.", "Popups were disabled successfully.", "Popups could not be disabled."); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleSoundsCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 2: { int state = CallService(MS_POPUP_QUERY, PUQS_GETSTATUS, 0); Set2StateReply(reply, state, 0, "Sounds are currently enabled.", "", "Sounds are currently disabled.", ""); break; } case 3: { int failure; int state = 0; int error = 0; switch (Get2StateValue(argv[2])) { case STATE_ON: { failure = 0; db_set_b(NULL, "Skin", "UseSound", 1); state = TRUE; break; } case STATE_OFF: { failure = 0; db_set_b(NULL, "Skin", "UseSound", 0); state = FALSE; break; } case STATE_TOGGLE: { state = db_get_b(NULL, "Skin", "UseSound", 1); failure = 0; state = 1 - state; db_set_b(NULL, "Skin", "UseSound", state); break; } default: { HandleUnknownParameter(command, argv[2], reply); error = 1; break; } } if (!error) { Set2StateReply(reply, state, failure, "Sounds were enabled successfully.", "Sounds could not be enabled.", "Sounds were disabled successfully.", "Sounds could not be disabled."); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleClistCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 2: { HWND hClist = (HWND) CallService(MS_CLUI_GETHWND, 0, 0); int state = IsWindowVisible(hClist); Set2StateReply(reply, state, 0, "Contact list is currectly shown.", "", "Contact list is currently hidden.", ""); break; } case 3: { int failure; int state = 0; int error = 0; HWND hClist = (HWND) CallService(MS_CLUI_GETHWND, 0, 0); switch (Get2StateValue(argv[2])) { case STATE_ON: { failure = 0; ShowWindow(hClist, SW_SHOW); state = TRUE; break; } case STATE_OFF: { failure = 0; ShowWindow(hClist, SW_HIDE); state = FALSE; break; } case STATE_TOGGLE: { state = IsWindowVisible(hClist); failure = 0; state = 1 - state; ShowWindow(hClist, (state) ? SW_SHOW : SW_HIDE); break; } default: { HandleUnknownParameter(command, argv[2], reply); error = 1; break; } } if (!error) { Set2StateReply(reply, state, failure, "Contact list was shown successfully.", "Contact list could not be shown.", "Contact list was hidden successfully.", "Contact list could not be hidden."); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleQuitCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 2: { CallService("CloseAction", 0, 0); //try another quit method HWND hWndMiranda = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); PostMessage(hWndMiranda, WM_COMMAND, ID_ICQ_EXIT, 0); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, "Issued a quit command."); break; } case 3: { char lower[128]; STRNCPY(lower, argv[2], sizeof(lower)); _strlwr(lower); if (strcmp(lower, "wait") == 0) { CallService("CloseAction", 0, 0); //try another quit method HWND hWndMiranda = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); PostMessage(hWndMiranda, WM_COMMAND, ID_ICQ_EXIT, 0); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, "Issued a quit and wait command."); SetEvent(heServerBufferFull); bWaitForUnload = 1; while (bWaitForUnload) { Sleep(250); //wait for Miranda to quit. } } else{ HandleUnknownParameter(command, argv[2], reply); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleExchangeCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 3: { char lower[128]; STRNCPY(lower, argv[2], sizeof(lower)); _strlwr(lower); if (strcmp(lower, "check") == 0) { if (ServiceExists(MS_EXCHANGE_CHECKEMAIL)) { CallService(MS_EXCHANGE_CHECKEMAIL, 0, 0); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Issued check email command to Exchange plugin.")); } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Exchange plugin is not running.")); } } else{ HandleUnknownParameter(command, argv[2], reply); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleYAMNCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 3: { char lower[128]; STRNCPY(lower, argv[2], sizeof(lower)); _strlwr(lower); if (strcmp(lower, "check") == 0) { if (ServiceExists(MS_YAMN_FORCECHECK)) { CallService(MS_YAMN_FORCECHECK, 0, 0); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Issued check email command to YAMN plugin.")); } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("YAMN plugin is not running.")); } } else{ HandleUnknownParameter(command, argv[2], reply); } break; } default: { HandleWrongParametersCount(command, reply); break; } } } void HandleCallServiceCommand(PCommand command, TArgument *argv, int argc, PReply reply) { switch (argc) { case 5: { char *service = argv[2]; if (ServiceExists(service)) { void *wParam = NULL; void *lParam = NULL; INT_PTR res1 = ParseValueParam(argv[3], wParam); INT_PTR res2 = ParseValueParam(argv[4], lParam); if ((res1 != 0) && (res2 != 0)) { //very dangerous but the user asked INT_PTR res = CallService(service, ((res1 == 1) ? *((long *) wParam) : (WPARAM) wParam), (LPARAM) ((res2 == 1) ? *((long *) lParam) : (LPARAM) lParam)); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("CallService call successful: service '%s' returned %p."), service, res); } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Invalid parameter '%s' passed to CallService command."), (wParam) ? argv[4] : argv[3]); } if (wParam) { free(wParam); } if (lParam) { free(lParam); } } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Service '%s' does not exist."), service); } break; } default: { HandleWrongParametersCount(command, reply); } } } HANDLE ParseContactParam(char *contact) { char name[512]; char account[128]; char protocol[128]; char *p = strrchr(contact, ':'); HANDLE hContact = NULL; if (p) { *p = 0; STRNCPY(name, contact, p - contact + 1); STRNCPY(account, p + 1, sizeof(account)); *p = ':'; AccountName2Protocol(account, protocol, sizeof(protocol)); hContact = GetContactFromID(name, protocol); } else{ hContact = GetContactFromID(contact, (char *) NULL); } return hContact; } void HandleMessageCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc >= 4) { char *message = argv[argc - 1]; //get the message int i; char *contact; char buffer[1024]; HANDLE hContact; HANDLE hProcess = NULL; ACKDATA *ack = NULL; for (i = 2; i < argc - 1; i++) { contact = argv[i]; hContact = ParseContactParam(contact); if (hContact) { bShouldProcessAcks = TRUE; hProcess = (HANDLE) CallContactService(hContact, PSS_MESSAGE, 0, (LPARAM) message); const int MAX_COUNT = 60; int counter = 0; while (((ack = GetAck(hProcess)) == NULL) && (counter < MAX_COUNT)) { SleepEx(250, TRUE); counter++; } bShouldProcessAcks = FALSE; if (counter < MAX_COUNT) { if (ack->result == ACKRESULT_SUCCESS) { if (ack->szModule) { mir_snprintf(buffer, sizeof(buffer), Translate("Message sent to '%s'."), contact); DBEVENTINFO e = {0}; char module[128]; e.cbSize = sizeof(DBEVENTINFO); e.eventType = EVENTTYPE_MESSAGE; e.flags = DBEF_SENT; e.pBlob = (PBYTE) message; e.cbBlob = (DWORD) strlen((char *) message) + 1; STRNCPY(module, ack->szModule, sizeof(module)); e.szModule = module; e.timestamp = (DWORD) time(NULL); db_event_add(ack->hContact, &e); } else mir_snprintf(buffer, sizeof(buffer), Translate("Message to '%s' was marked as sent but the account seems to be offline"), contact); } else mir_snprintf(buffer, sizeof(buffer), Translate("Could not send message to '%s'."), contact); } else mir_snprintf(buffer, sizeof(buffer), Translate("Timed out while waiting for acknowledgement for contact '%s'."), contact); } else mir_snprintf(buffer, sizeof(buffer), Translate("Could not find contact handle for contact '%s'."), contact); if (i == 3) { STRNCPY(reply->message, buffer, reply->cMessage); } else { strncat(reply->message, "\n", reply->cMessage); strncat(reply->message, buffer, reply->cMessage); } } } else{ HandleWrongParametersCount(command, reply); } } int ParseDatabaseData(DBVARIANT *var, char *buffer, int size, int free) { int ok = 1; switch (var->type) { case DBVT_BYTE: { mir_snprintf(buffer, size, "byte:%d", var->bVal); break; } case DBVT_WORD: { mir_snprintf(buffer, size, "word:%d", var->wVal); break; } case DBVT_DWORD: { mir_snprintf(buffer, size, "dword:%ld", var->dVal); break; } case DBVT_ASCIIZ: { mir_snprintf(buffer, size, "string:'%s'", var->pszVal); if (free) { mir_free(var->pszVal); } break; } case DBVT_WCHAR: { mir_snprintf(buffer, size, "wide string:'%S'", var->pwszVal); if (free) { mir_free(var->pwszVal); } break; } case DBVT_UTF8: { mir_snprintf(buffer, size, "utf8:'%s'", var->pszVal); if (free) { mir_free(var->pszVal); } } case DBVT_BLOB: { mir_snprintf(buffer, size, "blob:N/A"); if (free) { mir_free(var->pbVal); } break; } default: { ok = 0; mir_snprintf(buffer, size, "unknown value"); break; } } return ok; } void HandleDatabaseCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc >= 3) //we have something to parse { char dbcmd[128]; STRNCPY(dbcmd, argv[2], sizeof(dbcmd)); dbcmd[sizeof(dbcmd) - 1] = 0; _strlwr(dbcmd); if (strcmp(dbcmd, "delete") == 0) { if (argc == 5) { char *module = argv[3]; char *key = argv[4]; db_unset(NULL, module, key); reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Setting '%s/%s' deleted."), module, key); } else{ HandleWrongParametersCount(command, reply); } } else{ if (strcmp(dbcmd, "set") == 0) { if (argc == 6) { char *module = argv[3]; char *key = argv[4]; int ok = 1; void *value = NULL; char *wrote = NULL; int type = ParseValueParam(argv[5], value); switch (type) { case VALUE_STRING: { db_set_s(NULL, module, key, (char *) value); wrote = "string"; break; } case VALUE_BYTE: { db_set_b(NULL, module, key, (* (char *) value)); wrote = "byte"; break; } case VALUE_WORD: { db_set_w(NULL, module, key, (* (WORD *) value)); wrote = "word"; break; } case VALUE_DWORD: { db_set_dw(NULL, module, key, (* (DWORD *) value)); wrote = "dword"; break; } case VALUE_WIDE: { db_set_ws(NULL, module, key, (WCHAR *) value); wrote = "wide string"; break; } default: { HandleUnknownParameter(command, argv[5], reply); ok = 0; break; } } if (ok) { reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Wrote '%s:%s' to database entry '%s/%s'."), wrote, argv[5] + 1, module, key); } if (value) { free(value); } } else{ HandleWrongParametersCount(command, reply); } } else{ if (strcmp(dbcmd, "get") == 0) { if (argc == 5) { char *module = argv[3]; char *key = argv[4]; DBVARIANT var = {0}; int res = db_get(NULL, module, key, &var); if (!res) { char buffer[1024]; if (ParseDatabaseData(&var, buffer, sizeof(buffer), TRUE)) { reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("'%s/%s' - %s."), module, key, buffer); } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Could not retrieve setting '%s/%s': %s."), module, key, buffer); } } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Setting '%s/%s' was not found."), module, key); } } else{ HandleWrongParametersCount(command, reply); } } else{ HandleUnknownParameter(command, dbcmd, reply); } } } } else{ HandleWrongParametersCount(command, reply); } } int ParseProxyType(char *type) { char lower[128]; STRNCPY(lower, type, sizeof(lower)); lower[sizeof(lower) - 1] = 0; _strlwr(lower); int proxy = 0; if (strcmp(lower, "socks4") == 0) { proxy = PROXY_SOCKS4; } else{ if (strcmp(lower, "socks5") == 0) { proxy = PROXY_SOCKS5; } else{ if (strcmp(lower, "http") == 0) { proxy = PROXY_HTTP; } else{ if (strcmp(lower, "https") == 0) { proxy = PROXY_HTTPS; } } } } return proxy; } char *PrettyProxyType(int type, char *buffer, int size) { char *pretty = ""; switch (type) { case PROXY_SOCKS4: { pretty = "SOCKS4"; break; } case PROXY_SOCKS5: { pretty = "SOCKS5"; break; } case PROXY_HTTP: { pretty = "HTTP"; break; } case PROXY_HTTPS: { pretty = "HTTPS"; break; } default: { pretty = "Unknown"; break; } } STRNCPY(buffer, pretty, size); return buffer; } void HandleProtocolProxyCommand(PCommand command, TArgument *argv, int argc, PReply reply, char *module, char *protocol) { char proxycmd[128]; STRNCPY(proxycmd, argv[3], sizeof(proxycmd)); proxycmd[sizeof(proxycmd) - 1] = 0; _strlwr(proxycmd); char buffer[1024]; int ok = 1; if (strcmp(proxycmd, "status") == 0) {//status command switch (argc) { case 4: { int value = db_get_b(NULL, module, "NLUseProxy", 0); reply->code = MIMRES_SUCCESS; mir_snprintf(buffer, sizeof(buffer), "%s proxy status is %s", protocol, (value) ? "enabled" : "disabled"); break; } case 5: { int state = Get2StateValue(argv[4]); switch (state) { case STATE_OFF: { db_set_b(NULL, module, "NLUseProxy", 0); reply->code = MIMRES_SUCCESS; mir_snprintf(buffer, sizeof(buffer), Translate("'%s' proxy was disabled."), protocol); break; } case STATE_ON: { db_set_b(NULL, module, "NLUseProxy", 1); reply->code = MIMRES_SUCCESS; mir_snprintf(buffer, sizeof(buffer), Translate("'%s' proxy was enabled."), protocol); break; } case STATE_TOGGLE: { int value = db_get_b(NULL, module, "NLUseProxy", 0); value = 1 - value; db_set_b(NULL, module, "NLUseProxy", value); reply->code = MIMRES_SUCCESS; mir_snprintf(buffer, sizeof(buffer), (value) ? Translate("'%s' proxy was enabled.") : Translate("'%s' proxy was disabled.")); break; } default: { HandleUnknownParameter(command, argv[4], reply); break; } } break; } default: { HandleWrongParametersCount(command, reply); ok = 0; break; } } } else{ if (strcmp(proxycmd, "server") == 0) { switch (argc) { case 4: { char host[256]; int port; char type[256]; GetStringFromDatabase(NULL, module, "NLProxyServer", "", host, sizeof(host)); port = db_get_w(NULL, module, "NLProxyPort", 0); PrettyProxyType(db_get_b(NULL, module, "NLProxyType", 0), type, sizeof(type)); reply->code = MIMRES_SUCCESS; mir_snprintf(buffer, sizeof(buffer), Translate("%s proxy server: %s %s:%d."), protocol, type, host, port); break; } case 7: { int type = ParseProxyType(argv[4]); char *host = argv[5]; long port; char *stop = NULL; port = strtol(argv[6], &stop, 10); if ((*stop == 0) && (type > 0)) { db_set_s(NULL, module, "NLProxyServer", host); db_set_w(NULL, module, "NLProxyPort", port); db_set_b(NULL, module, "NLProxyType", type); reply->code = MIMRES_SUCCESS; mir_snprintf(buffer, sizeof(buffer), Translate("%s proxy set to %s %s:%d."), protocol, argv[4], host, port); } else { reply->code = MIMRES_FAILURE; mir_snprintf(buffer, sizeof(buffer), Translate("%s The port or the proxy type parameter is invalid."), protocol); } break; } default: { HandleWrongParametersCount(command, reply); ok = 0; break; } } } else{ ok = 0; HandleUnknownParameter(command, proxycmd, reply); } } if (ok) { if (strlen(reply->message) > 0) { strncat(reply->message, "\n", reply->cMessage); strncat(reply->message, buffer, reply->cMessage); reply->message[reply->cMessage - 1] = 0; } else{ mir_snprintf(reply->message, reply->cMessage, buffer); } } } void HandleProxyCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc >= 4) { char account[128]; char protocol[128]; STRNCPY(account, argv[2], sizeof(account)); account[sizeof(account) - 1] = 0; AccountName2Protocol(account, protocol, sizeof(protocol)); int count = 0; PROTOACCOUNT **accounts = NULL; ProtoEnumAccounts(&count, &accounts); int i; int global = (strcmp(protocol, "GLOBAL") == 0); reply->message[0] = 0; int found = 0; if (global) { HandleProtocolProxyCommand(command, argv, argc, reply, "Netlib", protocol); found = 1; } char *match; for (i = 0; i < count; i++) { if (accounts[i]->bIsEnabled) { match = accounts[i]->szModuleName; if ((global) || (strcmp(protocol, match) == 0)) { HandleProtocolProxyCommand(command, argv, argc, reply, match, match); found = 1; } } } if (!found) { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("'%s' doesn't seem to be a valid account."), account); } } else{ HandleWrongParametersCount(command, reply); } } int ContactMatchSearch(HANDLE hContact, char *contact, char *id, char *account, TArgument *argv, int argc) { int matches = 1; int i; char lwrName[2048] = "\0"; char lwrAccount[128] = "\0"; char lwrKeyword[512] = "\0"; char lwrID[512] = "\0"; char *pos; STRNCPY(lwrName, contact, sizeof(lwrName)); STRNCPY(lwrAccount, account, sizeof(lwrAccount)); if (id) { STRNCPY(lwrID, id, sizeof(lwrID)); } _strlwr(lwrName); _strlwr(lwrAccount); _strlwr(lwrID); for (i = 0; i < argc; i++) { STRNCPY(lwrKeyword, argv[i], sizeof(lwrKeyword)); _strlwr(lwrKeyword); pos = strstr(lwrKeyword, "account:"); if (pos) { pos += 8; if (strstr(lwrAccount, pos) == NULL) { matches = 0; break; } } else{ pos = strstr(lwrKeyword, "status:"); if (pos) { int searchStatus = ParseStatusParam(pos + 7); char protocol[128]; AccountName2Protocol(account, protocol, sizeof(protocol)); WORD contactStatus = db_get_w(hContact, protocol, "Status", ID_STATUS_ONLINE); if (searchStatus != contactStatus) { matches = 0; break; } } else{ pos = strstr(lwrKeyword, "id:"); if (pos) { pos += 3; if (strstr(lwrID, pos) == NULL) { matches = 0; break; } } else{ if ((strstr(lwrName, lwrKeyword) == NULL)) { matches = 0; break; } } } } } return matches; } DWORD WINAPI OpenMessageWindowThread(void *data) { HANDLE hContact = (HANDLE) data; if (hContact) { CallServiceSync(MS_MSG_SENDMESSAGE, (WPARAM) hContact, 0); CallServiceSync("SRMsg/LaunchMessageWindow", (WPARAM) hContact, 0); } return 0; } void HandleContactsCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc >= 3) { if (_stricmp(argv[2], "list") == 0) { char buffer[1024]; char protocol[128]; int count = 0; reply->code = MIMRES_SUCCESS; for (HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { GetContactProto(hContact, protocol, sizeof(protocol)); char *contact = GetContactName(hContact, protocol); char *id = GetContactID(hContact, protocol); if (ContactMatchSearch(hContact, contact, id, protocol, &argv[3], argc - 3)) { mir_snprintf(buffer, sizeof(buffer), "%s:[%s]:%s (%08d)", contact, id, protocol, hContact); if (count) { strncat(reply->message, "\n", reply->cMessage); strncat(reply->message, buffer, reply->cMessage); } else{ STRNCPY(reply->message, buffer, reply->cMessage); } if (strlen(reply->message) > 4096) { SetEvent(heServerBufferFull); Sleep(750); //wait a few milliseconds for the event to be processed count = 0; *reply->message = 0; } count++; } free(contact); free(id); } } else{ if (_stricmp(argv[2], "open") == 0) { if (argc > 3) { char protocol[128]; reply->code = MIMRES_SUCCESS; *reply->message = 0; for (HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { GetContactProto(hContact, protocol, sizeof(protocol)); char *contact = GetContactName(hContact, protocol); char *id = GetContactID(hContact, protocol); if (ContactMatchSearch(hContact, contact, id, protocol, &argv[3], argc - 3)) { DWORD threadID; HANDLE thread = CreateThread(NULL, NULL, OpenMessageWindowThread, hContact, NULL, &threadID); } free(contact); free(id); } } else if (argc == 3) { reply->code = MIMRES_SUCCESS; *reply->message = 0; for (HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { HANDLE hUnreadEvent = db_event_firstUnread(hContact); if (hUnreadEvent != NULL) { DWORD threadID; HANDLE thread = CreateThread(NULL, NULL, OpenMessageWindowThread, hContact, NULL, &threadID); } } } else HandleWrongParametersCount(command, reply); } else HandleUnknownParameter(command, argv[2], reply); } } else HandleWrongParametersCount(command, reply); } void AddHistoryEvent(DBEVENTINFO *dbEvent, char *contact, PReply reply) { struct tm * tEvent = localtime((time_t *) &dbEvent->timestamp); char timestamp[256]; strftime(timestamp, sizeof(timestamp), "%H:%M:%S %d/%b/%Y", tEvent); static char buffer[6144]; char *sender = (dbEvent->flags & DBEF_SENT) ? Translate("[me]") : contact; char message[4096] = {0}; STRNCPY(message, (char *) dbEvent->pBlob, sizeof(message)); message[dbEvent->cbBlob] = message[strlen(message)] = 0; //if ((strlen(message) <= 0) && (dbEvent->cbBlob > 0)) //{ // WCHAR *tmp = (WCHAR *) dbEvent->pBlob[dbEvent->cbBlob + 1]; // WideCharToMultiByte(CP_ACP, 0, tmp, -1, message, sizeof(message), NULL, NULL); //} mir_snprintf(buffer, sizeof(buffer), "[%s] %15s: %s", timestamp, sender, message); if (strlen(reply->message) > 0) { strncat(reply->message, "\n", reply->cMessage); strncat(reply->message, buffer, reply->cMessage); } else{ STRNCPY(reply->message, buffer, reply->cMessage); } if (strlen(reply->message) > (reply->cMessage / 2)) { SetEvent(heServerBufferFull); Sleep(750); strcpy(reply->message, "\n"); } } void HandleHistoryCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc >= 3) { char *cmd = argv[2]; switch (argc) { case 3: { if (_stricmp(cmd, "unread") == 0) { char buffer[4096]; int count; int contacts = 0; DBEVENTINFO dbEvent = { sizeof(dbEvent) }; reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("No unread messages found.")); for (HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { HANDLE hEvent = db_event_firstUnread(hContact); if (hEvent != NULL) { count = 0; while (hEvent != NULL) { if (!db_event_get( hEvent, &dbEvent)) if (!(dbEvent.flags & DBEF_READ)) count++; hEvent = db_event_next(hEvent); } char protocol[128]; GetContactProto(hContact, protocol, sizeof(protocol)); char *contact = GetContactName(hContact, protocol); mir_snprintf(buffer, sizeof(buffer), Translate("%s:%s - %d unread events."), contact, protocol, count); if (contacts > 0) { strncat(reply->message, "\n", reply->cMessage); strncat(reply->message, buffer, reply->cMessage); } else STRNCPY(reply->message, buffer, reply->cMessage); contacts++; free(contact); } } } else { if (_stricmp(cmd, "show") == 0) HandleWrongParametersCount(command, reply); else HandleUnknownParameter(command, cmd, reply); } break; } case 4: { char *contact = argv[3]; HANDLE hContact = ParseContactParam(contact); if (hContact) { if (_stricmp(cmd, "unread") == 0) { HANDLE hEvent = db_event_firstUnread(hContact); reply->code = MIMRES_SUCCESS; while (hEvent) { DBEVENTINFO dbEvent = { sizeof(dbEvent) }; if (!db_event_get(hEvent, &dbEvent)) //if successful call if (!(dbEvent.flags & DBEF_READ)) AddHistoryEvent(&dbEvent, contact, reply); hEvent = db_event_next(hEvent); } } else if (_stricmp(cmd, "show") == 0) { reply->code = MIMRES_SUCCESS; mir_snprintf(reply->message, reply->cMessage, Translate("Contact '%s' has '%d' events in history."), contact, db_event_count(hContact)); } else HandleUnknownParameter(command, cmd, reply); } else { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Could not find contact handle for contact '%s'."), contact); } break; } case 6: { char *contact = argv[3]; HANDLE hContact = ParseContactParam(contact); if (hContact) { if (_stricmp(cmd, "show") == 0) { char *stop1 = NULL; char *stop2 = NULL; long start = strtol(argv[4], &stop1, 10); long stop = strtol(argv[5], &stop2, 10); if (!(*stop1) && !(*stop2)) { int size = db_event_count(hContact); if (start < 0) { start = size + start + 1; } if (stop < 0) { stop = size + stop + 1; } reply->code = MIMRES_SUCCESS; int count = stop - start + 1; if (count > 0) { int index = 0; HANDLE hEvent = db_event_first(hContact); DBEVENTINFO dbEvent = { sizeof(DBEVENTINFO) }; char message[4096]; dbEvent.pBlob = (PBYTE) message; while (hEvent) { dbEvent.cbBlob = sizeof(message); if (!db_event_get( hEvent, &dbEvent)) // if successful call { dbEvent.pBlob[dbEvent.cbBlob] = 0; if ((index >= start) && (index <= stop)) AddHistoryEvent(&dbEvent, contact, reply); } if (index > stop) break; hEvent = db_event_next(hEvent); index++; } } } else HandleUnknownParameter(command, (*stop1) ? argv[4] : argv[5], reply); } else{ if (_stricmp(cmd, "unread") == 0) HandleWrongParametersCount(command, reply); else HandleUnknownParameter(command, cmd, reply); } } else{ reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Could not find contact handle for contact '%s'."), contact); } break; } default: HandleWrongParametersCount(command, reply); break; } } else HandleWrongParametersCount(command, reply); } void HandleVersionCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc == 2) { reply->code = MIMRES_SUCCESS; if (ServiceExists(MS_VERSIONINFO_GETINFO)) { char *data; CallService(MS_VERSIONINFO_GETINFO, (WPARAM) FALSE, (LPARAM) &data); mir_snprintf(reply->message, reply->cMessage, data); mir_free(data); } else{ char miranda[512]; char cmdline[512]; DWORD v = pluginInfo.version; CallService(MS_SYSTEM_GETVERSIONTEXT, (WPARAM) sizeof(miranda), (LPARAM) miranda); mir_snprintf(cmdline, sizeof(cmdline), "%d.%d.%d.%d", ((v >> 24) & 0xFF), ((v >> 16) & 0xFF), ((v >> 8) & 0xFF), (v & 0xFF)); mir_snprintf(reply->message, reply->cMessage, "Miranda %s\nCmdLine v.%s", miranda, cmdline); } } else{ HandleWrongParametersCount(command, reply); } } void HandleSetNicknameCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc == 4) { char protocol[512]; char nickname[512]; strcpy(protocol, argv[2]); strcpy(nickname, argv[3]); int res = CallProtoService(protocol, PS_SETMYNICKNAME, SMNN_TCHAR, (LPARAM) nickname); if (res == 0) { reply->code = MIMRES_SUCCESS; *reply->message = 0; } else { reply->code = MIMRES_FAILURE; mir_snprintf(reply->message, reply->cMessage, Translate("Error setting nickname to '%s' for protocol '%s'"), nickname, protocol); } } else { HandleWrongParametersCount(command, reply); } } void HandleIgnoreCommand(PCommand command, TArgument *argv, int argc, PReply reply) { if (argc >= 4) { BOOL block = FALSE; BOOL goodCommand = FALSE; if (_stricmp(argv[2], "block") == 0) { block = TRUE; goodCommand = TRUE; } if (_stricmp(argv[2], "unblock") == 0) { block = FALSE; goodCommand = TRUE; } if (!goodCommand) { HandleUnknownParameter(command, argv[2], reply); return; } HANDLE hContact = NULL; char *contact; for (int i = 3; i < argc; i++) { contact = argv[i]; hContact = ParseContactParam(contact); if (hContact) { CallService(block ? MS_IGNORE_IGNORE : MS_IGNORE_UNIGNORE, (WPARAM) hContact, IGNOREEVENT_ALL); } } reply->code = MIMRES_SUCCESS; *reply->message = 0; } else { HandleWrongParametersCount(command, reply); } }