The patch below is against version 2.3.2 of the transport. In order to use it, you first need to download and install the http_fetcher library at http://http-fetcher.sourceforge.net/. It should compile normally (albeit with some ignorable warnings).
To patch your Yahoo Transport, cd into it and run
patch -p1 < /path/to/the/patch/file
and then run 'make'.
When you run it and connect with a client that a) is registered with the Yahoo transport, b) has Yahoo buddies who have avatars, and c) supports jabber avatars via JEP-008, you should see Yahoo avatars in place of whatever generic placeholder normally appears.
I have only run this on linux, and cannot guarantee it will work, or that it won't hose up your server or something. Meaning: I wouldn't use this in production, just to fool around. Good luck, and may the Force be with you.
(I hereby release this hack into the public domain.)
<>diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/Makefile yahoo-transport/Makefile
--- yahoo-transport-orig/Makefile 2004-06-25 11:33:56.000000000 -0700
+++ yahoo-transport/Makefile 2004-08-16 11:05:43.048965928 -0700
@@ -4,11 +4,11 @@
include ../platform-settings
CFLAGS:=$(CFLAGS) -I../jabberd `glib-config --cflags` -LIBS:=$(LIBS) `glib-config --libs glib` +LIBS:=$(LIBS) `glib-config --libs glib` -lhttp_fetcher
YAHOO_OBJECTS=yahoo-transport.o yahoo-session.o yahoo-phandler.o yahoo.o \
crypt.o gaim-sha.o yahoo-presence.o yahoo-server.o md5.o yahoo-message.o \
- yahoo-stats.o yahoo-composing.o yahoo-mail.o yahoo-auth.o
+ yahoo-stats.o yahoo-composing.o yahoo-mail.o yahoo-auth.o sha.o yahoo-avatar.o
all: yahoo-transport
@@ -38,3 +38,4 @@
yahoo-stats.o: yahoo-stats.c yahoo-transport.h
yahoo.o: yahoo.c yahoo-transport.h
yahoo-auth.o: yahoo-auth.c yahoo-auth.h
+yahoo-avatar.o: yahoo-avatar.c
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/sha.c yahoo-transport/sha.c
--- yahoo-transport-orig/sha.c 1969-12-31 16:00:00.000000000 -0800
+++ yahoo-transport/sha.c 2004-08-04 18:14:45.000000000 -0700
@@ -0,0 +1,101 @@
+/*
+ Implements the Secure Hash Algorithm (1)
+
+ Copyright (C) 1999 Scott G. Miller
+
+ Released under the terms of the GNU General Public License v2
+ see file COPYING for details
+*/
+
+#define Ai 0x67452301
+#define Bi 0xefcdab89
+#define Ci 0x98badcfe
+#define Di 0x10325476
+#define Ei 0xc3d2e1f0
+
+#define A 0
+#define B 1
+#define C 2
+#define D 3
+#define E 4
+
+#define K1 0x5a827999
+#define K2 0x6ed9eba1
+#define K3 0x8f1bbcdc
+#define K4 0xca62c1d6
+
+#define f1(X,Y,Z) (X & Y) | ((!X) ^ Z)
+#define f2(X,Y,Z) (X ^ Y ^ Z)
+#define f3(X,Y,Z) (X & Y) | (X & Z) | (Y & Z)
+
+#define rol1(x) (x<<1) | ((x>>31) & 1)
+#define rol5(x) (x<<5) | ((x>>27) & 0x1f)
+#define rol30(x) (x<<30) | ((x>>2) & 0x3fffffff)
+
+int sha_hash(int *data, int *hash) {
+ int W[80];
+ int a=hash[A], b=hash[B], c=hash[C], d=hash[D], e=hash[E], t, x, TEMP;
+
+ /** Data expansion from 16 to 80 blocks **/
+ for (t=0; t<16; t++) {
+ W[t]=data[t];
+ }
+ for (t=16; t<80; t++) {
+ x=W[t-3] ^ W[t-8] ^ W[t-16];
+ W[t]=rol1(x);
+ }
+
+ /** Main loops **/
+ for (t=0; t<20; t++) {
+ TEMP=rol5(a) + f1(b,c,d) + e + W[t] + K1;
+ e=d;
+ d=c;
+ c=rol30(b);
+ b=a;
+ a=TEMP;
+ }
+ for (; t<40; t++) {
+ TEMP=rol5(a) + f2(b,c,d) + e + W[t] + K2;
+ e=d;
+ d=c;
+ c=rol30(b);
+ b=a;
+ a=TEMP;
+ }
+ for (; t<60; t++) {
+ TEMP=rol5(a) + f3(b,c,d) + e + W[t] + K3;
+ e=d;
+ d=c;
+ c=rol30(b);
+ b=a;
+ a=TEMP;
+ }
+ for (; t<80; t++) {
+ TEMP=rol5(a) + f2(b,c,d) + e + W[t] + K4;
+ e=d;
+ d=c;
+ c=rol30(b);
+ b=a;
+ a=TEMP;
+ }
+ hash[A]+=a;
+ hash[B]+=b;
+ hash[C]+=c;
+ hash[D]+=d;
+ hash[E]+=e;
+}
+
+int sha_init(int *hash) {
+ hash[A]=Ai;
+ hash[B]=Bi;
+ hash[C]=Ci;
+ hash[D]=Di;
+ hash[E]=Ei;
+}
+
+
+
+
+
+
+
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/sha.h yahoo-transport/sha.h
--- yahoo-transport-orig/sha.h 1969-12-31 16:00:00.000000000 -0800
+++ yahoo-transport/sha.h 2004-08-04 18:14:47.000000000 -0700
@@ -0,0 +1,2 @@
+int sha_hash(int *data, int *hash);
+int sha_init(int *hash);
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/yahoo-avatar.c yahoo-transport/yahoo-avatar.c
--- yahoo-transport-orig/yahoo-avatar.c 1969-12-31 16:00:00.000000000 -0800
+++ yahoo-transport/yahoo-avatar.c 2004-08-16 10:22:34.635706632 -0700
@@ -0,0 +1,206 @@
+#include "yahoo-transport.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* This is taken from Sylpheed by Hiroyuki Yamamoto. We have our own tobase64 function
+ * in util.c, but it has a bug I don't feel like finding right now ;) */
+
+/* Note: had to put this here and modify it because it didn't seem to output base64
+ * that is standard. The code had the final 2 chars in base64digits as ._ instead of
+ * the apparent standard of +/ */
+
+void get_avatar64(unsigned char *out, const unsigned char *in, int inlen) {
+ char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */
+
+ for (; inlen >= 3; inlen -= 3) {
+ *out++ = base64digits[in[0] >> 2];
+ *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+ *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+ *out++ = base64digits[in[2] & 0x3f];
+ in += 3;
+ }
+ if (inlen > 0) {
+ unsigned char fragment;
+
+ *out++ = base64digits[in[0] >> 2];
+ fragment = (in[0] << 4) & 0x30;
+ if (inlen > 1)
+ fragment |= in[1] >> 4;
+ *out++ = base64digits[fragment];
+ *out++ = (inlen < 2) ? '-' : base64digits[(in[1] << 2) & 0x3c];
+ *out++ = '-';
+ }
+ *out = '\0';
+}
+
+void hex_sha_hash(int *hashval, char *buffer) {
+ int x;
+ char tmp[9];
+
+ // I presume that buffer is already memsetted to 0s
+
+ for (x=0; x<5; x++) {
+ sprintf(tmp, "%08x", hashval[x]);
+ strcat(buffer, tmp);
+ }
+
+ return;
+}
+
+void av_sha_hash(char *filebuf, int length, char *av_hex_hash) {
+ int c=0;
+ int i;
+ int hashlength=0;
+ char buffer[64];
+ int av_bin_hash[Y_AVATAR_HASH_SIZE];
+
+ sha_init(av_bin_hash);
+
+ do {
+
+ if (c+64>length) {
+ memcpy(buffer, filebuf+c, length-c);
+// printf("memcpying the last %i bytes of filebuf into buffer\n", length-c);
+ hashlength+=(length-c);
+// printf("length is %i\n", hashlength);
+ for (i=length-c; i<61; i++) {
+ if (i==length-c)
+ buffer[i]=0x10;
+ else if (i==60)
+ ((int*)buffer)[15]=hashlength*8;
+ else
+ buffer[i]=0;
+ }
+ c+=i;
+ } else {
+// printf("doing byte %i to %i -- length is %i\n", c, c+64, length);
+ memcpy(buffer, filebuf+c, 64);
+ c+=64;
+ hashlength+=64;
+ }
+
+// for(q=0; q<64; q++) { printf("%i ", buffer[q]); }; printf("\n\n");
+ sha_hash((int*)buffer, av_bin_hash);
+ } while (c <= length);
+
+ memset(av_hex_hash, 0, 42);
+ hex_sha_hash(av_bin_hash, av_hex_hash);
+}
+
+int get_avatar_img(char *hash_string, char* filebuf) {
+ int pngsize;
+ char url[ sizeof(YAHOO_URL_PRE) + 65 + sizeof(YAHOO_URL_POST) ];
+
+ strcpy(url, YAHOO_URL_PRE);
+ strcat(url, hash_string);
+ strcat(url, YAHOO_URL_POST);
+
+ pngsize = http_fetch(url, (char **)filebuf);
+log_debug(ZONE, "[YAHOO]: addr of filebuf is %x", filebuf);
+
+ return(pngsize);
+}
+
+void get_avatar_sha_hash(char* filebuf, int pngsize, char* avatar_sha_string) {
+ /* ok, we have a string and we want to store it.
+
+ Do a web hit to yahoo and get the png img.
+
+ Get the SHA-1 hex hash of the img.
+
+ Base64-encode the img.
+
+ Send it to the jabber server's public storage.
+
+ Inject the SHA-1 hex hash of the img into the
+ current presence packet so the client knows
+ that there's an avatar available.
+
+ */
+
+ memset(avatar_sha_string, 0, 42);
+ av_sha_hash(filebuf, pngsize, avatar_sha_string);
+}
+
+void set_avatar_tag_info(xmlnode x, char* sha_hash) {
+ xmlnode query = xmlnode_insert_tag(x, "x");
+ xmlnode hashtag = xmlnode_insert_tag(query, "hash");
+
+ xmlnode_put_attrib(query, "xmlns", "jabber:x:avatar");
+ xmlnode_insert_cdata(hashtag, sha_hash, strlen(sha_hash));
+ // log_debug(ZONE, "[YAHOO]: inserted sha-1 avatar hash into presence packet at host %s, me = %s, server = %s", yd->yi->i->id, jid_full(yd->me), yd->me->server);
+ log_debug(ZONE, "[YAHOO]: j avatar hash is %s", sha_hash);
+}
+
+void store_avatar(struct yahoo_data *yd, char *contact_name, char* base64, char* sha_hash, char* y_hash) {
+
+ log_debug(ZONE, "[YAHOO]: store_avatar received y_hash of %s", y_hash);
+
+ xmlnode avatag_b64 = xmlnode_new_tag("yahoo_avatar");
+ xmlnode avatag_sha_hash = xmlnode_new_tag("yahoo_avatar_sha_hash");
+ xmlnode avatag_y_hash = xmlnode_new_tag("yahoo_avatar_y_hash");
+ pool p = pool_new();
+
+ jid j = jid_new(p, spools(p, contact_name, "@", "yahoo.com", p));
+
+ xmlnode_put_attrib(avatag_b64, "xmlns", "yahootrans:base64");
+ xmlnode_put_attrib(avatag_sha_hash, "xmlns", "yahootrans:sha_hash");
+ xmlnode_put_attrib(avatag_y_hash, "xmlns", "yahootrans:y_hash");
+
+ xmlnode_insert_cdata(avatag_b64, base64, strlen(base64));
+ xmlnode_insert_cdata(avatag_sha_hash, sha_hash, strlen(sha_hash));
+ xmlnode_insert_cdata(avatag_y_hash, y_hash, strlen(y_hash));
+
+ log_debug(ZONE, "[YAHOO]: doing an xdb set with owner %s", jid_full(j));
+
+ xdb_set(yd->yi->xc, j, "yahootrans:base64", avatag_b64);
+ xdb_set(yd->yi->xc, j, "yahootrans:sha_hash", avatag_sha_hash);
+ xdb_set(yd->yi->xc, j, "yahootrans:y_hash", avatag_y_hash);
+
+ xmlnode_free(avatag_b64);
+ xmlnode_free(avatag_sha_hash);
+ xmlnode_free(avatag_y_hash);
+}
+
+void retrieve_avatar_sha_hash(char* sha_hash, xdbcache xc, char* jid_str) {
+ pool p = pool_new();
+ jid j = jid_new(p, jid_str);
+
+ log_notice(ZONE, "[YAHOO]: trying to get db entry for %s", jid_full(j));
+
+ xmlnode sha_hash_xml = xdb_get(xc, j, "yahootrans:sha_hash");
+
+ if (sha_hash_xml != NULL)
+ strcpy(sha_hash, xmlnode_get_data(sha_hash_xml));
+ else
+ log_notice(ZONE, "[YAHOO]: no avatar retrieved!!");
+
+ xmlnode_free(sha_hash_xml);
+ pool_free(p);
+}
+
+int have_avatar_img_already(char* name, char* y_hash, xdbcache xc) {
+ int ret = 0;
+ pool p = pool_new();
+ jid j = jid_new(p, spools(p, name, "@", "yahoo.com", p));
+
+ log_notice(ZONE, "[YAHOO]: have_avatar_img_already is trying to get db entry for %s", jid_full(j));
+
+ xmlnode y_hash_xml = xdb_get(xc, j, "yahootrans:y_hash");
+ if (y_hash_xml != NULL)
+ if (strcmp(xmlnode_get_data(y_hash_xml), y_hash) == 0)
+ ret = 1;
+
+ log_notice(ZONE, "[YAHOO]: do we already have avatar for '%s' ? = * %i *", jid_full(j), ret);
+log_notice(ZONE, "[YAHOO]: y_hash received from yahoo is %s", y_hash);
+log_notice(ZONE, "[YAHOO]: y_hash stored is %s", xmlnode2str(y_hash_xml));
+
+ xmlnode_free(y_hash_xml);
+ pool_free(p);
+
+ return(ret);
+}
+
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/yahoo.c yahoo-transport/yahoo.c
--- yahoo-transport-orig/yahoo.c 2004-07-01 12:13:29.000000000 -0700
+++ yahoo-transport/yahoo.c 2004-08-16 10:51:21.132747351 -0700
@@ -480,6 +489,41 @@
case 16: /* Custom error message */
log_debug(ZONE, "[YAHOO]: Error Message: %s\n", pair->value);
break;
+ case 197: /* avatar hash */
+
+ log_debug(ZONE, "[YAHOO]: received y_avatar hash of %s\n", pair->value);
+ char avatar_y_hash[Y_AVATAR_HASH_SIZE];
+ strncpy(avatar_y_hash, pair->value, Y_AVATAR_HASH_SIZE);
+
+ log_debug(ZONE, "[YAHOO]: buddy name is %s", name);
+
+ if (!have_avatar_img_already(name, avatar_y_hash, yd->yi->xc)) {
+
+ log_debug(ZONE, "[YAHOO]: the 'already' routine sez we don't have it for %s (hash %s), loading", name, avatar_y_hash);
+
+ char avatar_sha_hash[Y_AVATAR_HASH_SIZE];
+ char hash64[Y_AVATAR_B64_SIZE]; // 16k is probably overkill but just in case ...
+ char *filebuf;
+ int pngsize;
+
+ pngsize = get_avatar_img(avatar_y_hash, &filebuf);
+
+ get_avatar_sha_hash(filebuf, pngsize, avatar_sha_hash);
+ log_debug(ZONE, "[YAHOO]: got sha-1 avatar hash %s\n", avatar_sha_hash);
+
+ get_avatar64(hash64, filebuf, pngsize);
+ store_avatar(yd, name, hash64, avatar_sha_hash, avatar_y_hash);
+ }
+
+ /*
+ set the presence for the sole purpose of announcing we have an avatar
+ for this user. That means there's no message (e.g. <show>away</show>)
+ so the 'state' variable can be 0 (normally meaning Available) because
+ it has no effect with a NULL message.
+ */
+ yahoo_set_jabber_presence(yd, name, 0, NULL);
+
+ break;
default:
log_debug(ZONE, "[YAHOO]: unknown status key %d\n", pair->key);
break;
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/yahoo-presence.c yahoo-transport/yahoo-presence.c
--- yahoo-transport-orig/yahoo-presence.c 2004-01-16 16:07:12.000000000 -0800
+++ yahoo-transport/yahoo-presence.c 2004-08-16 10:29:53.517937073 -0700
@@ -27,6 +27,7 @@
void yahoo_set_jabber_presence(struct yahoo_data *yd, char *contact_name, int state, char *msg) {
xmlnode x = NULL;
+ char avatar_hash[Y_AVATAR_HASH_SIZE] = "";
pool p;
p = pool_new();
@@ -36,14 +37,23 @@
case 0: // Available
x = jutil_presnew(JPACKET__AVAILABLE, jid_full(yd->me), msg);
xmlnode_put_attrib(x, "from", spools(p, contact_name, "@", yd->yi->i->id, p));
+
+ retrieve_avatar_sha_hash(avatar_hash, yd->yi->xc, spools(p, contact_name, "@", YAHOO_AVATAR_DOMAIN, p));
+ if (*avatar_hash != 0)
+ set_avatar_tag_info(x, avatar_hash);
+
log_debug(ZONE, "[YAHOO]: Presence for '%s' = available", xmlnode2str(x));
break;
-
case 1: // Away
x = jutil_presnew(JPACKET__AVAILABLE, jid_full(yd->me), msg);
xmlnode_put_attrib(x, "from", spools(p, contact_name, "@", yd->yi->i->id, p));
xmlnode_insert_cdata(xmlnode_insert_tag(x,"show"), "away", -1);
+
+ retrieve_avatar_sha_hash(avatar_hash, yd->yi->xc, spools(p, contact_name, "@", YAHOO_AVATAR_DOMAIN, p));
+ if (*avatar_hash != 0)
+ set_avatar_tag_info(x, avatar_hash);
+
log_debug(ZONE, "[YAHOO]: Presence for '%s' = away", xmlnode2str(x));
break;
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/yahoo-server.c yahoo-transport/yahoo-server.c
--- yahoo-transport-orig/yahoo-server.c 2004-07-01 12:13:29.000000000 -0700
+++ yahoo-transport/yahoo-server.c 2004-08-16 10:50:49.185937205 -0700
@@ -238,6 +239,47 @@
version, time, etc.
*/
+ if (NSCHECK(jp->iq, NS_IQ_AVATAR)) {
+
+ /*
+ If we get a jabber:iq:avatar packet, it means someone in jabber-land
+ is asking if the jabber public storage has a particular avatar img
+ stored as base64. I have not bothered to put in a check to see if
+ the result is an empty packet, but I think that's ok. It would be
+ like answering: "yes, I have no avatar."
+ */
+
+ log_notice(ZONE, "[YAHOO]: I just saw a jabber:iq:avatar packet");
+ log_notice(ZONE, "[YAHOO]: to user = %s, from server = %s, to server = %s", jp->to->user, jp->from->server, jp->to->server);
+
+ // grab the base64-encoded image from the public storage
+ pool p = pool_new();
+ jid j = jid_new(p, spools(p, jp->to->user, "@", YAHOO_AVATAR_DOMAIN, p));
+
+ log_notice(ZONE, "[YAHOO]: trying to get db entry for %s", jid_full(j));
+
+ xmlnode avatar64 = xdb_get(yi->xc, j, "yahootrans:base64");
+
+ log_notice(ZONE, "[YAHOO]: picked up this xdb name: %s", xmlnode_get_name(avatar64));
+
+log_notice(ZONE, "[YAHOO]: picked up this avatar:\n%s\n", xmlnode_get_data(avatar64));
+
+ jutil_iqresult(jp->x);
+ jpacket_reset(jp);
+ query = xmlnode_insert_tag(jp->x, "query");
+ xmlnode_put_attrib(query, "xmlns", NS_IQ_AVATAR);
+ xmlnode adata = xmlnode_insert_tag(query, "data");
+ xmlnode_put_attrib(adata, "mimetype", "image/png"); // yahoo avatar imgs are PNGs
+ xmlnode_insert_cdata(adata, xmlnode_get_data(avatar64), -1);
+
+ yahoo_deliver(NULL,jp->x);
+
+ xmlnode_free(avatar64);
+ pool_free(p);
+
+ return;
+ }
+
if (NSCHECK(jp->iq, NS_STATS)) {
yahoo_stats(jp);
return;
diff -burN --exclude=CVS --exclude='*.o' --exclude='*.so' --exclude='*.gz' --exclude='*.xml' yahoo-transport-orig/yahoo-transport.h yahoo-transport/yahoo-transport.h
--- yahoo-transport-orig/yahoo-transport.h 2004-07-01 09:06:34.000000000 -0700
+++ yahoo-transport/yahoo-transport.h 2004-08-16 10:31:24.796937932 -0700
@@ -37,6 +37,28 @@
#include <glib.h>
#include "md5.h"
+ +// Avatar stuff + +// this is the domain used for the jabber server public storage +#define YAHOO_AVATAR_DOMAIN "yahoo.com" + +#define Y_AVATAR_HASH_SIZE 64 +#define Y_AVATAR_B64_SIZE 16*1024 +#define NS_IQ_AVATAR "jabber:iq:avatar" +#define NS_X_AVATAR "jabber:x:avatar" +#define YAHOO_URL_PRE "img1.avatar.vip.dcn.yahoo.com/users/" +#define YAHOO_URL_POST ".medium.png" + +// hex sha library +#include "sha.h" + +// http library to fetch avatars from yahoo +#include <http_fetcher.h> + +// + + #ifdef _JCOMP #define YAHOO_VERSION "2.3.2-JCR"
#else
_______________________________________________ jdev mailing list [EMAIL PROTECTED] https://jabberstudio.org/mailman/listinfo/jdev
