diff -uNr -x .bzr -x debian devel/protocols/oscar/oscar.c branches/aim-icons/protocols/oscar/oscar.c
--- devel/protocols/oscar/oscar.c 2006-06-21 18:32:30.000000000 +0200
+++ branches/aim-icons/protocols/oscar/oscar.c 2006-06-24 21:43:47.000000000 +0200
@@ -1,6 +1,7 @@
/*
* gaim
*
+ * Buddy icon hooks Copyright (C) 2006, Kozoru
* Some code copyright (C) 2002-2006, Jelmer Vernooij
* and the BitlBee team.
* Some code copyright (C) 1998-1999, Mark Spencer
@@ -29,6 +30,7 @@
#include
#include
#include
+#include
#include
#include "nogaim.h"
#include "bitlbee.h"
@@ -45,9 +47,7 @@
#include "chat.h"
#include "chatnav.h"
-/* constants to identify proto_opts */
-#define USEROPT_AUTH 0
-#define USEROPT_AUTHPORT 1
+#include "http_client.h"
#define UC_AOL 0x02
#define UC_ADMIN 0x04
@@ -60,10 +60,13 @@
#define OSCAR_GROUP "Friends"
+#define OSCAR_MAX_ICON_SIZE 7168
+
/* Don't know if support for UTF8 is really working. For now it's UTF16 here.
static int gaim_caps = AIM_CAPS_UTF8; */
-static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY | AIM_CAPS_CHAT;
+static int gaim_caps = AIM_CAPS_INTEROP | AIM_CAPS_ICHAT | AIM_CAPS_ICQSERVERRELAY |
+ AIM_CAPS_CHAT | AIM_CAPS_BUDDYICON;
static guint8 gaim_features[] = {0x01, 0x01, 0x01, 0x02};
struct oscar_data {
@@ -90,6 +93,11 @@
gboolean killme;
gboolean icq;
GSList *evilhack;
+
+ char *icon;
+ guint icon_size;
+ time_t icon_time;
+ guint16 icon_sum;
struct {
guint maxbuddies; /* max users you can watch */
@@ -355,10 +363,12 @@
return FALSE;
}
+static void oscar_got_http_icon(struct http_request *req);
+
static void oscar_login(struct aim_user *user) {
aim_session_t *sess;
aim_conn_t *conn;
- char buf[256];
+ char buf[256], *server;
struct gaim_connection *gc = new_gaim_conn(user);
struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1);
@@ -389,9 +399,15 @@
return;
}
- if (g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.icq.com") != 0 &&
- g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.oscar.aol.com") != 0) {
- serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",user->proto_opt[USEROPT_AUTH]);
+ server = g_strdup(user->proto_opt[0]);
+ if ((odata->icon = strchr(server, ':'))) {
+ *odata->icon = 0;
+ odata->icon = g_strdup(odata->icon + 1);
+ }
+
+ if (g_strcasecmp(server, "login.icq.com") != 0 &&
+ g_strcasecmp(server, "login.oscar.aol.com") != 0) {
+ serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.", server);
}
g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username);
@@ -401,17 +417,100 @@
aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0);
conn->status |= AIM_CONN_STATUS_INPROGRESS;
- conn->fd = proxy_connect(user->proto_opt[USEROPT_AUTH][0] ?
- user->proto_opt[USEROPT_AUTH] : AIM_DEFAULT_LOGIN_SERVER,
- user->proto_opt[USEROPT_AUTHPORT][0] ?
- atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT,
- oscar_login_connect, gc);
+ conn->fd = proxy_connect(server, AIM_LOGIN_PORT, oscar_login_connect, gc);
+ g_free(server);
if (conn->fd < 0) {
hide_login_progress(gc, _("Couldn't connect to host"));
signoff(gc);
return;
}
aim_request_login(sess, conn, gc->username);
+
+ if (odata->icon) {
+ int fd = -1;
+
+ if (odata->icon[0] == '/') {
+ struct stat sb;
+
+ fd = open(odata->icon, O_RDONLY);
+ if (fd == -1)
+ goto icon_error;
+
+ if (fstat(fd, &sb) == -1)
+ goto icon_error;
+
+ if (sb.st_size > OSCAR_MAX_ICON_SIZE) {
+ serv_got_crap(gc, "Couldn't load usericon (%s)", "It's too big");
+ goto icon_error_silent;
+ }
+
+ g_free(odata->icon);
+ odata->icon_time = sb.st_mtime;
+ odata->icon_size = sb.st_size;
+ odata->icon = g_malloc(odata->icon_size);
+
+ if (read(fd, odata->icon, odata->icon_size) != odata->icon_size)
+ goto icon_error;
+
+ odata->icon_sum = aim_iconsum((guint8*)odata->icon, odata->icon_size);
+
+ serv_got_crap(gc, "Successfully loaded usericon (%d bytes)", odata->icon_size);
+
+ close(fd);
+ } else {
+ if (!http_dorequest_url(odata->icon, oscar_got_http_icon, odata))
+ goto icon_error;
+ }
+
+ return;
+
+icon_error:
+ serv_got_crap(gc, "Couldn't load usericon (%s)", strerror(errno));
+icon_error_silent:
+ g_free(odata->icon);
+ odata->icon = NULL;
+ odata->icon_size = 0;
+
+ if (fd != -1)
+ close(fd);
+ }
+
+ /* DON'T PUT ANY CODE HERE! EVIL CONSTRUCTION INSIDE [tm] ;-) */
+}
+
+static void oscar_got_http_icon(struct http_request *req) {
+ struct oscar_data *od = req->data;
+ struct gaim_connection *gc;
+ GSList *l;
+
+ for (l = get_connections(); l; l = l->next)
+ if (((struct gaim_connection*)l->data)->proto_data == od)
+ break;
+
+ if (!l)
+ return;
+
+ gc = l->data;
+
+ if (req->status_code != 200) {
+ serv_got_crap(gc, "Couldn't load usericon (HTTP error %d)", req->status_code);
+ return;
+ }
+
+ if (req->body_size > OSCAR_MAX_ICON_SIZE) {
+ serv_got_crap(gc, "Couldn't load usericon (%s)", "It's too big");
+ return;
+ }
+
+ g_free(od->icon);
+ od->icon_time = time(NULL);
+ od->icon_size = req->body_size;
+ od->icon = g_malloc(od->icon_size);
+ memcpy(od->icon, req->reply_body, od->icon_size);
+
+ od->icon_sum = aim_iconsum((guint8*)od->icon, od->icon_size);
+
+ serv_got_crap(gc, "Successfully loaded usericon (%d bytes)", od->icon_size);
}
static void oscar_close(struct gaim_connection *gc) {
@@ -444,6 +543,7 @@
b_event_remove(odata->cnpa);
if (odata->paspa > 0)
b_event_remove(odata->paspa);
+ g_free(odata->icon);
aim_session_kill(odata->sess);
g_free(odata->sess);
odata->sess = NULL;
@@ -490,8 +590,7 @@
struct gaim_connection *gc = sess->aux_data;
struct oscar_data *od = gc->proto_data;
user = gc->user;
- port = user->proto_opt[USEROPT_AUTHPORT][0] ?
- atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT,
+ port = AIM_LOGIN_PORT;
va_start(ap, fr);
info = va_arg(ap, struct aim_authresp_info *);
@@ -870,14 +969,12 @@
va_list ap;
struct aim_redirect_data *redir;
struct gaim_connection *gc = sess->aux_data;
- struct aim_user *user = gc->user;
aim_conn_t *tstconn;
int i;
char *host;
int port;
- port = user->proto_opt[USEROPT_AUTHPORT][0] ?
- atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT,
+ port = AIM_LOGIN_PORT;
va_start(ap, fr);
redir = va_arg(ap, struct aim_redirect_data *);
@@ -1051,8 +1148,14 @@
static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch1_args *args) {
char *tmp = g_malloc(BUF_LONG + 1);
struct gaim_connection *gc = sess->aux_data;
+ struct oscar_data *od = gc->proto_data;
int flags = 0;
+ /* W000t, they want to see our icon! \o/ */
+ if (args->icbmflags & AIM_IMFLAGS_BUDDYREQ && od->icon_size > 0)
+ aim_send_icon(sess, userinfo->sn, (guint8*) od->icon, od->icon_size,
+ od->icon_time, od->icon_sum);
+
if (args->icbmflags & AIM_IMFLAGS_AWAY)
flags |= IM_FLAG_AWAY;
@@ -1887,6 +1990,17 @@
args.msg = s;
args.msglen = len;
+ if (odata->icon_size > 0) {
+ /* Set this flag and give more information about the
+ icon, the client can decide if it wants to see
+ the icon or not. */
+ args.flags |= AIM_IMFLAGS_HASICON;
+
+ args.iconlen = odata->icon_size;
+ args.iconsum = odata->icon_sum;
+ args.iconstamp = odata->icon_time;
+ }
+
ret = aim_send_im_ext(odata->sess, &args);
if (s != message) {