# HG changeset patch # User Eric Warmenhoven # Date 971421880 0 # Node ID 7e231bc0018afeb568778c94a6c9ac0e46517c98 # Parent 82c5865f7cfe0094f1cebe6ed2870889fedc8073 [gaim-migrate @ 991] I think I need a Pepsi. committer: Tailor Script diff -r 82c5865f7cfe -r 7e231bc0018a PRPL --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PRPL Fri Oct 13 07:24:40 2000 +0000 @@ -0,0 +1,70 @@ +Protocol Plugins. What EveryBuddy should have been. + +Protocol Plugins are easier than GUI plugins. This is because there is necessarily a limited set +of server functions; protocols are limited. What a programmer can do with a UI is limitless. + +In order to design a framework for which Protocol Plugins can work, we must first think about +which protocols can be pluginized. (Henceforth PRPL will stand for both the Protocol Plugin +system and an individual Protocol Plugin.) + +Oscar. TOC. Yahoo. MSN. ICQ. FTP. IRC. + +There is a longer list. Note that FTP is in the list presented. FTP has basic functions similar +to those of the others. The basic functions that must be performed are: + +Sign on. (log in) +Sign off. +Send and receive messages. + +There really isn't much more to it than that. There are, then, additional functions that some +protocols implement: + +Chat. +File Transfer. +Away/Idle. (states) +Directory Info. + +Before PRPL there was a slight abstraction in the code. The UI simply needed to call serv_login, +and that function would decide between the protocols, which function to call. It did that with +an if-elseif-else series. + +With PRPL, each PRPL is stored in a struct. The structs are then kept in a GSList. The serv_ +functions then simply need to search the GSList for the correct protocol, and call the desired +function. The struct holds void * references to the desired functions. serv_* simply needs to +call that function. (Even better, each connection has a reference to the PRPL struct it uses; +this will reduce search time.) + +A new PRPL can be loaded at any time. They can be either static or dynamic code. When a new +protocol is loaded, gaim will call its protocol_init function, which is expected to return a +pointer to the aforementioned struct. If it returns NULL, the PRPL will not be loaded. (This is +not entirely true and needs to be modified in the code to work similarly to how it's decscribed +here.) + +Each PRPL needs to have a unique identifier. In the pre-PRPL system TOC was 0 and Oscar was 1. +This identifier can be found in prpl.h. They are pre-assigned. PROTO_TOC is still 0, PROTO_OSCAR +is still 1. The protocol_init function is expected to set the struct's protocol member to the +appropriate value. If you want to write a new PRPL for gaim, please email one of the maintainers +with the name of the protocol. We'll then reserve a number for it. Please do not use a number +that has not been assigned to your protocol, not even for testing purposes. + +The addition of PRPL to gaim means that gaim now supports multiple connections and multiple (and +dynamically loadable) protocols. + +====== + +In order to test that PRPL was working with as little work as possible I made Oscar a plugin. In +order to use Oscar as a plugin, first recompile gaim with the make variable DEBUG_CFLAGS set to +-DDYNAMIC_OSCAR, e.g. + +/usr/src/gaim $ make DEBUG_CFLAGS=-DDYNAMIC_OSCAR + +This will then remove Oscar support from the code (though it will still link with libfaim. However, +gaim does not need to link to libfaim itself). Making the Oscar plugin is straight-forward; simply +make oscar.so in the plugins directory, e.g. + +/usr/src/gaim/plugins $ make oscar.so + +You will then be presented with a gaim binary in src/gaim and the Oscar plugin in plugins/oscar.so. +Simply load the oscar.so file from the normal plugin window. This will set up everything necessary. +You may unload the plugin at any time, but the protocol will still be loaded. This may or may not +be a problem and may or may not be fixed at a later point in time. diff -r 82c5865f7cfe -r 7e231bc0018a configure.in --- a/configure.in Thu Oct 12 18:59:36 2000 +0000 +++ b/configure.in Fri Oct 13 07:24:40 2000 +0000 @@ -100,8 +100,15 @@ CFLAGS="$CFLAGS $GTK_CFLAGS" +dnl Even more X-Chat code if test "$enable_plugins" = yes ; then - AC_DEFINE(GAIM_PLUGINS) + AC_CHECK_FUNCS(dlopen, have_dl=yes) + if test "$have_dl" = yes; then + AC_CHECK_FUNCS(dlerror) + AC_DEFINE(GAIM_PLUGINS) + else + enable_plugins=no + fi fi dnl This was taken straight from X-Chat. @@ -145,7 +152,7 @@ AC_DEFINE(ESD_SOUND) LDADD="$LDADD $ESD_LIBS" else - enable_esd = no + enable_esd=no fi fi @@ -158,7 +165,6 @@ AC_SUBST(CFLAGS) AC_SUBST(LDADD) AC_SUBST(LIBS) -AC_SUBST(LIBFAIM_DO) AC_OUTPUT([Makefile src/Makefile diff -r 82c5865f7cfe -r 7e231bc0018a plugins/Makefile.am --- a/plugins/Makefile.am Thu Oct 12 18:59:36 2000 +0000 +++ b/plugins/Makefile.am Fri Oct 13 07:24:40 2000 +0000 @@ -1,10 +1,8 @@ -LDFLAGS += $(LIBS) -ggdb -shared +LDFLAGS += $(LDADD) $(LIBS) -ggdb -shared SUFFIXES = .c .so .c.so: $(CC) $(CFLAGS) -I../src -DVERSION=\"$(VERSION)\" -fPIC -DPIC -o $@ $< $(LDFLAGS) $(PLUGIN_LIBS) - - #if PLUGINS #plugin_DATA = autorecon.so iconaway.so notify.so spellchk.so lagmeter.so #plugindir = $(libdir)/gaim diff -r 82c5865f7cfe -r 7e231bc0018a plugins/oscar.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/oscar.c Fri Oct 13 07:24:40 2000 +0000 @@ -0,0 +1,1530 @@ +/* + * gaim + * + * Some code copyright (C) 1998-1999, Mark Spencer + * libfaim code copyright 1998, 1999 Adam Fritzler + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "multi.h" +#include "prpl.h" +#include "gaim.h" +#include "aim.h" +#include "gnome_applet_mgr.h" + +#include "pixmaps/cancel.xpm" +#include "pixmaps/ok.xpm" + +int gaim_caps = AIM_CAPS_CHAT | AIM_CAPS_SENDFILE | AIM_CAPS_GETFILE | + AIM_CAPS_VOICE | AIM_CAPS_IMIMAGE | AIM_CAPS_BUDDYICON; +int keepalv = -1; + +struct chat_connection *find_oscar_chat(struct gaim_connection *gc, char *name) { + GSList *g = gc->oscar_chats; + struct chat_connection *c = NULL; + if (gc->protocol != PROTO_OSCAR) return NULL; + + while (g) { + c = (struct chat_connection *)g->data; + if (!strcmp(name, c->name)) + break; + g = g->next; + c = NULL; + } + + return c; +} + +static struct chat_connection *find_oscar_chat_by_conn(struct gaim_connection *gc, + struct aim_conn_t *conn) { + GSList *g = gc->oscar_chats; + struct chat_connection *c = NULL; + + while (g) { + c = (struct chat_connection *)g->data; + if (c->conn == conn) + break; + g = g->next; + c = NULL; + } + + return c; +} + +static struct gaim_connection *find_gaim_conn_by_aim_sess(struct aim_session_t *sess) { + GSList *g = connections; + struct gaim_connection *gc = NULL; + + while (g) { + gc = (struct gaim_connection *)g->data; + if (sess == gc->oscar_sess) + break; + g = g->next; + gc = NULL; + } + + return gc; +} + +static struct gaim_connection *find_gaim_conn_by_oscar_conn(struct aim_conn_t *conn) { + GSList *g = connections; + struct gaim_connection *c = NULL; + struct aim_conn_t *s; + while (g) { + c = (struct gaim_connection *)g->data; + if (c->protocol != PROTO_OSCAR) { + c = NULL; + g = g->next; + continue; + } + s = c->oscar_sess->connlist; + while (s) { + if (conn == s) + break; + s = s->next; + } + if (s) break; + g = g->next; + c = NULL; + } + + return c; +} + +static int gaim_parse_auth_resp (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_login (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_server_ready (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_handle_redirect (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_oncoming (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_offgoing (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_incoming_im(struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_misses (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_user_info (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_motd (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_chatnav_info (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_chat_join (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_chat_leave (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_chat_info_update (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_chat_incoming_msg(struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_msgack (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_ratechange (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_evilnotify (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_bosrights (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_rateresp (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_reportinterval (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_msgerr (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_buddyrights(struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_parse_locerr (struct aim_session_t *, struct command_rx_struct *, ...); + +static int gaim_directim_incoming(struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_directim_typing (struct aim_session_t *, struct command_rx_struct *, ...); +static int gaim_directim_initiate(struct aim_session_t *, struct command_rx_struct *, ...); + +static char *msgerrreason[] = { + "Invalid error", + "Invalid SNAC", + "Rate to host", + "Rate to client", + "Not logged in", + "Service unavailable", + "Service not defined", + "Obsolete SNAC", + "Not supported by host", + "Not supported by client", + "Refused by client", + "Reply too big", + "Responses lost", + "Request denied", + "Busted SNAC payload", + "Insufficient rights", + "In local permit/deny", + "Too evil (sender)", + "Too evil (receiver)", + "User temporarily unavailable", + "No match", + "List overflow", + "Request ambiguous", + "Queue full", + "Not while on AOL" +}; +static int msgerrreasonlen = 25; + +static void oscar_callback(gpointer data, gint source, + GdkInputCondition condition) { + struct aim_conn_t *conn = (struct aim_conn_t *)data; + struct gaim_connection *gc = find_gaim_conn_by_oscar_conn(conn); + if (!gc) { + /* oh boy. this is probably bad. i guess the only thing we can really do + * is return? */ + debug_print("oscar callback for closed connection.\n"); + return; + } + + if (condition & GDK_INPUT_EXCEPTION) { + hide_login_progress(gc->username, _("Disconnected.")); + signoff(gc); + return; + } + if (condition & GDK_INPUT_READ) { + if (conn->type == AIM_CONN_TYPE_RENDEZVOUS_OUT) { + debug_print("got information on rendezvous\n"); + if (aim_handlerendconnect(gc->oscar_sess, conn) < 0) { + debug_print(_("connection error (rend)\n")); + } + } else { + if (aim_get_command(gc->oscar_sess, conn) >= 0) { + aim_rxdispatch(gc->oscar_sess); + } else { + if (conn->type == AIM_CONN_TYPE_RENDEZVOUS && + conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) { + struct conversation *cnv = + find_conversation(((struct aim_directim_priv *)conn->priv)->sn); + debug_print("connection error for directim\n"); + if (cnv) { + make_direct(cnv, FALSE, NULL, 0); + } + aim_conn_kill(gc->oscar_sess, &conn); + } else if ((conn->type == AIM_CONN_TYPE_BOS) || + !(aim_getconn_type(gc->oscar_sess, AIM_CONN_TYPE_BOS))) { + debug_print(_("major connection error\n")); + hide_login_progress(gc->username, _("Disconnected.")); + signoff(gc); + } else if (conn->type == AIM_CONN_TYPE_CHAT) { + struct chat_connection *c = find_oscar_chat_by_conn(gc, conn); + char buf[BUF_LONG]; + sprintf(debug_buff, "disconnected from chat room %s\n", c->name); + debug_print(debug_buff); + c->conn = NULL; + if (c->inpa > -1) + gdk_input_remove(c->inpa); + c->inpa = -1; + c->fd = -1; + aim_conn_kill(gc->oscar_sess, &conn); + sprintf(buf, _("You have been disconnected from chat room %s."), c->name); + do_error_dialog(buf, _("Chat Error!")); + } else if (conn->type == AIM_CONN_TYPE_CHATNAV) { + if (gc->cnpa > -1) + gdk_input_remove(gc->cnpa); + gc->cnpa = -1; + debug_print("removing chatnav input watcher\n"); + aim_conn_kill(gc->oscar_sess, &conn); + } else { + sprintf(debug_buff, "holy crap! generic connection error! %d\n", + conn->type); + debug_print(debug_buff); + aim_conn_kill(gc->oscar_sess, &conn); + } + } + } + } +} + +void oscar_login(struct aim_user *user) { + struct aim_session_t *sess; + struct aim_conn_t *conn; + char buf[256]; + struct gaim_connection *gc; + + sprintf(debug_buff, _("Logging in %s\n"), user->username); + debug_print(debug_buff); + + gc = new_gaim_conn(PROTO_OSCAR, user->username, user->password); + sess = g_new0(struct aim_session_t, 1); + aim_session_init(sess); + /* we need an immediate queue because we don't use a while-loop to + * see if things need to be sent. */ + sess->tx_enqueue = &aim_tx_enqueue__immediate; + gc->oscar_sess = sess; + + sprintf(buf, _("Looking up %s"), FAIM_LOGIN_SERVER); + conn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, FAIM_LOGIN_SERVER); + + if (conn == NULL) { + debug_print(_("internal connection error\n")); + hide_login_progress(gc->username, _("Unable to login to AIM")); + destroy_gaim_conn(gc); + return; + } else if (conn->fd == -1) { + if (conn->status & AIM_CONN_STATUS_RESOLVERR) { + sprintf(debug_buff, _("couldn't resolve host")); + debug_print(debug_buff); debug_print("\n"); + hide_login_progress(gc->username, debug_buff); + } else if (conn->status & AIM_CONN_STATUS_CONNERR) { + sprintf(debug_buff, _("couldn't connect to host")); + debug_print(debug_buff); debug_print("\n"); + hide_login_progress(gc->username, debug_buff); + } + destroy_gaim_conn(gc); + return; + } + g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username); + + aim_conn_addhandler(sess, conn, 0x0017, 0x0007, gaim_parse_login, 0); + aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0); + aim_sendconnack(sess, conn); + aim_request_login(sess, conn, gc->username); + + gc->inpa = gdk_input_add(conn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, conn); + + sprintf(gc->user_info, "%s", user->user_info); + gc->options = user->options; + save_prefs(); /* is this necessary anymore? */ + + debug_print(_("Password sent, waiting for response\n")); +} + +void oscar_close(struct gaim_connection *gc) { + if (gc->protocol != PROTO_OSCAR) return; + if (gc->inpa > 0) + gdk_input_remove(gc->inpa); + gc->inpa = -1; + if (gc->cnpa > 0) + gdk_input_remove(gc->cnpa); + gc->cnpa = -1; + if (gc->paspa > 0) + gdk_input_remove(gc->paspa); + gc->paspa = -1; + aim_logoff(gc->oscar_sess); + g_free(gc->oscar_sess); + debug_print(_("Signed off.\n")); +} + +int gaim_parse_auth_resp(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + struct aim_conn_t *bosconn = NULL; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + sprintf(debug_buff, "inside auth_resp (Screen name: %s)\n", + sess->logininfo.screen_name); + debug_print(debug_buff); + + if (sess->logininfo.errorcode) { + switch (sess->logininfo.errorcode) { + case 0x18: + /* connecting too frequently */ + do_error_dialog(_("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."), _("Gaim - Error")); + plugin_event(event_error, (void *)983, 0, 0); + break; + case 0x05: + /* Incorrect nick/password */ + do_error_dialog(_("Incorrect nickname or password."), _("Gaim - Error")); + plugin_event(event_error, (void *)980, 0, 0); + break; + case 0x1c: + /* client too old */ + do_error_dialog(_("The client version you are using is too old. Please upgrade at http://www.marko.net/gaim/"), _("Gaim - Error")); + plugin_event(event_error, (void *)989, 0, 0); + break; + } + sprintf(debug_buff, "Login Error Code 0x%04x\n", + sess->logininfo.errorcode); + debug_print(debug_buff); + sprintf(debug_buff, "Error URL: %s\n", + sess->logininfo.errorurl); + debug_print(debug_buff); +#ifdef USE_APPLET + set_user_state(offline); +#endif + gdk_input_remove(gc->inpa); + hide_login_progress(gc->username, _("Authentication Failed")); + signoff(gc); + return 0; + } + + + if (sess->logininfo.email) { + sprintf(debug_buff, "Email: %s\n", sess->logininfo.email); + debug_print(debug_buff); + } else { + debug_print("Email is NULL\n"); + } + sprintf(debug_buff, "Closing auth connection...\n"); + debug_print(debug_buff); + gdk_input_remove(gc->inpa); + aim_conn_kill(sess, &command->conn); + + bosconn = aim_newconn(sess, AIM_CONN_TYPE_BOS, sess->logininfo.BOSIP); + if (bosconn == NULL) { +#ifdef USE_APPLET + set_user_state(offline); +#endif + hide_login_progress(gc->username, _("Internal Error")); + destroy_gaim_conn(gc); + return -1; + } else if (bosconn->status != 0) { +#ifdef USE_APPLET + set_user_state(offline); +#endif + hide_login_progress(gc->username, _("Could Not Connect")); + destroy_gaim_conn(gc); + return -1; + } + + aim_conn_addhandler(sess, bosconn, 0x0009, 0x0003, gaim_bosrights, 0); + aim_conn_addhandler(sess, bosconn, 0x0001, 0x0007, gaim_rateresp, 0); /* rate info */ + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ACK, AIM_CB_ACK_ACK, NULL, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_SERVERREADY, gaim_server_ready, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATEINFO, NULL, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_REDIRECT, gaim_handle_redirect, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_STS, AIM_CB_STS_SETREPORTINTERVAL, gaim_reportinterval, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_RIGHTSINFO, gaim_parse_buddyrights, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_ONCOMING, gaim_parse_oncoming, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_BUD, AIM_CB_BUD_OFFGOING, gaim_parse_offgoing, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_INCOMING, gaim_parse_incoming_im, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_ERROR, gaim_parse_locerr, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MISSEDCALL, gaim_parse_misses, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_RATECHANGE, gaim_parse_ratechange, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_EVIL, gaim_parse_evilnotify, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ERROR, gaim_parse_msgerr, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parse_user_info, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_ACK, gaim_parse_msgack, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_CTN, AIM_CB_CTN_DEFAULT, aim_parse_unknown, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_DEFAULT, aim_parse_unknown, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_GEN, AIM_CB_GEN_MOTD, gaim_parse_motd, 0); + + aim_auth_sendcookie(sess, bosconn, sess->logininfo.cookie); + gc->oscar_conn = bosconn; + gc->inpa = gdk_input_add(bosconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, bosconn); + return 1; +} + +int gaim_parse_login(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + struct client_info_s info = {"AOL Instant Messenger (SM), version 4.1.2010/WIN32", 4, 30, 3141, "us", "en", 0x0004, 0x0001, 0x055}; + char *key; + va_list ap; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + va_start(ap, command); + key = va_arg(ap, char *); + va_end(ap); + + aim_send_login(sess, command->conn, gc->username, gc->password, &info, key); + return 1; +} + +int gaim_server_ready(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + static int id = 1; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + switch (command->conn->type) { + case AIM_CONN_TYPE_BOS: + aim_setversions(sess, command->conn); + aim_bos_reqrate(sess, command->conn); /* request rate info */ + debug_print("done with BOS ServerReady\n"); + break; + case AIM_CONN_TYPE_CHATNAV: + debug_print("chatnav: got server ready\n"); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CTN, AIM_CB_CTN_INFO, gaim_chatnav_info, 0); + aim_bos_reqrate(sess, command->conn); + aim_bos_ackrateresp(sess, command->conn); + aim_chatnav_clientready(sess, command->conn); + aim_chatnav_reqrights(sess, command->conn); + break; + case AIM_CONN_TYPE_CHAT: + debug_print("chat: got server ready\n"); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERJOIN, gaim_chat_join, 0); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_USERLEAVE, gaim_chat_leave, 0); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_ROOMINFOUPDATE, gaim_chat_info_update, 0); + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_CHT, AIM_CB_CHT_INCOMINGMSG, gaim_chat_incoming_msg, 0); + aim_bos_reqrate(sess, command->conn); + aim_bos_ackrateresp(sess, command->conn); + aim_chat_clientready(sess, command->conn); + serv_got_joined_chat(gc, id++, aim_chat_getname(command->conn)); + break; + case AIM_CONN_TYPE_RENDEZVOUS: + aim_conn_addhandler(sess, command->conn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0); + break; + default: /* huh? */ + sprintf(debug_buff, "server ready: got unexpected connection type %04x\n", command->conn->type); + debug_print(debug_buff); + break; + } + return 1; +} + +int gaim_handle_redirect(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + int serviceid; + char *ip; + unsigned char *cookie; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + va_start(ap, command); + serviceid = va_arg(ap, int); + ip = va_arg(ap, char *); + cookie = va_arg(ap, unsigned char *); + + switch(serviceid) { + case 0x7: /* Authorizer */ + debug_print("Reconnecting with authorizor...\n"); + { + struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_AUTH, ip); + if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR) + debug_print("unable to reconnect with authorizer\n"); + else { + gc->paspa = gdk_input_add(tstconn->fd, + GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, tstconn); + aim_auth_sendcookie(sess, tstconn, cookie); + } + } + break; + case 0xd: /* ChatNav */ + { + struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHATNAV, ip); + if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR) { + debug_print("unable to connect to chatnav server\n"); + return 1; + } + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0); + aim_auth_sendcookie(sess, tstconn, cookie); + gc->cnpa = gdk_input_add(tstconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, tstconn); + } + debug_print("chatnav: connected\n"); + break; + case 0xe: /* Chat */ + { + struct aim_conn_t *tstconn = aim_newconn(sess, AIM_CONN_TYPE_CHAT, ip); + char *roomname = va_arg(ap, char *); + struct chat_connection *ccon; + if (tstconn == NULL || tstconn->status >= AIM_CONN_STATUS_RESOLVERR) { + debug_print("unable to connect to chat server\n"); + return 1; + } + sprintf(debug_buff, "Connected to chat room %s\n", roomname); + debug_print(debug_buff); + + ccon = g_new0(struct chat_connection, 1); + ccon->conn = tstconn; + ccon->fd = tstconn->fd; + ccon->name = g_strdup(roomname); + + ccon->inpa = gdk_input_add(tstconn->fd, + GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, tstconn); + + gc->oscar_chats = g_slist_append(gc->oscar_chats, ccon); + + aim_chat_attachname(tstconn, roomname); + aim_conn_addhandler(sess, tstconn, 0x0001, 0x0003, gaim_server_ready, 0); + aim_auth_sendcookie(sess, tstconn, cookie); + } + break; + default: /* huh? */ + sprintf(debug_buff, "got redirect for unknown service 0x%04x\n", + serviceid); + debug_print(debug_buff); + break; + } + + va_end(ap); + + return 1; +} + +int gaim_parse_oncoming(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + struct aim_userinfo_s *info; + time_t time_idle; + int type = 0; + + va_list ap; + va_start(ap, command); + info = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + if (info->flags & AIM_FLAG_UNCONFIRMED) + type |= UC_UNCONFIRMED; + else if (info->flags & AIM_FLAG_ADMINISTRATOR) + type |= UC_ADMIN; + else if (info->flags & AIM_FLAG_AOL) + type |= UC_AOL; + else if (info->flags & AIM_FLAG_FREE) + type |= UC_NORMAL; + if (info->flags & AIM_FLAG_AWAY) + type |= UC_UNAVAILABLE; + + if (info->idletime) { + time(&time_idle); + time_idle -= info->idletime*60; + } else + time_idle = 0; + + serv_got_update(info->sn, 1, info->warnlevel/10, info->onlinesince, + time_idle, type, info->capabilities); + + return 1; +} + +int gaim_parse_offgoing(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + char *sn; + va_list ap; + + va_start(ap, command); + sn = va_arg(ap, char *); + va_end(ap); + + serv_got_update(sn, 0, 0, 0, 0, 0, 0); + + return 1; +} + +static void accept_directim(GtkWidget *w, GtkWidget *m) +{ + struct aim_conn_t *newconn; + struct aim_directim_priv *priv; + struct gaim_connection *gc; + int watcher; + + priv = (struct aim_directim_priv *)gtk_object_get_user_data(GTK_OBJECT(m)); + gc = (struct gaim_connection *)gtk_object_get_user_data(GTK_OBJECT(w)); + gtk_widget_destroy(m); + + if (!(newconn = aim_directim_connect(gc->oscar_sess, gc->oscar_conn, priv))) { + debug_print("imimage: could not connect\n"); + return; + } + + aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0); + aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0); + + watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, newconn); + + sprintf(debug_buff, "DirectIM: connected to %s\n", priv->sn); + debug_print(debug_buff); + + serv_got_imimage(gc, priv->sn, priv->cookie, priv->ip, newconn, watcher); + + g_free(priv); +} + +static void cancel_directim(GtkWidget *w, GtkWidget *m) +{ + gtk_widget_destroy(m); +} + +static void directim_dialog(struct gaim_connection *gc, struct aim_directim_priv *priv) +{ + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *hbox; + GtkWidget *label; + GtkWidget *yes; + GtkWidget *no; + char buf[BUF_LONG]; + + window = gtk_window_new(GTK_WINDOW_DIALOG); + gtk_window_set_title(GTK_WINDOW(window), _("Accept Direct IM?")); + gtk_window_set_wmclass(GTK_WINDOW(window), "directim", "Gaim"); + gtk_widget_realize(window); + aol_icon(window->window); + gtk_object_set_user_data(GTK_OBJECT(window), (void *)priv); + + vbox = gtk_vbox_new(TRUE, 5); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show(vbox); + + sprintf(buf, _("%s has requested to directly connect to your computer. " + "Do you accept?"), priv->sn); + label = gtk_label_new(buf); + gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 5); + gtk_widget_show(label); + + hbox = gtk_hbox_new(TRUE, 10); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); + gtk_widget_show(hbox); + + yes = picture_button(window, _("Accept"), ok_xpm); + gtk_box_pack_start(GTK_BOX(hbox), yes, FALSE, FALSE, 5); + gtk_object_set_user_data(GTK_OBJECT(yes), gc); + + no = picture_button(window, _("Cancel"), cancel_xpm); + gtk_box_pack_end(GTK_BOX(hbox), no, FALSE, FALSE, 5); + + gtk_signal_connect(GTK_OBJECT(yes), "clicked", + GTK_SIGNAL_FUNC(accept_directim), window); + gtk_signal_connect(GTK_OBJECT(no), "clicked", + GTK_SIGNAL_FUNC(cancel_directim), window); + + gtk_widget_show(window); +} + +int gaim_parse_incoming_im(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + int channel; + va_list ap; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + va_start(ap, command); + channel = va_arg(ap, int); + + /* channel 1: standard message */ + if (channel == 1) { + struct aim_userinfo_s *userinfo; + char *msg = NULL; + char *tmp = g_malloc(BUF_LONG); + u_int icbmflags = 0; + u_short flag1, flag2; + + userinfo = va_arg(ap, struct aim_userinfo_s *); + msg = va_arg(ap, char *); + icbmflags = va_arg(ap, u_int); + flag1 = (u_short)va_arg(ap, u_int); + flag2 = (u_short)va_arg(ap, u_int); + va_end(ap); + + g_snprintf(tmp, BUF_LONG, "%s", msg); + serv_got_im(gc, userinfo->sn, tmp, icbmflags & AIM_IMFLAGS_AWAY); + g_free(tmp); + } else if (channel == 2) { + struct aim_userinfo_s *userinfo; + int rendtype = va_arg(ap, int); + if (rendtype & AIM_CAPS_CHAT) { + char *msg, *encoding, *lang; + struct aim_chat_roominfo *roominfo; + + userinfo = va_arg(ap, struct aim_userinfo_s *); + roominfo = va_arg(ap, struct aim_chat_roominfo *); + msg = va_arg(ap, char *); + encoding = va_arg(ap, char *); + lang = va_arg(ap, char *); + va_end(ap); + + serv_got_chat_invite(gc, + roominfo->name, + roominfo->exchange, + userinfo->sn, + msg); + } else if (rendtype & AIM_CAPS_SENDFILE) { + /* libfaim won't tell us that we got this just yet */ + } else if (rendtype & AIM_CAPS_GETFILE) { + /* nor will it tell us this. but it's still there */ + } else if (rendtype & AIM_CAPS_VOICE) { + /* this one libfaim tells us unuseful info about */ + } else if (rendtype & AIM_CAPS_BUDDYICON) { + /* bah */ + } else if (rendtype & AIM_CAPS_IMIMAGE) { + /* DirectIM stuff */ + struct aim_directim_priv *priv, *priv2; + + userinfo = va_arg(ap, struct aim_userinfo_s *); + priv = va_arg(ap, struct aim_directim_priv *); + va_end(ap); + + sprintf(debug_buff, "DirectIM request from %s (%s)\n", userinfo->sn, priv->ip); + debug_print(debug_buff); + + priv2 = g_new0(struct aim_directim_priv, 1); + strcpy(priv2->cookie, priv->cookie); + strcpy(priv2->sn, priv->sn); + strcpy(priv2->ip, priv->ip); + directim_dialog(gc, priv2); + } else { + sprintf(debug_buff, "Unknown rendtype %d\n", rendtype); + debug_print(debug_buff); + } + } + + return 1; +} + +int gaim_parse_misses(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + u_short chan, nummissed, reason; + struct aim_userinfo_s *userinfo; + char buf[1024]; + + va_start(ap, command); + chan = (u_short)va_arg(ap, u_int); + userinfo = va_arg(ap, struct aim_userinfo_s *); + nummissed = (u_short)va_arg(ap, u_int); + reason = (u_short)va_arg(ap, u_int); + va_end(ap); + + switch(reason) { + case 1: + /* message too large */ + sprintf(buf, _("You missed a message from %s because it was too large."), userinfo->sn); + do_error_dialog(buf, _("Gaim - Error")); + plugin_event(event_error, (void *)961, 0, 0); + break; + default: + sprintf(buf, _("You missed a message from %s for unknown reasons."), userinfo->sn); + do_error_dialog(buf, _("Gaim - Error")); + plugin_event(event_error, (void *)970, 0, 0); + break; + } + + return 1; +} + +int gaim_parse_msgerr(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + char *destn; + u_short reason; + char buf[1024]; + + va_start(ap, command); + destn = va_arg(ap, char *); + reason = (u_short)va_arg(ap, u_int); + va_end(ap); + + sprintf(buf, _("Your message to %s did not get sent: %s"), destn, + (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); + do_error_dialog(buf, _("Gaim - Error")); + + return 1; +} + +int gaim_parse_locerr(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + char *destn; + u_short reason; + char buf[1024]; + + va_start(ap, command); + destn = va_arg(ap, char *); + reason = (u_short)va_arg(ap, u_int); + va_end(ap); + + sprintf(buf, _("User information for %s unavailable: %s"), destn, + (reason < msgerrreasonlen) ? msgerrreason[reason] : _("Reason unknown")); + do_error_dialog(buf, _("Gaim - Error")); + + return 1; +} + +int gaim_parse_user_info(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + struct aim_userinfo_s *info; + char *prof_enc = NULL, *prof = NULL; + u_short infotype; + char buf[BUF_LONG]; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + va_list ap; + + va_start(ap, command); + info = va_arg(ap, struct aim_userinfo_s *); + prof_enc = va_arg(ap, char *); + prof = va_arg(ap, char *); + infotype = (u_short)va_arg(ap, u_int); + va_end(ap); + + if (prof == NULL || !strlen(prof)) { + /* no info/away message */ + char buf[1024]; + sprintf(buf, _("%s has no info/away message."), info->sn); + do_error_dialog(buf, _("Gaim - Error")); + plugin_event(event_error, (void *)977, 0, 0); + return 1; + } + + snprintf(buf, sizeof buf, _("Username : %s\n
" + "Warning Level : %d %%\n
" + "Online Since : %s
" + "Idle Minutes : %d\n


" + "%s\n"), + info->sn, + info->warnlevel/10, + asctime(localtime(&info->onlinesince)), + info->idletime, + infotype == AIM_GETINFO_GENERALINFO ? prof : + away_subs(prof, gc->username)); + g_show_info_text(away_subs(buf, gc->username)); + + return 1; +} + +int gaim_parse_motd(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + char *msg; + u_short id; + va_list ap; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + va_start(ap, command); + id = (u_short)va_arg(ap, u_int); + msg = va_arg(ap, char *); + va_end(ap); + + sprintf(debug_buff, "MOTD: %s (%d)\n", msg, id); + debug_print(debug_buff); + sprintf(debug_buff, "Gaim %s / Libfaim %s\n", + VERSION, aim_getbuildstring()); + debug_print(debug_buff); + if (id != 4) + do_error_dialog(_("Your connection may be lost."), + _("AOL error")); + + if (gc->keepalive < 0) + update_keepalive(gc, gc->keepalive); + + return 1; +} + +int gaim_chatnav_info(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + u_short type; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + va_start(ap, command); + type = (u_short)va_arg(ap, u_int); + + switch(type) { + case 0x0002: { + int maxrooms; + struct aim_chat_exchangeinfo *exchanges; + int exchangecount, i = 0; + + maxrooms = (u_char)va_arg(ap, u_int); + exchangecount = va_arg(ap, int); + exchanges = va_arg(ap, struct aim_chat_exchangeinfo *); + va_end(ap); + + debug_print("chat info: Chat Rights:\n"); + sprintf(debug_buff, "chat info: \tMax Concurrent Rooms: %d\n", maxrooms); + debug_print(debug_buff); + sprintf(debug_buff, "chat info: \tExchange List: (%d total)\n", exchangecount); + debug_print(debug_buff); + while (i < exchangecount) { + sprintf(debug_buff, "chat info: \t\t%x: %s (%s/%s)\n", + exchanges[i].number, + exchanges[i].name, + exchanges[i].charset1, + exchanges[i].lang1); + debug_print(debug_buff); + i++; + } + if (gc->create_exchange) { + sprintf(debug_buff, "creating room %s\n", + gc->create_name); + debug_print(debug_buff); + aim_chatnav_createroom(sess, command->conn, gc->create_name, gc->create_exchange); + gc->create_exchange = 0; + g_free(gc->create_name); + gc->create_name = NULL; + } + } + break; + case 0x0008: { + char *fqcn, *name, *ck; + u_short instance, flags, maxmsglen, maxoccupancy, unknown; + unsigned char createperms; + unsigned long createtime; + + fqcn = va_arg(ap, char *); + instance = (u_short)va_arg(ap, u_int); + flags = (u_short)va_arg(ap, u_int); + createtime = va_arg(ap, unsigned long); + maxmsglen = (u_short)va_arg(ap, u_int); + maxoccupancy = (u_short)va_arg(ap, u_int); + createperms = (unsigned char)va_arg(ap, int); + unknown = (u_short)va_arg(ap, u_int); + name = va_arg(ap, char *); + ck = va_arg(ap, char *); + va_end(ap); + + sprintf(debug_buff, "created room: %s %d %d %lu %d %d %d %d %s %s\n", fqcn, instance, flags, createtime, maxmsglen, maxoccupancy, createperms, unknown, name, ck); + debug_print(debug_buff); + if (flags & 0x4) { + sprintf(debug_buff, "joining %s on exchange 5\n", name); + debug_print(debug_buff); + aim_chat_join(gc->oscar_sess, gc->oscar_conn, 5, ck); + } else + sprintf(debug_buff, "joining %s on exchange 4\n", name);{ + debug_print(debug_buff); + aim_chat_join(gc->oscar_sess, gc->oscar_conn, 4, ck); + } + } + break; + default: + va_end(ap); + sprintf(debug_buff, "chatnav info: unknown type (%04x)\n", type); + debug_print(debug_buff); + break; + } + return 1; +} + +int gaim_chat_join(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + int count, i = 0; + struct aim_userinfo_s *info; + struct gaim_connection *g = find_gaim_conn_by_aim_sess(sess); + + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + + va_start(ap, command); + count = va_arg(ap, int); + info = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + while(bcs) { + b = (struct conversation *)bcs->data; + if (!strcasecmp(b->name, (char *)command->conn->priv)) + break; + bcs = bcs->next; + b = NULL; + } + if (!b) + return 1; + + while (i < count) + add_chat_buddy(b, info[i++].sn); + + return 1; +} + +int gaim_chat_leave(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + int count, i = 0; + struct aim_userinfo_s *info; + struct gaim_connection *g = find_gaim_conn_by_aim_sess(sess); + + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + + va_start(ap, command); + count = va_arg(ap, int); + info = va_arg(ap, struct aim_userinfo_s *); + va_end(ap); + + while(bcs) { + b = (struct conversation *)bcs->data; + if (!strcasecmp(b->name, (char *)command->conn->priv)) + break; + bcs = bcs->next; + b = NULL; + } + if (!b) + return 1; + + while (i < count) + remove_chat_buddy(b, info[i++].sn); + + return 1; +} + +int gaim_chat_info_update(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + debug_print("inside chat_info_update\n"); + return 1; +} + +int gaim_chat_incoming_msg(struct aim_session_t *sess, + struct command_rx_struct *command, ...) { + va_list ap; + struct aim_userinfo_s *info; + char *msg; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + GSList *bcs = gc->buddy_chats; + struct conversation *b = NULL; + + va_start(ap, command); + info = va_arg(ap, struct aim_userinfo_s *); + msg = va_arg(ap, char *); + + while(bcs) { + b = (struct conversation *)bcs->data; + if (!strcasecmp(b->name, (char *)command->conn->priv)) + break; + bcs = bcs->next; + b = NULL; + } + if (!b) + return 0; + + serv_got_chat_in(gc, b->id, info->sn, 0, msg); + + return 1; +} + + /* + * Recieved in response to an IM sent with the AIM_IMFLAGS_ACK option. + */ +int gaim_parse_msgack(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + u_short type; + char *sn = NULL; + + va_start(ap, command); + type = (u_short)va_arg(ap, u_int); + sn = va_arg(ap, char *); + va_end(ap); + + sprintf(debug_buff, "Sent message to %s.\n", sn); + debug_print(debug_buff); + + return 1; +} + +int gaim_parse_ratechange(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + unsigned long newrate; + + va_start(ap, command); + newrate = va_arg(ap, unsigned long); + va_end(ap); + + sprintf(debug_buff, "ratechange: %lu\n", newrate); + debug_print(debug_buff); + + return 1; +} + +int gaim_parse_evilnotify(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + char *sn; + + va_start(ap, command); + sn = va_arg(ap, char *); + va_end(ap); + + serv_got_eviled(sn, 0); + + return 1; +} + +int gaim_rateresp(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + switch (command->conn->type) { + case AIM_CONN_TYPE_BOS: + aim_bos_ackrateresp(sess, command->conn); + aim_bos_reqpersonalinfo(sess, command->conn); + aim_bos_reqlocaterights(sess, command->conn); + aim_bos_setprofile(sess, command->conn, gc->user_info, NULL, gaim_caps); + aim_bos_reqbuddyrights(sess, command->conn); + + if (mainwindow) + gtk_widget_hide(mainwindow); + show_buddy_list(); + +#ifdef USE_APPLET + if (general_options & OPT_GEN_APP_BUDDY_SHOW) { + refresh_buddy_window(); + createOnlinePopup(); + applet_buddy_show = TRUE; + } else { + gtk_widget_hide(blist); + applet_buddy_show = FALSE; + } + set_user_state(online); +#else + refresh_buddy_window(); +#endif + + serv_finish_login(gc); + gaim_setup(gc); + + if (bud_list_cache_exists(gc)) + do_import(NULL, gc); + + debug_print("buddy list loaded\n"); + + setup_buddy_chats(); + + aim_addicbmparam(sess, command->conn); + aim_bos_reqicbmparaminfo(sess, command->conn); + + aim_bos_reqrights(sess, command->conn); + aim_bos_setgroupperm(sess, command->conn, AIM_FLAG_ALLUSERS); + aim_bos_setprivacyflags(sess, command->conn, AIM_PRIVFLAGS_ALLOWIDLE | + AIM_PRIVFLAGS_ALLOWMEMBERSINCE); + + break; + default: + sprintf(debug_buff, "got rate response for unhandled connection type %04x\n", + command->conn->type); + debug_print(debug_buff); + break; + } + + return 1; +} + +int gaim_reportinterval(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + if (command->data) { + sprintf(debug_buff, "minimum report interval: %d (seconds?)\n", aimutil_get16(command->data+10)); + debug_print(debug_buff); + } else + debug_print("NULL minimum report interval!\n"); + return 1; +} + +int gaim_parse_buddyrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + u_short maxbuddies, maxwatchers; + + va_start(ap, command); + maxbuddies = (u_short)va_arg(ap, u_int); + maxwatchers = (u_short)va_arg(ap, u_int); + va_end(ap); + + sprintf(debug_buff, "buddy list rights: Max buddies = %d / Max watchers = %d\n", maxbuddies, maxwatchers); + debug_print(debug_buff); + + return 1; +} + +int gaim_bosrights(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + u_short maxpermits, maxdenies; + va_list ap; + + va_start(ap, command); + maxpermits = (u_short)va_arg(ap, u_int); + maxdenies = (u_short)va_arg(ap, u_int); + va_end(ap); + + sprintf(debug_buff, "BOS rights: Max permit = %d / Max deny = %d\n", maxpermits, maxdenies); + debug_print(debug_buff); + + aim_bos_clientready(sess, command->conn); + + aim_bos_reqservice(sess, command->conn, AIM_CONN_TYPE_CHATNAV); + + return 1; +} + +int gaim_directim_incoming(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + char *sn = NULL, *msg = NULL; + struct aim_conn_t *conn; + struct gaim_connection *gc = find_gaim_conn_by_aim_sess(sess); + + va_start(ap, command); + conn = va_arg(ap, struct aim_conn_t *); + sn = va_arg(ap, char *); + msg = va_arg(ap, char *); + va_end(ap); + + sprintf(debug_buff, "Got DirectIM message from %s\n", sn); + debug_print(debug_buff); + + serv_got_im(gc, sn, msg, 0); + + return 1; +} + +/* this is such a f*cked up function */ +int gaim_directim_initiate(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + struct aim_directim_priv *priv; + struct aim_conn_t *newconn; + struct conversation *cnv; + int watcher; + + va_start(ap, command); + newconn = va_arg(ap, struct aim_conn_t *); + va_end(ap); + + priv = (struct aim_directim_priv *)newconn->priv; + + sprintf(debug_buff, "DirectIM: initiate success to %s\n", priv->sn); + debug_print(debug_buff); + + cnv = find_conversation(priv->sn); + gdk_input_remove(cnv->watcher); + watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + oscar_callback, newconn); + make_direct(cnv, TRUE, newconn, watcher); + + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINCOMING, gaim_directim_incoming, 0); + aim_conn_addhandler(sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMTYPING, gaim_directim_typing, 0); + + return 1; +} + +int gaim_directim_typing(struct aim_session_t *sess, struct command_rx_struct *command, ...) { + va_list ap; + char *sn; + + va_start(ap, command); + sn = va_arg(ap, char *); + va_end(ap); + + /* I had to leave this. It's just too funny. It reminds me of my sister. */ + sprintf(debug_buff, "ohmigod! %s has started typing (DirectIM). He's going to send you a message! *squeal*\n", sn); + debug_print(debug_buff); + + return 1; +} + +void oscar_do_directim(struct gaim_connection *gc, char *name) { + struct aim_conn_t *newconn = aim_directim_initiate(gc->oscar_sess, gc->oscar_conn, NULL, name); + struct conversation *cnv = find_conversation(name); /* this will never be null because it just got set up */ + cnv->conn = newconn; + cnv->watcher = gdk_input_add(newconn->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, oscar_callback, newconn); + aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, gaim_directim_initiate, 0); +} + +static void oscar_keepalive(struct gaim_connection *gc) { + aim_flap_nop(gc->oscar_sess, gc->oscar_conn); +} + +static char *oscar_name() { + return "Oscar"; +} + +char *name() { + return "Oscar"; +} + +char *description() { + return "Allows gaim to use the Oscar protocol"; +} + +static void oscar_send_im(struct gaim_connection *gc, char *name, char *message, int away) { + struct conversation *cnv = find_conversation(name); + if (cnv && cnv->is_direct) { + debug_printf("Sending DirectIM to %s\n", name); + aim_send_im_direct(gc->oscar_sess, cnv->conn, message); + } else { + if (away) + aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_AWAY, message); + else + aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_ACK, message); + } +} + +static void oscar_get_info(struct gaim_connection *g, char *name) { + aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_GENERALINFO); +} + +static void oscar_get_away_msg(struct gaim_connection *g, char *name) { + aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_AWAYMESSAGE); +} + +static void oscar_set_dir(struct gaim_connection *g, char *first, char *middle, char *last, + char *maiden, char *city, char *state, char *country, int web) { + /* FIXME : some of these things are wrong, but i'm lazy */ + aim_setdirectoryinfo(g->oscar_sess, g->oscar_conn, first, middle, last, + maiden, NULL, NULL, city, state, NULL, 0, web); +} + + +static void oscar_set_idle(struct gaim_connection *g, int time) { + aim_bos_setidle(g->oscar_sess, g->oscar_conn, time); +} + +static void oscar_set_info(struct gaim_connection *g, char *info) { + if (awaymessage) + aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info, + awaymessage->message, gaim_caps); + else + aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info, + NULL, gaim_caps); +} + +static void oscar_set_away(struct gaim_connection *g, char *message) { + aim_bos_setprofile(g->oscar_sess, g->oscar_conn, g->user_info, message, gaim_caps); +} + +static void oscar_warn(struct gaim_connection *g, char *name, int anon) { + aim_send_warning(g->oscar_sess, g->oscar_conn, name, anon); +} + +static void oscar_dir_search(struct gaim_connection *g, char *first, char *middle, char *last, + char *maiden, char *city, char *state, char *country, char *email) { + if (strlen(email)) + aim_usersearch_address(g->oscar_sess, g->oscar_conn, email); +} + +static void oscar_add_buddy(struct gaim_connection *g, char *name) { + aim_add_buddy(g->oscar_sess, g->oscar_conn, name); +} + +static void oscar_add_buddies(struct gaim_connection *g, GList *buddies) { + char buf[MSG_LEN]; + int n = 0; + while (buddies) { + if (n > MSG_LEN - 18) { + aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf); + n = 0; + } + n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", (char *)buddies->data); + buddies = buddies->next; + } + aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf); +} + +static void oscar_remove_buddy(struct gaim_connection *g, char *name) { + aim_remove_buddy(g->oscar_sess, g->oscar_conn, name); +} + +static void oscar_join_chat(struct gaim_connection *g, int exchange, char *name) { + struct aim_conn_t *cur = NULL; + sprintf(debug_buff, "Attempting to join chat room %s.\n", name); + debug_print(debug_buff); + if ((cur = aim_getconn_type(g->oscar_sess, AIM_CONN_TYPE_CHATNAV))) { + debug_print("chatnav exists, creating room\n"); + aim_chatnav_createroom(g->oscar_sess, cur, name, exchange); + } else { + /* this gets tricky */ + debug_print("chatnav does not exist, opening chatnav\n"); + g->create_exchange = exchange; + g->create_name = g_strdup(name); + aim_bos_reqservice(g->oscar_sess, g->oscar_conn, AIM_CONN_TYPE_CHATNAV); + } +} + +static void oscar_chat_invite(struct gaim_connection *g, int id, char *message, char *name) { + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + + while (bcs) { + b = (struct conversation *)bcs->data; + if (id == b->id) + break; + bcs = bcs->next; + b = NULL; + } + + if (!b) + return; + + aim_chat_invite(g->oscar_sess, g->oscar_conn, name, + message ? message : "", 0x4, b->name, 0x0); +} + +static void oscar_chat_leave(struct gaim_connection *g, int id) { + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + struct chat_connection *c = NULL; + int count = 0; + + while (bcs) { + count++; + b = (struct conversation *)bcs->data; + if (id == b->id) + break; + bcs = bcs->next; + b = NULL; + } + + if (!b) + return; + + sprintf(debug_buff, "Attempting to leave room %s (currently in %d rooms)\n", + b->name, count); + debug_print(debug_buff); + + c = find_oscar_chat(g, b->name); + if (c != NULL) { + g->oscar_chats = g_slist_remove(g->oscar_chats, c); + gdk_input_remove(c->inpa); + if (g && g->oscar_sess) + aim_conn_kill(g->oscar_sess, &c->conn); + g_free(c->name); + g_free(c); + } + /* we do this because with Oscar it doesn't tell us we left */ + serv_got_chat_left(g, b->id); +} + +static void oscar_chat_whisper(struct gaim_connection *g, int id, char *who, char *message) { + do_error_dialog("Sorry, Oscar doesn't whisper. Send an IM. (The last message was not received.)", + "Gaim - Chat"); +} + +static void oscar_chat_send(struct gaim_connection *g, int id, char *message) { + struct aim_conn_t *cn; + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + + while (bcs) { + b = (struct conversation *)bcs->data; + if (id == b->id) + break; + bcs = bcs->next; + b = NULL; + } + if (!b) + return; + + cn = aim_chat_getconn(g->oscar_sess, b->name); + aim_chat_send_im(g->oscar_sess, cn, message); +} + +struct prpl *oscar_init() { + struct prpl *ret = g_new0(struct prpl, 1); + + ret->protocol = PROTO_OSCAR; + ret->name = oscar_name; + ret->login = oscar_login; + ret->close = oscar_close; + ret->send_im = oscar_send_im; + ret->set_info = oscar_set_info; + ret->get_info = oscar_get_info; + ret->set_away = oscar_set_away; + ret->get_away_msg = oscar_get_away_msg; + ret->set_dir = oscar_set_dir; + ret->get_dir = NULL; /* Oscar really doesn't have this */ + ret->dir_search = oscar_dir_search; + ret->set_idle = oscar_set_idle; + ret->change_passwd = NULL; /* Oscar doesn't have this either */ + ret->add_buddy = oscar_add_buddy; + ret->add_buddies = oscar_add_buddies; + ret->remove_buddy = oscar_remove_buddy; + ret->add_permit = NULL; /* Oscar's permit/deny stuff is messed up */ + ret->add_deny = NULL; /* at least, i can't figure it out :-P */ + ret->warn = oscar_warn; + ret->accept_chat = NULL; /* oscar doesn't have accept, it just joins */ + ret->join_chat = oscar_join_chat; + ret->chat_invite = oscar_chat_invite; + ret->chat_leave = oscar_chat_leave; + ret->chat_whisper = oscar_chat_whisper; + ret->chat_send = oscar_chat_send; + ret->keepalive = oscar_keepalive; + + return ret; +} + +int gaim_plugin_init(void *handle) { + protocols = g_slist_append(protocols, oscar_init()); + return 0; +} diff -r 82c5865f7cfe -r 7e231bc0018a sounds/Makefile.am --- a/sounds/Makefile.am Thu Oct 12 18:59:36 2000 +0000 +++ b/sounds/Makefile.am Fri Oct 13 07:24:40 2000 +0000 @@ -1,4 +1,4 @@ -bin_PROGRAMS = au2h +noinst_PROGRAMS = au2h au2h_SOURCES = au2h.c diff -r 82c5865f7cfe -r 7e231bc0018a src/Makefile.am --- a/src/Makefile.am Thu Oct 12 18:59:36 2000 +0000 +++ b/src/Makefile.am Fri Oct 13 07:24:40 2000 +0000 @@ -21,6 +21,7 @@ plugins.c \ prefs.c \ proxy.c \ + prpl.c \ rvous.c \ server.c \ sound.c \ @@ -51,6 +52,7 @@ plugins.c \ prefs.c \ proxy.c \ + prpl.c \ rvous.c \ server.c \ sound.c \ @@ -63,4 +65,4 @@ CFLAGS += -DLOCALEDIR=\"$(datadir)/locale\" $(DEBUG_CFLAGS) LDFLAGS += $(DEBUG_LDFLAGS) -EXTRA_DIST = gaim.h proxy.h gnome_applet_mgr.h gtkhtml.h gtkticker.h convo.h multi.h +EXTRA_DIST = gaim.h proxy.h gnome_applet_mgr.h gtkhtml.h gtkticker.h convo.h multi.h prpl.h diff -r 82c5865f7cfe -r 7e231bc0018a src/aim.c --- a/src/aim.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/aim.c Fri Oct 13 07:24:40 2000 +0000 @@ -368,6 +368,8 @@ #else + static_proto_init(); + show_login(); auto_login(); gtk_main(); diff -r 82c5865f7cfe -r 7e231bc0018a src/dialogs.c --- a/src/dialogs.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/dialogs.c Fri Oct 13 07:24:40 2000 +0000 @@ -1153,6 +1153,7 @@ save_prefs(); if (gc) { + g_snprintf(gc->user_info, sizeof(gc->user_info), "%s", junk); buf = g_malloc(strlen(junk) * 4); if (!buf) { buf = g_malloc(1); @@ -1609,11 +1610,9 @@ gtk_text_set_word_wrap(GTK_TEXT(b->text), TRUE); gtk_text_set_editable(GTK_TEXT(b->text), TRUE); gtk_widget_set_usize(b->text, 350, 100); - /* is this necessary? - if (users) + if (aim_users) gtk_text_insert(GTK_TEXT(b->text), NULL, NULL, NULL, - ((struct aim_user *)users->data)->user_info, -1); - */ + ((struct aim_user *)aim_users->data)->user_info, -1); gtk_widget_show(b->text); diff -r 82c5865f7cfe -r 7e231bc0018a src/multi.c --- a/src/multi.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/multi.c Fri Oct 13 07:24:40 2000 +0000 @@ -20,6 +20,7 @@ */ #include +#include "prpl.h" #include "multi.h" #include "gaim.h" #include "gnome_applet_mgr.h" @@ -49,6 +50,7 @@ { struct gaim_connection *gc = g_new0(struct gaim_connection, 1); gc->protocol = proto; + gc->prpl = find_prpl(proto); g_snprintf(gc->username, sizeof(gc->username), "%s", username); g_snprintf(gc->password, sizeof(gc->password), "%s", password); gc->keepalive = -1; @@ -122,15 +124,11 @@ static char *proto_name(int proto) { - switch (proto) { - case PROTO_TOC: - return "TOC"; - case PROTO_OSCAR: - return "Oscar"; - default: - /* PRPL */ - return "Other"; - } + struct prpl *p = find_prpl(proto); + if (p && p->name) + return (*p->name)(); + else + return "Unknown"; } static GtkWidget *generate_list() @@ -228,7 +226,6 @@ return; } u = g_new0(struct aim_user, 1); - u->protocol = PROTO_TOC; g_snprintf(u->username, sizeof(u->username), "%s", txt); txt = gtk_entry_get_text(GTK_ENTRY(tmpusr.pass)); g_snprintf(u->password, sizeof(u->password), "%s", txt); @@ -269,6 +266,8 @@ GtkWidget *optmenu; GtkWidget *menu; GtkWidget *opt; + GSList *p = protocols; + struct prpl *e; /* PRPL: should we set some way to update these when new protocols get added? */ optmenu = gtk_option_menu_new(); @@ -277,18 +276,19 @@ menu = gtk_menu_new(); - /* PRPL: we need to have some way of getting all the plugin names, etc */ - opt = gtk_menu_item_new_with_label("TOC"); - gtk_object_set_user_data(GTK_OBJECT(opt), u); - gtk_signal_connect(GTK_OBJECT(opt), "activate", GTK_SIGNAL_FUNC(set_prot), (void *)PROTO_TOC); - gtk_menu_append(GTK_MENU(menu), opt); - gtk_widget_show(opt); - - opt = gtk_menu_item_new_with_label("Oscar"); - gtk_object_set_user_data(GTK_OBJECT(opt), u); - gtk_signal_connect(GTK_OBJECT(opt), "activate", GTK_SIGNAL_FUNC(set_prot), (void *)PROTO_OSCAR); - gtk_menu_append(GTK_MENU(menu), opt); - gtk_widget_show(opt); + while (p) { + e = (struct prpl *)p->data; + if (e->name) + opt = gtk_menu_item_new_with_label((*e->name)()); + else + opt = gtk_menu_item_new_with_label("Unknown"); + gtk_object_set_user_data(GTK_OBJECT(opt), u); + gtk_signal_connect(GTK_OBJECT(opt), "activate", + GTK_SIGNAL_FUNC(set_prot), (void *)e->protocol); + gtk_menu_append(GTK_MENU(menu), opt); + gtk_widget_show(opt); + p = p->next; + } gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); u->tmp_protocol = u->protocol; diff -r 82c5865f7cfe -r 7e231bc0018a src/multi.h --- a/src/multi.h Thu Oct 12 18:59:36 2000 +0000 +++ b/src/multi.h Fri Oct 13 07:24:40 2000 +0000 @@ -34,6 +34,7 @@ /* we need to do either oscar or TOC */ /* we make this as an int in case if we want to add more protocols later */ int protocol; + struct prpl *prpl; /* let's do the oscar-specific stuff first since i know it better */ struct aim_session_t *oscar_sess; diff -r 82c5865f7cfe -r 7e231bc0018a src/oscar.c --- a/src/oscar.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/oscar.c Fri Oct 13 07:24:40 2000 +0000 @@ -20,6 +20,8 @@ * */ +#ifndef DYNAMIC_OSCAR + #ifdef HAVE_CONFIG_H #include "../config.h" #endif @@ -38,6 +40,7 @@ #include #include #include "multi.h" +#include "prpl.h" #include "gaim.h" #include "aim.h" #include "gnome_applet_mgr.h" @@ -1301,23 +1304,218 @@ aim_conn_addhandler(gc->oscar_sess, newconn, AIM_CB_FAM_OFT, AIM_CB_OFT_DIRECTIMINITIATE, gaim_directim_initiate, 0); } -void send_keepalive(gpointer d) { - struct gaim_connection *gc = (struct gaim_connection *)d; - debug_print("sending oscar NOP\n"); - if (gc->protocol == PROTO_OSCAR) { /* keeping it open for TOC */ - aim_flap_nop(gc->oscar_sess, gc->oscar_conn); - } else if (gc->protocol == PROTO_TOC) { - sflap_send(gc, "", 0, TYPE_KEEPALIVE); +static void oscar_keepalive(struct gaim_connection *gc) { + aim_flap_nop(gc->oscar_sess, gc->oscar_conn); +} + +static char *oscar_name() { + return "Oscar"; +} + +static void oscar_send_im(struct gaim_connection *gc, char *name, char *message, int away) { + struct conversation *cnv = find_conversation(name); + if (cnv && cnv->is_direct) { + debug_printf("Sending DirectIM to %s\n", name); + aim_send_im_direct(gc->oscar_sess, cnv->conn, message); + } else { + if (away) + aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_AWAY, message); + else + aim_send_im(gc->oscar_sess, gc->oscar_conn, name, AIM_IMFLAGS_ACK, message); + } +} + +static void oscar_get_info(struct gaim_connection *g, char *name) { + aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_GENERALINFO); +} + +static void oscar_get_away_msg(struct gaim_connection *g, char *name) { + aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_AWAYMESSAGE); +} + +static void oscar_set_dir(struct gaim_connection *g, char *first, char *middle, char *last, + char *maiden, char *city, char *state, char *country, int web) { + /* FIXME : some of these things are wrong, but i'm lazy */ + aim_setdirectoryinfo(g->oscar_sess, g->oscar_conn, first, middle, last, + maiden, NULL, NULL, city, state, NULL, 0, web); +} + + +static void oscar_set_idle(struct gaim_connection *g, int time) { + aim_bos_setidle(g->oscar_sess, g->oscar_conn, time); +} + +static void oscar_set_info(struct gaim_connection *g, char *info) { + if (awaymessage) + aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info, + awaymessage->message, gaim_caps); + else + aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info, + NULL, gaim_caps); +} + +static void oscar_set_away(struct gaim_connection *g, char *message) { + aim_bos_setprofile(g->oscar_sess, g->oscar_conn, g->user_info, message, gaim_caps); +} + +static void oscar_warn(struct gaim_connection *g, char *name, int anon) { + aim_send_warning(g->oscar_sess, g->oscar_conn, name, anon); +} + +static void oscar_dir_search(struct gaim_connection *g, char *first, char *middle, char *last, + char *maiden, char *city, char *state, char *country, char *email) { + if (strlen(email)) + aim_usersearch_address(g->oscar_sess, g->oscar_conn, email); +} + +static void oscar_add_buddy(struct gaim_connection *g, char *name) { + aim_add_buddy(g->oscar_sess, g->oscar_conn, name); +} + +static void oscar_add_buddies(struct gaim_connection *g, GList *buddies) { + char buf[MSG_LEN]; + int n = 0; + while (buddies) { + if (n > MSG_LEN - 18) { + aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf); + n = 0; + } + n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", (char *)buddies->data); + buddies = buddies->next; + } + aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf); +} + +static void oscar_remove_buddy(struct gaim_connection *g, char *name) { + aim_remove_buddy(g->oscar_sess, g->oscar_conn, name); +} + +static void oscar_join_chat(struct gaim_connection *g, int exchange, char *name) { + struct aim_conn_t *cur = NULL; + sprintf(debug_buff, "Attempting to join chat room %s.\n", name); + debug_print(debug_buff); + if ((cur = aim_getconn_type(g->oscar_sess, AIM_CONN_TYPE_CHATNAV))) { + debug_print("chatnav exists, creating room\n"); + aim_chatnav_createroom(g->oscar_sess, cur, name, exchange); + } else { + /* this gets tricky */ + debug_print("chatnav does not exist, opening chatnav\n"); + g->create_exchange = exchange; + g->create_name = g_strdup(name); + aim_bos_reqservice(g->oscar_sess, g->oscar_conn, AIM_CONN_TYPE_CHATNAV); } } -void update_keepalive(struct gaim_connection *gc, gboolean on) { - if (on && gc->keepalive < 0 && blist) { - debug_print("allowing NOP\n"); - gc->keepalive = gtk_timeout_add(60000, (GtkFunction)send_keepalive, gc); - } else if (!on && gc->keepalive > -1) { - debug_print("removing NOP\n"); - gtk_timeout_remove(gc->keepalive); - gc->keepalive = -1; +static void oscar_chat_invite(struct gaim_connection *g, int id, char *message, char *name) { + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + + while (bcs) { + b = (struct conversation *)bcs->data; + if (id == b->id) + break; + bcs = bcs->next; + b = NULL; + } + + if (!b) + return; + + aim_chat_invite(g->oscar_sess, g->oscar_conn, name, + message ? message : "", 0x4, b->name, 0x0); +} + +static void oscar_chat_leave(struct gaim_connection *g, int id) { + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + struct chat_connection *c = NULL; + int count = 0; + + while (bcs) { + count++; + b = (struct conversation *)bcs->data; + if (id == b->id) + break; + bcs = bcs->next; + b = NULL; + } + + if (!b) + return; + + sprintf(debug_buff, "Attempting to leave room %s (currently in %d rooms)\n", + b->name, count); + debug_print(debug_buff); + + c = find_oscar_chat(g, b->name); + if (c != NULL) { + g->oscar_chats = g_slist_remove(g->oscar_chats, c); + gdk_input_remove(c->inpa); + if (g && g->oscar_sess) + aim_conn_kill(g->oscar_sess, &c->conn); + g_free(c->name); + g_free(c); } + /* we do this because with Oscar it doesn't tell us we left */ + serv_got_chat_left(g, b->id); } + +static void oscar_chat_whisper(struct gaim_connection *g, int id, char *who, char *message) { + do_error_dialog("Sorry, Oscar doesn't whisper. Send an IM. (The last message was not received.)", + "Gaim - Chat"); +} + +static void oscar_chat_send(struct gaim_connection *g, int id, char *message) { + struct aim_conn_t *cn; + GSList *bcs = g->buddy_chats; + struct conversation *b = NULL; + + while (bcs) { + b = (struct conversation *)bcs->data; + if (id == b->id) + break; + bcs = bcs->next; + b = NULL; + } + if (!b) + return; + + cn = aim_chat_getconn(g->oscar_sess, b->name); + aim_chat_send_im(g->oscar_sess, cn, message); +} + +struct prpl *oscar_init() { + struct prpl *ret = g_new0(struct prpl, 1); + + ret->protocol = PROTO_OSCAR; + ret->name = oscar_name; + ret->login = oscar_login; + ret->close = oscar_close; + ret->send_im = oscar_send_im; + ret->set_info = oscar_set_info; + ret->get_info = oscar_get_info; + ret->set_away = oscar_set_away; + ret->get_away_msg = oscar_get_away_msg; + ret->set_dir = oscar_set_dir; + ret->get_dir = NULL; /* Oscar really doesn't have this */ + ret->dir_search = oscar_dir_search; + ret->set_idle = oscar_set_idle; + ret->change_passwd = NULL; /* Oscar doesn't have this either */ + ret->add_buddy = oscar_add_buddy; + ret->add_buddies = oscar_add_buddies; + ret->remove_buddy = oscar_remove_buddy; + ret->add_permit = NULL; /* Oscar's permit/deny stuff is messed up */ + ret->add_deny = NULL; /* at least, i can't figure it out :-P */ + ret->warn = oscar_warn; + ret->accept_chat = NULL; /* oscar doesn't have accept, it just joins */ + ret->join_chat = oscar_join_chat; + ret->chat_invite = oscar_chat_invite; + ret->chat_leave = oscar_chat_leave; + ret->chat_whisper = oscar_chat_whisper; + ret->chat_send = oscar_chat_send; + ret->keepalive = oscar_keepalive; + + return ret; +} + +#endif diff -r 82c5865f7cfe -r 7e231bc0018a src/plugins.c --- a/src/plugins.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/plugins.c Fri Oct 13 07:24:40 2000 +0000 @@ -408,12 +408,6 @@ gaim_plugin_unload(p->handle); } -static void remove_callback(struct gaim_plugin *p) { - gtk_timeout_remove(p->remove); - dlclose(p->handle); - g_free(p); -} - /* gaim_plugin_unload serves 2 purposes: 1. so plugins can unload themselves * 2. to make my life easier */ void gaim_plugin_unload(void *handle) { @@ -456,11 +450,11 @@ c = g_list_next(c); } } - /* remove callbacks later (this will g_free p) */ - p->remove = gtk_timeout_add(5000, (GtkFunction)remove_callback, p); plugins = g_list_remove(plugins, p); g_free(p->filename); + /* we don't dlclose(p->handle) in case if we still need code from the plugin later */ + g_free(p); if (config) gtk_widget_set_sensitive(config, 0); update_show_plugins(); save_prefs(); @@ -504,7 +498,7 @@ void gaim_signal_connect(void *handle, enum gaim_event which, void *func, void *data) { - struct gaim_callback *call = g_malloc(sizeof *call); + struct gaim_callback *call = g_new0(struct gaim_callback, 1); call->handle = handle; call->event = which; call->function = func; diff -r 82c5865f7cfe -r 7e231bc0018a src/prpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/prpl.c Fri Oct 13 07:24:40 2000 +0000 @@ -0,0 +1,49 @@ +/* + * gaim + * + * Copyright (C) 1998-1999, Mark Spencer + * + * 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 "prpl.h" +extern struct prpl *toc_init(); +extern struct prpl *oscar_init(); + +GSList *protocols = NULL; + +struct prpl *find_prpl(int prot) +{ + GSList *e = protocols; + struct prpl *r; + + while (e) { + r = (struct prpl *)e->data; + if (r->protocol == prot) + return r; + e = e->next; + } + + return NULL; +} + +void static_proto_init() +{ + protocols = g_slist_append(protocols, toc_init()); +#ifndef DYNAMIC_OSCAR + protocols = g_slist_append(protocols, oscar_init()); +#endif +} diff -r 82c5865f7cfe -r 7e231bc0018a src/prpl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/prpl.h Fri Oct 13 07:24:40 2000 +0000 @@ -0,0 +1,87 @@ +/* + * gaim + * + * Copyright (C) 1998-1999, Mark Spencer + * + * 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 + * + */ + +#ifndef _GAIMPRPL_H_ +#define _GAIMPRPL_H_ + +#include "multi.h" + +#define PROTO_TOC 0 +#define PROTO_OSCAR 1 +#define PROTO_YAHOO 2 +#define PROTO_ICQ 3 +#define PROTO_MSN 4 +#define PROTO_IRC 5 +#define PROTO_FTP 6 + +struct prpl { + int protocol; + char *(* name)(); + + void (* login) (struct aim_user *); + void (* close) (struct gaim_connection *); + void (* send_im) (struct gaim_connection *, char *who, char *message, int away); + void (* set_info) (struct gaim_connection *, char *info); + void (* get_info) (struct gaim_connection *, char *who); + void (* set_away) (struct gaim_connection *, char *message); + void (* get_away_msg) (struct gaim_connection *, char *who); + void (* set_dir) (struct gaim_connection *, char *first, + char *middle, + char *last, + char *maiden, + char *city, + char *state, + char *country, + int web); + void (* get_dir) (struct gaim_connection *, char *who); + void (* dir_search) (struct gaim_connection *, char *first, + char *middle, + char *last, + char *maiden, + char *city, + char *state, + char *country, + char *email); + void (* set_idle) (struct gaim_connection *, int idletime); + void (* change_passwd) (struct gaim_connection *, char *old, char *new); + void (* add_buddy) (struct gaim_connection *, char *name); + void (* add_buddies) (struct gaim_connection *, GList *buddies); + void (* remove_buddy) (struct gaim_connection *, char *name); + void (* add_permit) (struct gaim_connection *, char *name); + void (* add_deny) (struct gaim_connection *, char *name); + void (* warn) (struct gaim_connection *, char *who, int anonymous); + void (* accept_chat) (struct gaim_connection *, int id); + void (* join_chat) (struct gaim_connection *, int id, char *name); + void (* chat_invite) (struct gaim_connection *, int id, char *who, char *message); + void (* chat_leave) (struct gaim_connection *, int id); + void (* chat_whisper) (struct gaim_connection *, int id, char *who, char *message); + void (* chat_send) (struct gaim_connection *, int id, char *message); + + void (* keepalive) (struct gaim_connection *); +}; + +extern GSList *protocols; + +void static_proto_init(); + +struct prpl *find_prpl(int); + +#endif diff -r 82c5865f7cfe -r 7e231bc0018a src/server.c --- a/src/server.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/server.c Fri Oct 13 07:24:40 2000 +0000 @@ -32,6 +32,7 @@ #include #include extern int gaim_caps; +#include "prpl.h" #include "multi.h" #include "gaim.h" @@ -42,20 +43,17 @@ void serv_login(struct aim_user *user) { - if (user->protocol == PROTO_TOC) { - toc_login(user); - } else if (user->protocol == PROTO_OSCAR) { - debug_print("Logging in using Oscar. Expect problems.\n"); - oscar_login(user); + struct prpl *p = find_prpl(user->protocol); + if (p && p->login) { + debug_printf("Logging in using %s\n", (*p->name)()); + (*p->login)(user); } } void serv_close(struct gaim_connection *gc) { - if (gc->protocol == PROTO_TOC) - toc_close(gc); - else if (gc->protocol == PROTO_OSCAR) - oscar_close(gc); + if (gc->prpl && gc->prpl->close) + (*gc->prpl->close)(gc); account_offline(gc); destroy_gaim_conn(gc); @@ -133,27 +131,9 @@ void serv_send_im(struct gaim_connection *gc, char *name, char *message, int away) { - struct conversation *cnv = find_conversation(name); - if (cnv && cnv->is_direct && (gc->protocol == PROTO_OSCAR)) { - debug_printf("Sending DirectIM to %s\n", name); - aim_send_im_direct(gc->oscar_sess, cnv->conn, message); - } else { - if (gc->protocol == PROTO_TOC) { - char buf[MSG_LEN - 7]; + if (gc->prpl && gc->prpl->send_im) + (*gc->prpl->send_im)(gc, name, message, away); - escape_text(message); - g_snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name), - message, ((away) ? " auto" : "")); - sflap_send(gc, buf, -1, TYPE_DATA); - } else if (gc->protocol == PROTO_OSCAR) { - if (away) - aim_send_im(gc->oscar_sess, gc->oscar_conn, - name, AIM_IMFLAGS_AWAY, message); - else - aim_send_im(gc->oscar_sess, gc->oscar_conn, - name, AIM_IMFLAGS_ACK, message); - } - } if (!away) serv_touch_idle(gc); } @@ -163,35 +143,27 @@ /* FIXME: getting someone's info? how do you decide something like that? I think that * the buddy list/UI needs to be really changed before this gets fixed*/ struct gaim_connection *g = connections->data; - if (g->protocol == PROTO_TOC) { - char buf[MSG_LEN]; - g_snprintf(buf, MSG_LEN, "toc_get_info %s", normalize(name)); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_GENERALINFO); - } + + if (g->prpl && g->prpl->get_info) + (*g->prpl->get_info)(g, name); } void serv_get_away_msg(char *name) { /* FIXME: see the serv_get_info comment above :-P */ struct gaim_connection *g = connections->data; - if (g->protocol == PROTO_TOC) { - /* HAHA! TOC doesn't have this yet */ - } else if (g->protocol == PROTO_OSCAR) { - aim_getinfo(g->oscar_sess, g->oscar_conn, name, AIM_GETINFO_AWAYMESSAGE); - } + + if (g->prpl && g->prpl->get_info) + (*g->prpl->get_info)(g, name); } void serv_get_dir(char *name) { /* FIXME: see the serv_get_info comment above :-P */ struct gaim_connection *g = connections->data; - if (g->protocol == PROTO_TOC) { - char buf[MSG_LEN]; - g_snprintf(buf, MSG_LEN, "toc_get_dir %s", normalize(name)); - sflap_send(g, buf, -1, TYPE_DATA); - } + + if (g->prpl && g->prpl->get_dir) + (*g->prpl->get_dir)(g, name); } void serv_set_dir(char *first, char *middle, char *last, char *maiden, @@ -199,19 +171,9 @@ { /* FIXME */ struct gaim_connection *g = connections->data; - if (g->protocol == PROTO_TOC) { - char buf2[BUF_LEN*4], buf[BUF_LEN]; - g_snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first, - middle, last, maiden, city, state, country, - (web == 1) ? "Y" : ""); - escape_text(buf2); - g_snprintf(buf, sizeof(buf), "toc_set_dir %s", buf2); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - /* FIXME : some of these things are wrong, but i'm lazy */ - aim_setdirectoryinfo(g->oscar_sess, g->oscar_conn, first, middle, last, - maiden, NULL, NULL, city, state, NULL, 0, web); - } + + if (g->prpl && g->prpl->set_dir) + (*g->prpl->set_dir)(g, first, middle, last, maiden, city, state, country, web); } void serv_dir_search(char *first, char *middle, char *last, char *maiden, @@ -219,16 +181,9 @@ { /* FIXME */ struct gaim_connection *g = connections->data; - if (g->protocol == PROTO_TOC) { - char buf[BUF_LONG]; - g_snprintf(buf, sizeof(buf)/2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle, last, maiden, city, state, country, email); - sprintf(debug_buff,"Searching for: %s,%s,%s,%s,%s,%s,%s\n", first, middle, last, maiden, city, state, country); - debug_print(debug_buff); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - if (strlen(email)) - aim_usersearch_address(g->oscar_sess, g->oscar_conn, email); - } + + if (g->prpl && g->prpl->dir_search) + (*g->prpl->dir_search)(g, first, middle, last, maiden, city, state, country, email); } @@ -240,47 +195,21 @@ while (c) { g = (struct gaim_connection *)c->data; - if (g->protocol == PROTO_TOC) { - char buf[MSG_LEN]; - if (message) { - escape_text(message); - g_snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", message); - } else - g_snprintf(buf, MSG_LEN, "toc_set_away \"\""); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - aim_bos_setprofile(g->oscar_sess, g->oscar_conn, g->user_info, message, gaim_caps); - } + if (g->prpl && g->prpl->set_away) + (*g->prpl->set_away)(g, message); c = c->next; } } void serv_set_info(struct gaim_connection *g, char *info) { - if (g->protocol == PROTO_TOC) { - char buf[MSG_LEN]; - escape_text(info); - g_snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", info); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - if (awaymessage) - aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info, - awaymessage->message, gaim_caps); - else - aim_bos_setprofile(g->oscar_sess, g->oscar_conn, info, - NULL, gaim_caps); - } + if (g->prpl && g->prpl->set_info) + (*g->prpl->set_info)(g, info); } void serv_change_passwd(struct gaim_connection *g, char *orig, char *new) { - if (g->protocol == PROTO_TOC) { - char *buf = g_malloc(BUF_LONG); - g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new); - sflap_send(g, buf, strlen(buf), TYPE_DATA); - g_free(buf); - } else if (g->protocol == PROTO_OSCAR) { - /* Oscar change_passwd FIXME */ - } + if (g->prpl && g->prpl->change_passwd) + (*g->prpl->change_passwd)(g, orig, new); } void serv_add_buddy(char *name) @@ -292,13 +221,8 @@ while (c) { g = (struct gaim_connection *)c->data; - if (g->protocol == PROTO_TOC) { - char buf[1024]; - g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name)); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - aim_add_buddy(g->oscar_sess, g->oscar_conn, name); - } + if (g->prpl && g->prpl->add_buddy) + (*g->prpl->add_buddy)(g, name); c = c->next; } } @@ -311,37 +235,8 @@ while (c) { g = (struct gaim_connection *)c->data; - if (g->protocol == PROTO_TOC) { - char buf[MSG_LEN]; - int n, num = 0; - - n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); - while(buddies) { - /* i don't know why we choose 8, it just seems good */ - if (strlen(normalize(buddies->data)) > MSG_LEN - n - 8) { - sflap_send(g, buf, -1, TYPE_DATA); - n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); - num = 0; - } - ++num; - n += g_snprintf(buf + n, sizeof(buf)-n, " %s", normalize(buddies->data)); - buddies = buddies->next; - } - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - char buf[MSG_LEN]; - int n = 0; - while(buddies) { - if (n > MSG_LEN - 18) { - aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf); - n = 0; - } - n += g_snprintf(buf + n, sizeof(buf) - n, "%s&", - (char *)buddies->data); - buddies = buddies->next; - } - aim_bos_setbuddylist(g->oscar_sess, g->oscar_conn, buf); - } + if (g->prpl && g->prpl->add_buddies) + (*g->prpl->add_buddies)(g, buddies); c = c->next; } } @@ -355,13 +250,8 @@ while (c) { g = (struct gaim_connection *)c->data; - if (g->protocol == PROTO_TOC) { - char buf[1024]; - g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name)); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - aim_remove_buddy(g->oscar_sess, g->oscar_conn, name); - } + if (g->prpl && g->prpl->remove_buddy) + (*g->prpl->remove_buddy)(g, name); c = c->next; } } @@ -481,27 +371,15 @@ void serv_set_idle(struct gaim_connection *g, int time) { - if (g->protocol == PROTO_TOC) { - char buf[256]; - g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - aim_bos_setidle(g->oscar_sess, g->oscar_conn, time); - } + if (g->prpl && g->prpl->set_idle) + (*g->prpl->set_idle)(g, time); } void serv_warn(struct gaim_connection *g, char *name, int anon) { - if (g->protocol == PROTO_TOC) { - char *send = g_malloc(256); - g_snprintf(send, 255, "toc_evil %s %s", name, - ((anon) ? "anon" : "norm")); - sflap_send(g, send, -1, TYPE_DATA); - g_free(send); - } else if (g->protocol == PROTO_OSCAR) { - aim_send_warning(g->oscar_sess, g->oscar_conn, name, anon); - } + if (g->prpl && g->prpl->warn) + (*g->prpl->warn)(g, name, anon); } void serv_build_config(char *buf, int len, gboolean show) { @@ -527,146 +405,38 @@ void serv_accept_chat(struct gaim_connection *g, int i) { - if (g->protocol == PROTO_TOC) { - char *buf = g_malloc(256); - g_snprintf(buf, 255, "toc_chat_accept %d", i); - sflap_send(g, buf, -1, TYPE_DATA); - g_free(buf); - } else if (g->protocol == PROTO_OSCAR) { - /* this should never get called because libfaim doesn't use the id - * (i'm not even sure Oscar does). go through serv_join_chat instead */ - } + if (g->prpl && g->prpl->accept_chat) + (*g->prpl->accept_chat)(g, i); } void serv_join_chat(struct gaim_connection *g, int exchange, char *name) { - if (g->protocol == PROTO_TOC) { - char buf[BUF_LONG]; - g_snprintf(buf, sizeof(buf)/2, "toc_chat_join %d \"%s\"", exchange, name); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - struct aim_conn_t *cur = NULL; - sprintf(debug_buff, "Attempting to join chat room %s.\n", name); - debug_print(debug_buff); - if ((cur = aim_getconn_type(g->oscar_sess, AIM_CONN_TYPE_CHATNAV))) { - debug_print("chatnav exists, creating room\n"); - aim_chatnav_createroom(g->oscar_sess, cur, name, exchange); - } else { - /* this gets tricky */ - debug_print("chatnav does not exist, opening chatnav\n"); - g->create_exchange = exchange; - g->create_name = g_strdup(name); - aim_bos_reqservice(g->oscar_sess, g->oscar_conn, AIM_CONN_TYPE_CHATNAV); - } - } + if (g->prpl && g->prpl->join_chat) + (*g->prpl->join_chat)(g, exchange, name); } void serv_chat_invite(struct gaim_connection *g, int id, char *message, char *name) { - if (g->protocol == PROTO_TOC) { - char buf[BUF_LONG]; - g_snprintf(buf, sizeof(buf)/2, "toc_chat_invite %d \"%s\" %s", id, message, normalize(name)); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - GSList *bcs = g->buddy_chats; - struct conversation *b = NULL; - - while (bcs) { - b = (struct conversation *)bcs->data; - if (id == b->id) - break; - bcs = bcs->next; - b = NULL; - } - - if (!b) - return; - - aim_chat_invite(g->oscar_sess, g->oscar_conn, name, - message ? message : "", 0x4, b->name, 0x0); - } + if (g->prpl && g->prpl->chat_invite) + (*g->prpl->chat_invite)(g, id, message, name); } void serv_chat_leave(struct gaim_connection *g, int id) { - if (g->protocol == PROTO_TOC) { - char *buf = g_malloc(256); - g_snprintf(buf, 255, "toc_chat_leave %d", id); - sflap_send(g, buf, -1, TYPE_DATA); - g_free(buf); - } else if (g->protocol == PROTO_OSCAR) { - GSList *bcs = g->buddy_chats; - struct conversation *b = NULL; - struct chat_connection *c = NULL; - int count = 0; - - while (bcs) { - count++; - b = (struct conversation *)bcs->data; - if (id == b->id) - break; - bcs = bcs->next; - b = NULL; - } - - if (!b) - return; - - sprintf(debug_buff, "Attempting to leave room %s (currently in %d rooms)\n", - b->name, count); - debug_print(debug_buff); - - c = find_oscar_chat(g, b->name); - if (c != NULL) { - g->oscar_chats = g_slist_remove(g->oscar_chats, c); - gdk_input_remove(c->inpa); - if (g && g->oscar_sess) - aim_conn_kill(g->oscar_sess, &c->conn); - g_free(c->name); - g_free(c); - } - /* we do this because with Oscar it doesn't tell us we left */ - serv_got_chat_left(g, b->id); - } + if (g->prpl && g->prpl->chat_leave) + (*g->prpl->chat_leave)(g, id); } void serv_chat_whisper(struct gaim_connection *g, int id, char *who, char *message) { - if (g->protocol == PROTO_TOC) { - char buf2[MSG_LEN]; - g_snprintf(buf2, sizeof(buf2), "toc_chat_whisper %d %s \"%s\"", id, who, message); - sflap_send(g, buf2, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - do_error_dialog("Sorry, Oscar doesn't whisper. Send an IM. (The last message was not received.)", - "Gaim - Chat"); - } + if (g->prpl && g->prpl->chat_whisper) + (*g->prpl->chat_whisper)(g, id, who, message); } void serv_chat_send(struct gaim_connection *g, int id, char *message) { - if (g->protocol == PROTO_TOC) { - char buf[MSG_LEN]; - escape_text(message); - g_snprintf(buf, sizeof(buf), "toc_chat_send %d \"%s\"",id, message); - sflap_send(g, buf, -1, TYPE_DATA); - } else if (g->protocol == PROTO_OSCAR) { - struct aim_conn_t *cn; - GSList *bcs = g->buddy_chats; - struct conversation *b = NULL; - - while (bcs) { - b = (struct conversation *)bcs->data; - if (id == b->id) - break; - bcs = bcs->next; - b = NULL; - } - if (!b) - return; - - cn = aim_chat_getconn(g->oscar_sess, b->name); - aim_chat_send_im(g->oscar_sess, cn, message); - } + if (g->prpl && g->prpl->chat_send) + (*g->prpl->chat_send)(g, id, message); serv_touch_idle(g); } @@ -758,6 +528,7 @@ /* apply default fonts and colors */ tmpmsg = stylize(awaymessage->message, MSG_LEN); + /* PRPL */ if (gc->protocol == PROTO_TOC) { escape_text(tmpmsg); escape_message(tmpmsg); @@ -1088,7 +859,9 @@ if (cnv->gc->protocol == PROTO_TOC) { /* Direct IM TOC FIXME */ } else if (cnv->gc->protocol == PROTO_OSCAR) { + /* PRPL oscar_do_directim(cnv->gc, name); + */ } } @@ -1103,3 +876,21 @@ make_direct(cnv, TRUE, conn, watcher); } } + +void send_keepalive(gpointer d) { + struct gaim_connection *gc = (struct gaim_connection *)d; + debug_print("sending oscar NOP\n"); + if (gc->prpl && gc->prpl->keepalive) + (*gc->prpl->keepalive)(gc); +} + +void update_keepalive(struct gaim_connection *gc, gboolean on) { + if (on && gc->keepalive < 0 && blist) { + debug_print("allowing NOP\n"); + gc->keepalive = gtk_timeout_add(60000, (GtkFunction)send_keepalive, gc); + } else if (!on && gc->keepalive > -1) { + debug_print("removing NOP\n"); + gtk_timeout_remove(gc->keepalive); + gc->keepalive = -1; + } +} diff -r 82c5865f7cfe -r 7e231bc0018a src/toc.c --- a/src/toc.c Thu Oct 12 18:59:36 2000 +0000 +++ b/src/toc.c Fri Oct 13 07:24:40 2000 +0000 @@ -35,11 +35,12 @@ #include #include #include +#include "prpl.h" #include "multi.h" #include "gaim.h" #include "gnome_applet_mgr.h" -#define REVISION "gaim:$Revision: 990 $" +#define REVISION "gaim:$Revision: 991 $" static unsigned int peer_ver=0; @@ -932,3 +933,188 @@ do_export( (GtkWidget *) NULL, 0 ); } } + +static char *toc_name() { + return "TOC"; +} + +static void toc_send_im(struct gaim_connection *gc, char *name, char *message, int away) { + char buf[MSG_LEN - 7]; + + escape_text(message); + g_snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name), + message, ((away) ? " auto" : "")); + sflap_send(gc, buf, -1, TYPE_DATA); +} + +static void toc_get_info(struct gaim_connection *g, char *name) { + char buf[MSG_LEN]; + g_snprintf(buf, MSG_LEN, "toc_get_info %s", normalize(name)); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_get_dir(struct gaim_connection *g, char *name) { + char buf[MSG_LEN]; + g_snprintf(buf, MSG_LEN, "toc_get_dir %s", normalize(name)); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_set_dir(struct gaim_connection *g, char *first, char *middle, char *last, + char *maiden, char *city, char *state, char *country, int web) { + char buf2[BUF_LEN*4], buf[BUF_LEN]; + g_snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first, + middle, last, maiden, city, state, country, + (web == 1) ? "Y" : ""); + escape_text(buf2); + g_snprintf(buf, sizeof(buf), "toc_set_dir %s", buf2); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_dir_search(struct gaim_connection *g, char *first, char *middle, char *last, + char *maiden, char *city, char *state, char *country, char *email) { + char buf[BUF_LONG]; + g_snprintf(buf, sizeof(buf)/2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle, + last, maiden, city, state, country, email); + sprintf(debug_buff,"Searching for: %s,%s,%s,%s,%s,%s,%s\n", first, middle, last, maiden, + city, state, country); + debug_print(debug_buff); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_set_away(struct gaim_connection *g, char *message) { + char buf[MSG_LEN]; + if (message) { + escape_text(message); + g_snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", message); + } else + g_snprintf(buf, MSG_LEN, "toc_set_away \"\""); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_set_info(struct gaim_connection *g, char *info) { + char buf[MSG_LEN]; + escape_text(info); + g_snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", info); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_change_passwd(struct gaim_connection *g, char *orig, char *new) { + char buf[MSG_LEN]; + g_snprintf(buf, BUF_LONG, "toc_change_passwd %s %s", orig, new); + sflap_send(g, buf, strlen(buf), TYPE_DATA); +} + +static void toc_add_buddy(struct gaim_connection *g, char *name) { + char buf[1024]; + g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name)); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_add_buddies(struct gaim_connection *g, GList *buddies) { + char buf[MSG_LEN]; + int n; + + n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); + while (buddies) { + if (strlen(normalize(buddies->data)) > MSG_LEN - n - 16) { + sflap_send(g, buf, -1, TYPE_DATA); + n = g_snprintf(buf, sizeof(buf), "toc_add_buddy"); + } + n += g_snprintf(buf + n, sizeof(buf)-n, " %s", normalize(buddies->data)); + buddies = buddies->next; + } + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_remove_buddy(struct gaim_connection *g, char *name) { + char buf[1024]; + g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name)); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_set_idle(struct gaim_connection *g, int time) { + char buf[256]; + g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_warn(struct gaim_connection *g, char *name, int anon) { + char send[256]; + g_snprintf(send, 255, "toc_evil %s %s", name, ((anon) ? "anon" : "norm")); + sflap_send(g, send, -1, TYPE_DATA); +} + +static void toc_accept_chat(struct gaim_connection *g, int i) { + char buf[256]; + g_snprintf(buf, 255, "toc_chat_accept %d", i); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_join_chat(struct gaim_connection *g, int exchange, char *name) { + char buf[BUF_LONG]; + g_snprintf(buf, sizeof(buf)/2, "toc_chat_join %d \"%s\"", exchange, name); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_chat_invite(struct gaim_connection *g, int id, char *message, char *name) { + char buf[BUF_LONG]; + g_snprintf(buf, sizeof(buf)/2, "toc_chat_invite %d \"%s\" %s", id, message, normalize(name)); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_chat_leave(struct gaim_connection *g, int id) { + char buf[256]; + g_snprintf(buf, 255, "toc_chat_leave %d", id); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_chat_whisper(struct gaim_connection *g, int id, char *who, char *message) { + char buf2[MSG_LEN]; + g_snprintf(buf2, sizeof(buf2), "toc_chat_whisper %d %s \"%s\"", id, who, message); + sflap_send(g, buf2, -1, TYPE_DATA); +} + +static void toc_chat_send(struct gaim_connection *g, int id, char *message) { + char buf[MSG_LEN]; + escape_text(message); + g_snprintf(buf, sizeof(buf), "toc_chat_send %d \"%s\"",id, message); + sflap_send(g, buf, -1, TYPE_DATA); +} + +static void toc_keepalive(struct gaim_connection *gc) { + sflap_send(gc, "", 0, TYPE_KEEPALIVE); +} + +struct prpl *toc_init() { + struct prpl *ret = g_new0(struct prpl, 1); + + ret->protocol = PROTO_TOC; + ret->name = toc_name; + ret->login = toc_login; + ret->close = toc_close; + ret->send_im = toc_send_im; + ret->set_info = toc_set_info; + ret->get_info = toc_get_info; + ret->set_away = toc_set_away; + ret->get_away_msg = NULL; + ret->set_dir = toc_set_dir; + ret->get_dir = toc_get_dir; + ret->dir_search = toc_dir_search; + ret->set_idle = toc_set_idle; + ret->change_passwd = toc_change_passwd; + ret->add_buddy = toc_add_buddy; + ret->add_buddies = toc_add_buddies; + ret->remove_buddy = toc_remove_buddy; + ret->add_permit = NULL; /* FIXME */ + ret->add_deny = NULL; + ret->warn = toc_warn; + ret->accept_chat = toc_accept_chat; + ret->join_chat = toc_join_chat; + ret->chat_invite = toc_chat_invite; + ret->chat_leave = toc_chat_leave; + ret->chat_whisper = toc_chat_whisper; + ret->chat_send = toc_chat_send; + ret->keepalive = toc_keepalive; + + return ret; +}