From: Sean E. <sea...@us...> - 2002-08-30 16:09:25
|
Update of /cvsroot/gaim/gaim/src In directory usw-pr-cvs1:/tmp/cvs-serv26153/src Modified Files: Makefile.am aim.c core.c core.h gaim.h util.c Added Files: gaim-socket.h socket.c Log Message: This isn't complete--but it's cool. gaim-remote is now built and installed. Eventually it will do lots of cool stuff--right now it just handles aim:// URI's. Try it out... when connected to OSCAR run: gaim-remote uri "aim://goim?screenname=seanegn&message=Good+job+Sean" Also, I made it so that if you're already running a Gaim session, and start a new one, it won't auto-login and disconnect all your accounts from the first instance. Useful if you accidentally hit the wrong button or something. --- NEW FILE: gaim-socket.h --- /* * gaim-remote * * Copyright (C) 2002, Sean Egan <bj...@bi...> * * 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 _GAIM_SOCKET_H_ #define _GAIM_SOCKET_H_ struct gaim_cui_packet { guchar type; guchar subtype; guint32 length; char *data; }; void cui_send_packet (int fd, struct gaim_cui_packet *p); gint gaim_connect_to_session(gint session); gboolean gaim_session_exists(int sess); struct gaim_cui_packet *cui_packet_new(guchar type, guchar subtype); void cui_packet_free(struct gaim_cui_packet *p); void cui_packet_append_string(struct gaim_cui_packet *p, char *str); void cui_packet_append_char(struct gaim_cui_packet *p, char c); void cui_packet_append_raw(struct gaim_cui_packet *p, char *str, int len); #endif /* _GAIM_SOCKET_H_ */ --- NEW FILE: socket.c --- /* * gaim-remote * * Copyright (C) 2002, Sean Egan <bj...@bi...> * * 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 * */ /* Somewhat inspired by XMMS: * Copyright (C) 1998-2002 Peter Alm, Mikael Alm, Olle Hallnas, * Thomas Nilsson and 4Front Technologies * Copyright (C) 1999-2002 Haavard Kvaalen */ /* This provides code for connecting to a Gaim socket and communicating with * it. It will eventually be made a library once the core and ui are split. */ #include <sys/socket.h> #include <sys/un.h> #include "gaim.h" #include "gaim-socket.h" void cui_send_packet (int fd, struct gaim_cui_packet *p) { int len = sizeof(p->type) + sizeof(p->subtype) + sizeof(p->length) + p->length; char *pack = g_malloc(len); char *a = pack; memcpy (a, &(p->type), sizeof(p->type)); a = a + sizeof(p->type); memcpy (a, &(p->subtype), sizeof(p->subtype)); a = a + sizeof(p->subtype); memcpy (a, &(p->length), sizeof(p->length)); a = a + sizeof(p->length); memcpy (a, p->data, p->length); write(fd, pack, len); g_free(pack); } void cui_packet_append_string(struct gaim_cui_packet *p, char *str) { int len = p->length + strlen(str); char *k = g_malloc(len); memcpy(k, p->data, p->length); memcpy(k + p->length, str, strlen(str)); if (p->data) g_free(p->data); p->data = k; p->length = len; } void cui_packet_append_char(struct gaim_cui_packet *p, char c) { int len = p->length + sizeof(char); char *k = g_malloc(len); memcpy(k, p->data, p->length); k[p->length] = c; if (p->data) g_free(p->data); p->data = k; p->length = len; } void cui_packet_append_raw(struct gaim_cui_packet *p, char *str, int len) { int lent = p->length + len; char *k = g_malloc(lent); memcpy(k, p->data, p->length); memcpy(k + p->length, str, len); if (p->data) g_free(p->data); p->data = k; p->length = lent; } struct gaim_cui_packet *cui_packet_new(guchar type, guchar subtype) { struct gaim_cui_packet *p = g_new0(struct gaim_cui_packet, 1); p->type = type; p->subtype = subtype; p->length = 0; p->data = NULL; return p; } void cui_packet_free(struct gaim_cui_packet *p) { if (p->data) g_free(p->data); g_free(p); } struct gaim_cui_packet *cui_read_packet(int fd) { struct gaim_cui_packet *p = g_new0(struct gaim_cui_packet, 1); char *data = NULL; if (!(read(fd, p->type, sizeof(p->type)))) { g_free(p); return NULL; } if (!(read(fd, p->subtype, sizeof(p->subtype)))) { g_free(p); return NULL; } if (!(read(fd, p->length, sizeof(p->length)))) { g_free(p); return NULL; } if (p->length) { data = g_malloc(p->length); if (!(read(fd, data, p->length))) { g_free(p); return NULL; } } p->data = data; } /* copied directly from xmms_connect_to_session */ gint gaim_connect_to_session(gint session) { gint fd; uid_t stored_uid, euid; struct sockaddr_un saddr; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) { saddr.sun_family = AF_UNIX; stored_uid = getuid(); euid = geteuid(); setuid(euid); sprintf(saddr.sun_path, "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), session); setreuid(stored_uid, euid); if (connect(fd, (struct sockaddr *) &saddr, sizeof (saddr)) != -1) return fd; } close(fd); return -1; } gboolean gaim_session_exists(int sess) { struct gaim_cui_packet *pack = NULL; int fd = gaim_connect_to_session(sess); if (fd > 0) { pack = cui_packet_new(CUI_TYPE_META, CUI_META_PING); cui_send_packet(fd, pack); cui_packet_free(pack); close(fd); } else { return FALSE; } return TRUE; } Index: Makefile.am =================================================================== RCS file: /cvsroot/gaim/gaim/src/Makefile.am,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -r1.49 -r1.50 --- Makefile.am 26 Aug 2002 03:49:28 -0000 1.49 +++ Makefile.am 30 Aug 2002 16:09:21 -0000 1.50 @@ -1,6 +1,6 @@ SUBDIRS = protocols -bin_PROGRAMS = gaim +bin_PROGRAMS = gaim gaim-remote gaim_SOURCES = about.c \ aim.c \ away.c \ @@ -25,11 +25,14 @@ proxy.c \ prpl.c \ server.c \ + socket.c \ sound.c \ util.c gaim_DEPENDENCIES = @LIBOBJS@ $(STATIC_LINK_LIBS) gaim_LDFLAGS = -export-dynamic gaim_LDADD = @LDADD@ @LIBOBJS@ + +gaim_remote_SOURCES = gaim-remote.c socket.c CFLAGS += $(PERL_CFLAGS) CFLAGS += -DLOCALEDIR=\"$(datadir)/locale\" -DLIBDIR=\"$(libdir)/gaim/\" $(DEBUG_CFLAGS) -DDATADIR=\"$(datadir)\" Index: aim.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/aim.c,v retrieving revision 1.188 retrieving revision 1.189 diff -u -d -r1.188 -r1.189 --- aim.c 30 Aug 2002 03:39:00 -0000 1.188 +++ aim.c 30 Aug 2002 16:09:22 -0000 1.189 @@ -504,7 +504,7 @@ debug_printf("Failed to load icon from %s/pixmaps/gaim.png\n",DATADIR); } - g_snprintf(name, sizeof(name), "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), getpid()); + g_snprintf(name, sizeof(name), "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), gaim_session); UI_fd = open_socket(name); if (UI_fd < 0) @@ -770,7 +770,7 @@ } } - if (!opt_acct && !opt_nologin) + if (!opt_acct && !opt_nologin && gaim_session == 0) auto_login(); if (opt_acct) { Index: core.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/core.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- core.c 20 Mar 2002 17:21:29 -0000 1.20 +++ core.c 30 Aug 2002 16:09:22 -0000 1.21 @@ -38,8 +38,10 @@ #include <string.h> #include "gaim.h" +#include "gaim-socket.h" static gint UI_fd = -1; +int gaim_session = 0; GSList *uis = NULL; static guchar *UI_build(guint32 *len, guchar type, guchar subtype, va_list args) @@ -132,6 +134,7 @@ static void meta_handler(struct UI *ui, guchar subtype, guchar *data) { + struct gaim_cui_packet *p; switch (subtype) { case CUI_META_LIST: break; @@ -151,6 +154,11 @@ g_source_remove(ui->inpa); g_free(ui); break; + case CUI_META_PING: + p = cui_packet_new(CUI_TYPE_META, CUI_META_ACK); + cui_send_packet(g_io_channel_unix_get_fd(ui->channel), p); + cui_packet_free(p); + break; default: debug_printf("unhandled meta subtype %d\n", subtype); break; @@ -289,6 +297,27 @@ return total; } +static void remote_handler(struct UI *ui, guchar subtype, guchar *data, int len) +{ + const char *resp; + char *send; + switch (subtype) { + case CUI_REMOTE_CONNECTIONS: + break; + case CUI_REMOTE_URI: + send = g_malloc(len + 1); + memcpy(send, data, len); + send[len] = 0; + resp = handle_uri(send); + g_free(send); + /* report error */ + break; + default: + debug_printf("Unhandled remote subtype %d\n", subtype); + break; + } +} + static gboolean UI_readable(GIOChannel *source, GIOCondition cond, gpointer data) { struct UI *ui = data; @@ -365,8 +394,11 @@ case CUI_TYPE_CHAT: chat_handler(ui, subtype, in); break; - */ - default: + */ + case CUI_TYPE_REMOTE: + remote_handler(ui, subtype, in, len); + break; + default: debug_printf("unhandled type %d\n", type); break; } @@ -402,18 +434,23 @@ { struct sockaddr_un saddr; gint fd; - + + while (gaim_session_exists(gaim_session)) + gaim_session++; + + debug_printf("session: %d\n", gaim_session); + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) { mode_t m = umask(0177); saddr.sun_family = AF_UNIX; g_snprintf(saddr.sun_path, 108, "%s/gaim_%s.%d", - g_get_tmp_dir(), g_get_user_name(), getpid()); + g_get_tmp_dir(), g_get_user_name(), gaim_session); if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) != -1) listen(fd, 100); else { g_log(NULL, G_LOG_LEVEL_CRITICAL, - "Failed to assign %s to a socket (Error: %s)", - saddr.sun_path, strerror(errno)); + "Failed to assign %s to a socket (Error: %s)", + saddr.sun_path, strerror(errno)); return -1; } umask(m); @@ -450,7 +487,7 @@ { char buf[1024]; close(UI_fd); - sprintf(buf, "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), getpid()); + sprintf(buf, "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), gaim_session); unlink(buf); debug_printf("Removed core\n"); } Index: core.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/core.h,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- core.h 29 Aug 2002 01:47:13 -0000 1.22 +++ core.h 30 Aug 2002 16:09:22 -0000 1.23 @@ -148,6 +148,7 @@ /* Globals in core.c */ extern GSList *uis; +extern gaim_session; /* Globals in plugins.c */ extern GList *plugins; Index: gaim.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/gaim.h,v retrieving revision 1.334 retrieving revision 1.335 diff -u -d -r1.334 -r1.335 --- gaim.h 29 Aug 2002 21:40:07 -0000 1.334 +++ gaim.h 30 Aug 2002 16:09:22 -0000 1.335 @@ -43,12 +43,19 @@ #define CUI_TYPE_BUDDY 5 /* BUDDY_LIST, i.e., both groups and buddies */ #define CUI_TYPE_MESSAGE 6 #define CUI_TYPE_CHAT 7 +#define CUI_TYPE_REMOTE 8 /* This is used to send commands to other UI's, + * like "Open new conversation" or "send IM". + * Even though there's much redundancy with the + * other CUI_TYPES, we're better keeping this stuff + * seperate because it's intended use is so different */ #define CUI_META_LIST 1 /* 1 is always list; this is ignored by the core. If we move to TCP this can be a keepalive */ #define CUI_META_QUIT 2 #define CUI_META_DETACH 3 /* you don't need to send this, you can just close the socket. the core will understand. */ +#define CUI_META_PING 4 +#define CUI_META_ACK 5 #define CUI_PLUGIN_LIST 1 #define CUI_PLUGIN_LOAD 2 @@ -84,6 +91,19 @@ #define CUI_CHAT_SEND 5 #define CUI_CHAT_RECV 6 +#define CUI_REMOTE_CONNECTIONS 2 /* Get a list of gaim_connections */ +#define CUI_REMOTE_URI 3 /* Have the core handle aim:// URI's */ +#define CUI_REMOTE_BLIST 4 /* Return a copy of the buddy list */ +#define CUI_REMOTE_STATE 5 /* Given a buddy, return his presence. */ +#define CUI_REMOTE_NEW_CONVO 6 /* Must give a user, can give an optional message */ +#define CUI_REMOTE_SEND 7 /* Sends a message, a 'quiet' flag determines whether + * a convo window is displayed or not. */ +#define CUI_REMOTE_ADD_BUDDY 8 /* Adds buddy to list */ +#define CUI_REMOTE_REMOVE_BUDDY 9 /* Removes buddy from list */ +#define CUI_REMOTE_JOIN_CHAT 10 /* Joins a chat. */ + /* What else?? */ + + #define IM_FLAG_AWAY 0x01 #define IM_FLAG_CHECKBOX 0x02 #define IM_FLAG_GAIMUSER 0x04 @@ -432,6 +452,7 @@ extern time_t get_time(int, int, int, int, int, int); extern FILE *gaim_mkstemp(gchar **); extern char *convert_string(char *, const char *, const char *); +extern const char *handle_uri(char *); #ifdef HAVE_LANGINFO_CODESET #define utf8_to_str(in) convert_string(in, nl_langinfo(CODESET), "UTF-8"); Index: util.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/util.c,v retrieving revision 1.131 retrieving revision 1.132 diff -u -d -r1.131 -r1.132 --- util.c 30 Aug 2002 03:14:05 -0000 1.131 +++ util.c 30 Aug 2002 16:09:22 -0000 1.132 @@ -32,7 +32,9 @@ #include <string.h> #include <sys/wait.h> #include <ctype.h> +#ifdef HAVE_ICONV #include <iconv.h> +#endif #include <math.h> #include "gaim.h" #include "prpl.h" @@ -1263,4 +1265,128 @@ } return fp; +} + +/* AIM URI's ARE FUN :-D */ +const char *handle_uri(char *uri) { + GString *str; + GSList *conn = connections; + struct gaim_connection *gc; + + debug_printf("Handling URI: %s\n", uri); + + /* Well, we'd better check to make sure we have at least one + AIM account connected. */ + while (gc = conn->data) { + if (gc->protocol == PROTO_TOC) { + break; + } + conn = conn->next; + } + + if (gc == NULL) + return "Not connected to AIM"; + + /* aim://goim?screenname=screenname&message=message */ + if (!g_strncasecmp(uri, "aim://goim?", strlen("aim://goim?"))) { + char *who, *what; + struct conversation *c; + uri = uri + strlen("aim://goim?"); + + if (!(who = strstr(uri, "screenname="))) { + return "No screenname given."; + } + /* spaces are encoded as +'s */ + who = who + strlen("screenname="); + str = g_string_new(NULL); + while (*who && (*who != '&')) { + g_string_append_c(str, *who == '+' ? ' ' : *who); + who++; + } + who = g_strdup(str->str); + g_string_free(str, TRUE); + + what = strstr(uri, "message="); + if (what) { + what = what + strlen("message="); + str = g_string_new(NULL); + while (*what && (*what != '&' || !g_strncasecmp(what, "&", 5))) { + g_string_append_c(str, *what == '+' ? ' ' : *what); + what++; + } + what = g_strdup(str->str); + g_string_free(str, TRUE); + } + + c = new_conversation(who); + g_free(who); + if (what) { + int finish; + gtk_editable_insert_text(GTK_EDITABLE(c->entry), + what, strlen(what), &finish); + g_free(what); + } + } else if (!g_strncasecmp(uri, "aim://addbuddy?", strlen("aim://addbuddy?"))) { + char *who, *group; + uri = uri + strlen("aim://addbuddy?"); + /* spaces are encoded as +'s */ + + if (!(who = strstr(uri, "screenname="))) { + return "No screenname given."; + } + who = who + strlen("screenname="); + str = g_string_new(NULL); + while (*who && (*who != '&')) { + g_string_append_c(str, *who == '+' ? ' ' : *who); + who++; + } + who = g_strdup(str->str); + g_string_free(str, TRUE); + + group = strstr(uri, "group="); + if (group) { + group = group + strlen("group="); + str = g_string_new(NULL); + while (*group && (*group != '&' || !g_strncasecmp(group, "&", 5))) { + g_string_append_c(str, *group == '+' ? ' ' : *group); + group++; + } + group = g_strdup(str->str); + g_string_free(str, TRUE); + } + debug_printf("who: %s\n", who); + show_add_buddy(gc, who, group, NULL); + g_free(who); + if (group) + g_free(group); + } else if (!g_strncasecmp(uri, "aim://gochat?", strlen("aim://gochat?"))) { + char *room; + GList *chat=NULL; + int exch = 5; + + uri = uri + strlen("aim://gochat?"); + /* spaces are encoded as +'s */ + + if (!(room = strstr(uri, "roomname="))) { + return "No roomname given."; + } + room = room + strlen("roomname="); + str = g_string_new(NULL); + while (*room && (*room != '&')) { + g_string_append_c(str, *room == '+' ? ' ' : *room); + room++; + } + room = g_strdup(str->str); + g_string_free(str, TRUE); + chat = g_list_append(NULL, room); + chat = g_list_append(chat, &exch); + serv_join_chat(gc, chat); + g_free(room); + g_list_free(chat); + } else { + return "Invalid AIM URI"; + } + + + return NULL; } |