# HG changeset patch # User Sean Egan # Date 1030723762 0 # Node ID 3da42b64304e14ac92e605f1a8ca806d7fab78f9 # Parent db5dd21aa3458651ea5c99aaad5f019327439cbc [gaim-migrate @ 3532] 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. committer: Tailor Script diff -r db5dd21aa345 -r 3da42b64304e ChangeLog --- a/ChangeLog Fri Aug 30 03:39:00 2002 +0000 +++ b/ChangeLog Fri Aug 30 16:09:22 2002 +0000 @@ -58,6 +58,9 @@ * Nice Oscar changes--mostly internal (Thanks Mark Doliner) * event_del_conversation for plugins (Thanks Bill Tompkins) * Code cleanups and fixes (Thanks Federico Mena Quintero) + * aim:// URI's supported with gaim-remote command + * Don't auto-login if an existing Gaim session is already + running. version 0.59 (06/24/2002): * Hungarian translation added (Thanks, Sutto Zoltan) diff -r db5dd21aa345 -r 3da42b64304e src/Makefile.am --- a/src/Makefile.am Fri Aug 30 03:39:00 2002 +0000 +++ b/src/Makefile.am Fri Aug 30 16:09:22 2002 +0000 @@ -1,6 +1,6 @@ SUBDIRS = protocols -bin_PROGRAMS = gaim +bin_PROGRAMS = gaim gaim-remote gaim_SOURCES = about.c \ aim.c \ away.c \ @@ -25,12 +25,15 @@ 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)\" diff -r db5dd21aa345 -r 3da42b64304e src/aim.c --- a/src/aim.c Fri Aug 30 03:39:00 2002 +0000 +++ b/src/aim.c Fri Aug 30 16:09:22 2002 +0000 @@ -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) { diff -r db5dd21aa345 -r 3da42b64304e src/core.c --- a/src/core.c Fri Aug 30 03:39:00 2002 +0000 +++ b/src/core.c Fri Aug 30 16:09:22 2002 +0000 @@ -38,8 +38,10 @@ #include #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"); } diff -r db5dd21aa345 -r 3da42b64304e src/core.h --- a/src/core.h Fri Aug 30 03:39:00 2002 +0000 +++ b/src/core.h Fri Aug 30 16:09:22 2002 +0000 @@ -148,6 +148,7 @@ /* Globals in core.c */ extern GSList *uis; +extern gaim_session; /* Globals in plugins.c */ extern GList *plugins; diff -r db5dd21aa345 -r 3da42b64304e src/gaim-socket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gaim-socket.h Fri Aug 30 16:09:22 2002 +0000 @@ -0,0 +1,44 @@ +/* + * gaim-remote + * + * Copyright (C) 2002, Sean Egan + * + * 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_ */ diff -r db5dd21aa345 -r 3da42b64304e src/gaim.h --- a/src/gaim.h Fri Aug 30 03:39:00 2002 +0000 +++ b/src/gaim.h Fri Aug 30 16:09:22 2002 +0000 @@ -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"); diff -r db5dd21aa345 -r 3da42b64304e src/socket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/socket.c Fri Aug 30 16:09:22 2002 +0000 @@ -0,0 +1,168 @@ +/* + * gaim-remote + * + * Copyright (C) 2002, Sean Egan + * + * 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 +#include +#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; +} + diff -r db5dd21aa345 -r 3da42b64304e src/util.c --- a/src/util.c Fri Aug 30 03:39:00 2002 +0000 +++ b/src/util.c Fri Aug 30 16:09:22 2002 +0000 @@ -32,7 +32,9 @@ #include #include #include +#ifdef HAVE_ICONV #include +#endif #include #include "gaim.h" #include "prpl.h" @@ -1264,3 +1266,127 @@ 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; +}