Mercurial > pidgin.yaz
diff plugins/tcl/tcl_cmds.c @ 6694:2d2f04c5c7d2
[gaim-migrate @ 7220]
Sean probably won't think this is contact support. This is in fact a
Tcl script plugin loader. That's probably what he'll think it is.
committer: Tailor Script <tailor@pidgin.im>
author | Ethan Blanton <elb@pidgin.im> |
---|---|
date | Tue, 02 Sep 2003 03:34:37 +0000 |
parents | |
children | 57161e3abbb5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/tcl/tcl_cmds.c Tue Sep 02 03:34:37 2003 +0000 @@ -0,0 +1,913 @@ +/** + * @file tcl_cmds.c Commands for the Gaim Tcl plugin bindings + * + * gaim + * + * Copyright (C) 2003 Ethan Blanton <eblanton@cs.purdue.edu> + * + * 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 <tcl.h> + +#include "internal.h" +#include "conversation.h" +#include "connection.h" +#include "account.h" +#include "server.h" +#include "notify.h" +#include "debug.h" +#include "prefs.h" +#include "core.h" + +#include "tcl_gaim.h" + +static gboolean tcl_validate_account(GaimAccount *account, Tcl_Interp *interp); +static gboolean tcl_validate_gc(GaimConnection *gc); + +static gboolean tcl_validate_account(GaimAccount *account, Tcl_Interp *interp) +{ + GList *cur; + for (cur = gaim_accounts_get_all(); cur != NULL; cur = g_list_next(cur)) { + if (account == cur->data) + return TRUE; + } + if (interp != NULL) + Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid account", -1); + return FALSE; +} + +static gboolean tcl_validate_conversation(GaimConversation *convo, Tcl_Interp *interp) +{ + GList *cur; + + for (cur = gaim_get_conversations(); cur != NULL; cur = g_list_next(cur)) { + if (convo == cur->data) + return TRUE; + } + if (interp != NULL) + Tcl_SetStringObj(Tcl_GetObjResult(interp), "invalid account", -1); + return FALSE; +} + +static gboolean tcl_validate_gc(GaimConnection *gc) +{ + GList *cur; + for (cur = gaim_connections_get_all(); cur != NULL; cur = g_list_next(cur)) { + if (gc == cur->data) + return TRUE; + } + return FALSE; +} + +int tcl_cmd_account(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *result = Tcl_GetObjResult(interp), *list, *elem; + char *cmds[] = { "alias", "connect", "connection", "disconnect", "find", + "handle", "isconnected", "list", "protocol", "username", + NULL }; + enum { CMD_ACCOUNT_ALIAS, CMD_ACCOUNT_CONNECT, CMD_ACCOUNT_CONNECTION, + CMD_ACCOUNT_DISCONNECT, CMD_ACCOUNT_FIND, CMD_ACCOUNT_HANDLE, + CMD_ACCOUNT_ISCONNECTED, CMD_ACCOUNT_LIST, CMD_ACCOUNT_PROTOCOL, + CMD_ACCOUNT_USERNAME } cmd; + char *listopts[] = { "-all", "-online", NULL }; + enum { CMD_ACCOUNTLIST_ALL, CMD_ACCOUNTLIST_ONLINE } listopt; + const char *alias; + GList *cur; + GaimAccount *account; + int error; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + switch (cmd) { + case CMD_ACCOUNT_ALIAS: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + alias = gaim_account_get_alias(account); + Tcl_SetStringObj(result, alias ? (char *)alias : "", -1); + break; + case CMD_ACCOUNT_CONNECT: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + if (gaim_account_is_connected(account)) + Tcl_SetIntObj(result, (int)gaim_account_get_connection(account)); + else + Tcl_SetIntObj(result, (int)gaim_account_connect(account)); + break; + case CMD_ACCOUNT_CONNECTION: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + Tcl_SetIntObj(result, (int)gaim_account_get_connection(account)); + break; + case CMD_ACCOUNT_DISCONNECT: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + gaim_account_disconnect(account); + break; + case CMD_ACCOUNT_FIND: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "username protocol"); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_accounts_find_with_prpl_id(Tcl_GetString(objv[2]), + Tcl_GetString(objv[3]))); + break; + case CMD_ACCOUNT_HANDLE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_accounts_get_handle()); + break; + case CMD_ACCOUNT_ISCONNECTED: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + Tcl_SetBooleanObj(result, gaim_account_is_connected(account)); + break; + case CMD_ACCOUNT_LIST: + listopt = CMD_ACCOUNTLIST_ALL; + if (objc > 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?option?"); + return TCL_ERROR; + } + if (objc == 3) { + if ((error = Tcl_GetIndexFromObj(interp, objv[2], listopts, "option", 0, (int *)&listopt)) != TCL_OK) + return error; + } + list = Tcl_NewListObj(0, NULL); + for (cur = gaim_accounts_get_all(); cur != NULL; cur = g_list_next(cur)) { + account = cur->data; + if (listopt == CMD_ACCOUNTLIST_ONLINE && !gaim_account_is_connected(account)) + continue; + elem = Tcl_NewIntObj((int)account); + Tcl_ListObjAppendElement(interp, list, elem); + } + Tcl_SetObjResult(interp, list); + break; + case CMD_ACCOUNT_PROTOCOL: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + Tcl_SetStringObj(result, (char *)gaim_account_get_protocol_id(account), -1); + break; + case CMD_ACCOUNT_USERNAME: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "account"); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account); + if (error || !tcl_validate_account(account, interp)) + return TCL_ERROR; + Tcl_SetStringObj(result, (char *)gaim_account_get_username(account), -1); + break; + } + + return TCL_OK; +} + +static GaimBlistNode *tcl_list_to_buddy(Tcl_Interp *interp, int count, Tcl_Obj **elems) +{ + GaimBlistNode *node = NULL; + GaimAccount *account; + char *name; + char *type; + + if (count < 3) { + Tcl_SetStringObj(Tcl_GetObjResult(interp), "list too short", -1); + return NULL; + } + + type = Tcl_GetString(elems[0]); + name = Tcl_GetString(elems[1]); + if (Tcl_GetIntFromObj(interp, elems[2], (int *)&account) != TCL_OK) + return NULL; + if (!tcl_validate_account(account, interp)) + return NULL; + + if (!strcmp(type, "buddy")) { + node = (GaimBlistNode *)gaim_find_buddy(account, name); + } else if (!strcmp(type, "group")) { + node = (GaimBlistNode *)gaim_blist_find_chat(account, name); + } + + return node; +} + +int tcl_cmd_buddy(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *list, *tclgroup, *tclgrouplist, *tclbud, **elems, *result; + char *cmds[] = { "alias", "handle", "info", "list", NULL }; + enum { CMD_BUDDY_ALIAS, CMD_BUDDY_HANDLE, CMD_BUDDY_INFO, CMD_BUDDY_LIST } cmd; + struct gaim_buddy_list *blist; + GaimBlistNode *node, *gnode; + GaimAccount *account; + struct buddy *bnode; + struct chat *cnode; + int error, all = 0, count; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + result = Tcl_GetObjResult(interp); + + switch (cmd) { + case CMD_BUDDY_ALIAS: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "buddy"); + return TCL_ERROR; + } + if ((error = Tcl_ListObjGetElements(interp, objv[2], &count, &elems)) != TCL_OK) + return error; + if ((node = tcl_list_to_buddy(interp, count, elems)) == NULL) + return TCL_ERROR; + if (node->type == GAIM_BLIST_CHAT_NODE) + Tcl_SetStringObj(result, ((struct chat *)node)->alias, -1); + else if (node->type == GAIM_BLIST_BUDDY_NODE) + Tcl_SetStringObj(result, gaim_get_buddy_alias((struct buddy *)node), -1); + return TCL_OK; + break; + case CMD_BUDDY_HANDLE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_blist_get_handle()); + break; + case CMD_BUDDY_INFO: + if (objc != 3 && objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "( buddy | account username )"); + return TCL_ERROR; + } + if (objc == 3) { + if ((error = Tcl_ListObjGetElements(interp, objv[2], &count, &elems)) != TCL_OK) + return error; + if (count < 3) { + Tcl_SetStringObj(result, "buddy too short", -1); + return TCL_ERROR; + } + if (strcmp("buddy", Tcl_GetString(elems[0]))) { + Tcl_SetStringObj(result, "invalid buddy", -1); + return TCL_ERROR; + } + if ((error = Tcl_GetIntFromObj(interp, elems[2], (int *)&account)) != TCL_OK) + return TCL_ERROR; + if (!tcl_validate_account(account, interp)) + return TCL_ERROR; + serv_get_info(gaim_account_get_connection(account), Tcl_GetString(elems[1])); + } else { + if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&account)) != TCL_OK) + return error; + if (!tcl_validate_account(account, interp)) + return TCL_ERROR; + serv_get_info(gaim_account_get_connection(account), Tcl_GetString(objv[3])); + } + break; + case CMD_BUDDY_LIST: + if (objc == 3) { + if (!strcmp("-all", Tcl_GetString(objv[2]))) { + all = 1; + } else { + Tcl_SetStringObj(result, "", -1); + Tcl_AppendStringsToObj(result, "unknown option: ", Tcl_GetString(objv[2]), NULL); + return TCL_ERROR; + } + } + list = Tcl_NewListObj(0, NULL); + blist = gaim_get_blist(); + for (gnode = blist->root; gnode != NULL; gnode = gnode->next) { + tclgroup = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tclgroup, Tcl_NewStringObj("group", -1)); + Tcl_ListObjAppendElement(interp, tclgroup, + Tcl_NewStringObj(((struct group *)gnode)->name, -1)); + tclgrouplist = Tcl_NewListObj(0, NULL); + for (node = gnode->child; node != NULL; node = node->next) { + switch (node->type) { + case GAIM_BLIST_BUDDY_NODE: + bnode = (struct buddy *)node; + if (!all && !gaim_account_is_connected(bnode->account)) + continue; + tclbud = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tclbud, Tcl_NewStringObj("buddy", -1)); + Tcl_ListObjAppendElement(interp, tclbud, Tcl_NewStringObj(bnode->name, -1)); + Tcl_ListObjAppendElement(interp, tclbud, Tcl_NewIntObj((int)bnode->account)); + break; + case GAIM_BLIST_CHAT_NODE: + cnode = (struct chat *)node; + if (!all && !gaim_account_is_connected(cnode->account)) + continue; + tclbud = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(interp, tclbud, Tcl_NewStringObj("chat", -1)); + Tcl_ListObjAppendElement(interp, tclbud, Tcl_NewStringObj(cnode->alias, -1)); + Tcl_ListObjAppendElement(interp, tclbud, Tcl_NewIntObj((int)cnode->account)); + break; + default: + continue; + } + Tcl_ListObjAppendElement(interp, tclgrouplist, tclbud); + } + Tcl_ListObjAppendElement(interp, tclgroup, tclgrouplist); + Tcl_ListObjAppendElement(interp, list, tclgroup); + } + Tcl_SetObjResult(interp, list); + break; + } + + return TCL_OK; +} + +int tcl_cmd_connection(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *result = Tcl_GetObjResult(interp), *list, *elem; + char *cmds[] = { "account", "handle", "list", NULL }; + enum { CMD_CONN_ACCOUNT, CMD_CONN_HANDLE, CMD_CONN_LIST } cmd; + int error; + GList *cur; + GaimConnection *gc; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + switch (cmd) { + case CMD_CONN_ACCOUNT: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, _("gc")); + return TCL_ERROR; + } + error = Tcl_GetIntFromObj(interp, objv[2], (int *)&gc); + if (error || !tcl_validate_gc(gc)) { + Tcl_SetStringObj(result, "invalid gc", -1); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_connection_get_account(gc)); + break; + case CMD_CONN_HANDLE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_connections_get_handle()); + break; + case CMD_CONN_LIST: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + list = Tcl_NewListObj(0, NULL); + for (cur = gaim_connections_get_all(); cur != NULL; cur = g_list_next(cur)) { + elem = Tcl_NewIntObj((int)cur->data); + Tcl_ListObjAppendElement(interp, list, elem); + } + Tcl_SetObjResult(interp, list); + break; + } + + return TCL_OK; +} + +int tcl_cmd_conversation(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *list, *elem, *result = Tcl_GetObjResult(interp); + char *cmds[] = { "find", "handle", "list", "new", "write", NULL }; + enum { CMD_CONV_FIND, CMD_CONV_HANDLE, CMD_CONV_LIST, CMD_CONV_NEW, CMD_CONV_WRITE } cmd; + char *styles[] = { "send", "recv", "system", NULL }; + enum { CMD_CONV_WRITE_SEND, CMD_CONV_WRITE_RECV, CMD_CONV_WRITE_SYSTEM } style; + char *findopts[] = { "-account", NULL }; + enum { CMD_CONV_FIND_ACCOUNT } findopt; + char *newopts[] = { "-chat", "-im" }; + enum { CMD_CONV_NEW_CHAT, CMD_CONV_NEW_IM } newopt; + GaimConversation *convo; + GaimAccount *account; + GaimConversationType type; + GList *cur; + char *opt, *from, *what; + int error, argsused, flags; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + switch (cmd) { + case CMD_CONV_FIND: + if (objc < 3) { + Tcl_WrongNumArgs(interp, 2, objv, "?options? name"); + return TCL_ERROR; + } + argsused = 2; + account = NULL; + while (argsused < objc) { + opt = Tcl_GetString(objv[argsused]); + if (*opt == '-') { + if ((error = Tcl_GetIndexFromObj(interp, objv[argsused], findopts, + "option", 0, (int *)&findopt)) != TCL_OK) + return error; + argsused++; + switch (findopt) { + case CMD_CONV_FIND_ACCOUNT: + if (argsused == objc - 1) { + Tcl_SetStringObj(result, "-account requires an argument", -1); + return TCL_ERROR; + } + if ((error = Tcl_GetIntFromObj(interp, objv[argsused], + (int *)&account)) != TCL_OK) + return error; + if (!tcl_validate_account(account, interp)) + return TCL_ERROR; + argsused++; + break; + } + } else { + break; + } + } + if (objc - argsused != 1) { + Tcl_WrongNumArgs(interp, 2, objv, "?options? name"); + return error; + } + if (account != NULL) { + convo = gaim_find_conversation_with_account(Tcl_GetString(objv[argsused]), account); + } else { + convo = gaim_find_conversation(Tcl_GetString(objv[argsused])); + } + Tcl_SetIntObj(result, (int)convo); + break; + case CMD_CONV_HANDLE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_conversations_get_handle()); + break; + case CMD_CONV_LIST: + list = Tcl_NewListObj(0, NULL); + for (cur = gaim_get_conversations(); cur != NULL; cur = g_list_next(cur)) { + elem = Tcl_NewIntObj((int)cur->data); + Tcl_ListObjAppendElement(interp, list, elem); + } + Tcl_SetObjResult(interp, list); + break; + case CMD_CONV_NEW: + if (objc < 4) { + Tcl_WrongNumArgs(interp, 2, objv, "?options? account name"); + return TCL_ERROR; + } + argsused = 2; + type = GAIM_CONV_IM; + while (argsused < objc) { + opt = Tcl_GetString(objv[argsused]); + if (*opt == '-') { + if ((error = Tcl_GetIndexFromObj(interp, objv[argsused], newopts, + "option", 0, (int *)&newopt)) != TCL_OK) + return error; + argsused++; + switch (newopt) { + case CMD_CONV_NEW_CHAT: + type = GAIM_CONV_CHAT; + break; + case CMD_CONV_NEW_IM: + type = GAIM_CONV_IM; + break; + } + } else { + break; + } + } + if (objc - argsused != 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?options? account name"); + return TCL_ERROR; + } + if ((error = Tcl_GetIntFromObj(interp, objv[argsused++], (int *)&account)) != TCL_OK) + return error; + if (!tcl_validate_account(account, interp)) + return TCL_ERROR; + convo = gaim_conversation_new(type, account, Tcl_GetString(objv[argsused])); + Tcl_SetIntObj(result, (int)convo); + break; + case CMD_CONV_WRITE: + if (objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "conversation style from what"); + return TCL_ERROR; + } + if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&convo)) != TCL_OK) + return error; + if ((error = Tcl_GetIndexFromObj(interp, objv[3], styles, "style", 0, (int *)&style)) != TCL_OK) + return error; + if (!tcl_validate_conversation(convo, interp)) + return TCL_ERROR; + from = Tcl_GetString(objv[4]); + what = Tcl_GetString(objv[5]); + + switch (style) { + case CMD_CONV_WRITE_SEND: + flags = GAIM_MESSAGE_SEND; + break; + case CMD_CONV_WRITE_RECV: + flags = GAIM_MESSAGE_RECV; + break; + case CMD_CONV_WRITE_SYSTEM: + flags = GAIM_MESSAGE_SYSTEM; + break; + } + if (gaim_conversation_get_type(convo) == GAIM_CONV_CHAT) + gaim_chat_write(GAIM_CHAT(convo), from, what, flags, time(NULL)); + else + gaim_im_write(GAIM_IM(convo), from, what, -1, flags, time(NULL)); + break; + } + + return TCL_OK; +} + +int tcl_cmd_core(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *result = Tcl_GetObjResult(interp); + char *cmds[] = { "handle", "quit", NULL }; + enum { CMD_CORE_HANDLE, CMD_CORE_QUIT } cmd; + int error; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + switch (cmd) { + case CMD_CORE_HANDLE: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + Tcl_SetIntObj(result, (int)gaim_get_core()); + break; + case CMD_CORE_QUIT: + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, ""); + return TCL_ERROR; + } + gaim_core_quit(); + break; + } + + return TCL_OK; +} + +int tcl_cmd_debug(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *category, *message; + int lev; + char *levels[] = { "-misc", "-info", "-warning", "-error", NULL }; + GaimDebugLevel levelind[] = { GAIM_DEBUG_MISC, GAIM_DEBUG_INFO, GAIM_DEBUG_WARNING, GAIM_DEBUG_ERROR }; + int error; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "level category message"); + return TCL_ERROR; + } + + error = Tcl_GetIndexFromObj(interp, objv[1], levels, "debug level", 0, &lev); + if (error != TCL_OK) + return error; + + category = Tcl_GetString(objv[2]); + message = Tcl_GetString(objv[3]); + + gaim_debug(levelind[lev], category, "%s\n", message); + + return TCL_OK; +} + +int tcl_cmd_notify(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + int error, type; + char *opts[] = { "-error", "-warning", "-info", NULL }; + GaimNotifyMsgType optind[] = { GAIM_NOTIFY_MSG_ERROR, GAIM_NOTIFY_MSG_WARNING, GAIM_NOTIFY_MSG_INFO }; + char *title, *msg1, *msg2; + + if (objc < 4 || objc > 5) { + Tcl_WrongNumArgs(interp, 1, objv, "?type? title primary secondary"); + return TCL_ERROR; + } + + if (objc == 4) { + title = Tcl_GetString(objv[1]); + msg1 = Tcl_GetString(objv[2]); + msg2 = Tcl_GetString(objv[3]); + } else { + error = Tcl_GetIndexFromObj(interp, objv[1], opts, "message type", 0, &type); + if (error != TCL_OK) + return error; + title = Tcl_GetString(objv[2]); + msg1 = Tcl_GetString(objv[3]); + msg2 = Tcl_GetString(objv[4]); + } + + gaim_notify_message(_tcl_plugin, optind[type], title, msg1, msg2, NULL, NULL); + + return TCL_OK; +} + +int tcl_cmd_prefs(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *result, *list, *elem, **elems; + char *cmds[] = { "get", "set", "type", NULL }; + enum { CMD_PREFS_GET, CMD_PREFS_SET, CMD_PREFS_TYPE } cmd; + /* char *types[] = { "none", "boolean", "int", "string", "stringlist", NULL }; */ + /* enum { TCL_PREFS_NONE, TCL_PREFS_BOOL, TCL_PREFS_INT, TCL_PREFS_STRING, TCL_PREFS_STRINGLIST } type; */ + GaimPrefType preftype; + GList *cur; + int error, intval, nelem, i; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + result = Tcl_GetObjResult(interp); + switch (cmd) { + case CMD_PREFS_GET: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "path"); + return TCL_ERROR; + } + preftype = gaim_prefs_get_type(Tcl_GetString(objv[2])); + switch (preftype) { + case GAIM_PREF_NONE: + Tcl_SetStringObj(result, "pref type none", -1); + return TCL_ERROR; + break; + case GAIM_PREF_BOOLEAN: + Tcl_SetBooleanObj(result, gaim_prefs_get_bool(Tcl_GetString(objv[2]))); + break; + case GAIM_PREF_INT: + Tcl_SetIntObj(result, gaim_prefs_get_int(Tcl_GetString(objv[2]))); + break; + case GAIM_PREF_STRING: + Tcl_SetStringObj(result, (char *)gaim_prefs_get_string(Tcl_GetString(objv[2])), -1); + break; + case GAIM_PREF_STRING_LIST: + cur = gaim_prefs_get_string_list(Tcl_GetString(objv[2])); + list = Tcl_NewListObj(0, NULL); + while (cur != NULL) { + elem = Tcl_NewStringObj((char *)cur->data, -1); + Tcl_ListObjAppendElement(interp, list, elem); + cur = g_list_next(cur); + } + Tcl_SetObjResult(interp, list); + break; + default: + gaim_debug(GAIM_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype); + Tcl_SetStringObj(result, "unknown pref type", -1); + return TCL_ERROR; + } + break; + case CMD_PREFS_SET: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "path value"); + return TCL_ERROR; + } + preftype = gaim_prefs_get_type(Tcl_GetString(objv[2])); + switch (preftype) { + case GAIM_PREF_NONE: + Tcl_SetStringObj(result, "bad path or pref type none", -1); + return TCL_ERROR; + break; + case GAIM_PREF_BOOLEAN: + if ((error = Tcl_GetBooleanFromObj(interp, objv[3], &intval)) != TCL_OK) + return error; + gaim_prefs_set_bool(Tcl_GetString(objv[2]), intval); + break; + case GAIM_PREF_INT: + if ((error = Tcl_GetIntFromObj(interp, objv[3], &intval)) != TCL_OK) + return error; + gaim_prefs_set_int(Tcl_GetString(objv[2]), intval); + break; + case GAIM_PREF_STRING: + gaim_prefs_set_string(Tcl_GetString(objv[2]), Tcl_GetString(objv[3])); + break; + case GAIM_PREF_STRING_LIST: + if ((error = Tcl_ListObjGetElements(interp, objv[3], &nelem, &elems)) != TCL_OK) + return error; + cur = NULL; + for (i = 0; i < nelem; i++) { + cur = g_list_append(cur, (gpointer)Tcl_GetString(elems[i])); + } + gaim_prefs_set_string_list(Tcl_GetString(objv[2]), cur); + g_list_free(cur); + break; + default: + gaim_debug(GAIM_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype); + return TCL_ERROR; + } + break; + case CMD_PREFS_TYPE: + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "path"); + return TCL_ERROR; + } + preftype = gaim_prefs_get_type(Tcl_GetString(objv[2])); + switch (preftype) { + case GAIM_PREF_NONE: + Tcl_SetStringObj(result, "none", -1); + break; + case GAIM_PREF_BOOLEAN: + Tcl_SetStringObj(result, "boolean", -1); + break; + case GAIM_PREF_INT: + Tcl_SetStringObj(result, "int", -1); + break; + case GAIM_PREF_STRING: + Tcl_SetStringObj(result, "string", -1); + break; + case GAIM_PREF_STRING_LIST: + Tcl_SetStringObj(result, "stringlist", -1); + break; + default: + gaim_debug(GAIM_DEBUG_ERROR, "tcl", "tcl does not know about pref type %d\n", preftype); + Tcl_SetStringObj(result, "unknown", -1); + } + break; + } + + return TCL_OK; +} + +int tcl_cmd_send_im(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + GaimConnection *gc; + char *who, *text; + int error; + Tcl_Obj *result; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 1, objv, "gc who text"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIntFromObj(interp, objv[1], (int *)&gc)) != TCL_OK) + return error; + if (!tcl_validate_gc(gc)) { + result = Tcl_GetObjResult(interp); + Tcl_SetStringObj(result, "invalid gc", -1); + return TCL_ERROR; + } + + who = Tcl_GetString(objv[2]); + text = Tcl_GetString(objv[3]); + + serv_send_im(gc, who, text, -1, 0); + + return TCL_OK; +} + +int tcl_cmd_signal(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + char *cmds[] = { "connect", "disconnect", NULL }; + enum { CMD_SIGNAL_CONNECT, CMD_SIGNAL_DISCONNECT } cmd; + struct tcl_signal_handler *handler; + Tcl_Obj **elems, *result = Tcl_GetObjResult(interp); + void *instance; + int error, nelems, i; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?"); + return TCL_ERROR; + } + + if ((error = Tcl_GetIndexFromObj(interp, objv[1], cmds, "subcommand", 0, (int *)&cmd)) != TCL_OK) + return error; + + switch (cmd) { + case CMD_SIGNAL_CONNECT: + if (objc != 6) { + Tcl_WrongNumArgs(interp, 2, objv, "instance signal args proc"); + return TCL_ERROR; + } + if ((error = Tcl_ListObjGetElements(interp, objv[4], &nelems, &elems)) != TCL_OK) + return error; + handler = g_new0(struct tcl_signal_handler, 1); + if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&handler->instance)) != TCL_OK) { + g_free(handler); + return error; + } + handler->signal = g_strdup(Tcl_GetString(objv[3])); + if (nelems) { + handler->argnames = g_new0(char *, nelems); + for (i = 0; i < nelems; i++) { + handler->argnames[i] = g_strdup(Tcl_GetString(elems[i])); + } + } + handler->nnames = nelems; + handler->proc = Tcl_NewStringObj("namespace eval ::gaim::_callback { ", -1); + Tcl_AppendStringsToObj(handler->proc, Tcl_GetString(objv[5]), " }", NULL); + Tcl_IncrRefCount(handler->proc); + handler->interp = interp; + if (!tcl_signal_connect(handler)) { + tcl_signal_handler_free(handler); + Tcl_SetIntObj(result, 1); + } else { + Tcl_SetIntObj(result, 0); + } + break; + case CMD_SIGNAL_DISCONNECT: + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "signal"); + return TCL_ERROR; + } + if ((error = Tcl_GetIntFromObj(interp, objv[2], (int *)&instance)) != TCL_OK) + return error; + tcl_signal_disconnect(instance, Tcl_GetString(objv[3]), interp); + break; + } + + return TCL_OK; +} + +static gboolean unload_self(gpointer data) +{ + GaimPlugin *plugin = data; + gaim_plugin_unload(plugin); + return FALSE; +} + +int tcl_cmd_unload(ClientData unused, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + GaimPlugin *plugin; + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + + if ((plugin = tcl_interp_get_plugin(interp)) == NULL) { + /* This isn't exactly OK, but heh. What do you do? */ + return TCL_OK; + } + /* We can't unload immediately, but we can unload at the first + * known safe opportunity. */ + g_idle_add(unload_self, (gpointer)plugin); + + return TCL_OK; +}