From: Eric W. <war...@us...> - 2001-11-10 08:02:42
|
Update of /cvsroot/gaim/gaim/src/protocols/oscar In directory usw-pr-cvs1:/tmp/cvs-serv20536/src/protocols/oscar Modified Files: aim.h aim_cbtypes.h aim_internal.h icq.c oscar.c rxqueue.c Log Message: oh Index: aim.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/aim.h,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- aim.h 2001/11/10 02:07:37 1.17 +++ aim.h 2001/11/10 08:02:39 1.18 @@ -966,6 +966,17 @@ faim_export int aim_ssi_modbegin(aim_session_t *sess, aim_conn_t *conn); faim_export int aim_ssi_modend(aim_session_t *sess, aim_conn_t *conn); +struct aim_icq_offlinemsg { + fu32_t sender; + fu16_t year; + fu8_t month, day, hour, minute; + fu16_t type; + char *msg; +}; + +faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess); +faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess); + /* aim_util.c */ /* * These are really ugly. You'd think this was LISP. I wish it was. @@ -991,6 +1002,34 @@ (((*((buf)+1))<<16)&0x00ff0000) + \ (((*((buf)+2))<< 8)&0x0000ff00) + \ (((*((buf)+3) )&0x000000ff))) + +/* Little-endian versions (damn ICQ) */ +#define aimutil_putle8(buf, data) ( \ + (*(buf) = (unsigned char)(data) & 0xff), \ + 1) +#define aimutil_getle8(buf) ( \ + (*(buf)) & 0xff \ + ) +#define aimutil_putle16(buf, data) ( \ + (*((buf)+0) = (unsigned char)((data) >> 0) & 0xff), \ + (*((buf)+1) = (unsigned char)((data) >> 8) & 0xff), \ + 2) +#define aimutil_getle16(buf) ( \ + (((*((buf)+0)) << 0) & 0x00ff) + \ + (((*((buf)+1)) << 8) & 0xff00) \ + ) +#define aimutil_putle32(buf, data) ( \ + (*((buf)+0) = (unsigned char)((data) >> 0) & 0xff), \ + (*((buf)+1) = (unsigned char)((data) >> 8) & 0xff), \ + (*((buf)+2) = (unsigned char)((data) >> 16) & 0xff), \ + (*((buf)+3) = (unsigned char)((data) >> 24) & 0xff), \ + 4) +#define aimutil_getle32(buf) ( \ + (((*((buf)+0)) << 0) & 0x000000ff) + \ + (((*((buf)+1)) << 8) & 0x0000ff00) + \ + (((*((buf)+2)) << 16) & 0x00ff0000) + \ + (((*((buf)+3)) << 24) & 0xff000000)) + faim_export int aimutil_putstr(u_char *, const char *, int); faim_export int aimutil_tokslen(char *toSearch, int index, char dl); Index: aim_cbtypes.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/aim_cbtypes.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- aim_cbtypes.h 2001/11/05 12:25:22 1.2 +++ aim_cbtypes.h 2001/11/10 08:02:39 1.3 @@ -23,6 +23,7 @@ #define AIM_CB_FAM_TRN 0x000c #define AIM_CB_FAM_CTN 0x000d /* ChatNav */ #define AIM_CB_FAM_CHT 0x000e /* Chat */ +#define AIM_CB_FAM_ICQ 0x0015 #define AIM_CB_FAM_ATH 0x0017 #define AIM_CB_FAM_OFT 0xfffe /* OFT/Rvous */ #define AIM_CB_FAM_SPECIAL 0xffff /* Internal libfaim use */ @@ -170,6 +171,16 @@ #define AIM_CB_CHT_OUTGOINGMSG 0x0005 #define AIM_CB_CHT_INCOMINGMSG 0x0006 #define AIM_CB_CHT_DEFAULT 0xffff + +/* + * SNAC Family: ICQ + * + * Most of these are actually special. + */ +#define AIM_CB_ICQ_ERROR 0x0001 +#define AIM_CB_ICQ_OFFLINEMSG 0x00f0 +#define AIM_CB_ICQ_OFFLINEMSGCOMPLETE 0x00f1 +#define AIM_CB_ICQ_DEFAULT 0xffff /* * SNAC Family: Authorizer Index: aim_internal.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/aim_internal.h,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- aim_internal.h 2001/11/10 01:48:17 1.7 +++ aim_internal.h 2001/11/10 08:02:39 1.8 @@ -72,9 +72,15 @@ faim_internal fu8_t aimbs_get8(aim_bstream_t *bs); faim_internal fu16_t aimbs_get16(aim_bstream_t *bs); faim_internal fu32_t aimbs_get32(aim_bstream_t *bs); +faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs); +faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs); +faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs); faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v); faim_internal int aimbs_put16(aim_bstream_t *bs, fu16_t v); faim_internal int aimbs_put32(aim_bstream_t *bs, fu32_t v); +faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v); +faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v); +faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v); faim_internal int aimbs_getrawbuf(aim_bstream_t *bs, fu8_t *buf, int len); faim_internal fu8_t *aimbs_getraw(aim_bstream_t *bs, int len); faim_internal char *aimbs_getstr(aim_bstream_t *bs, int len); Index: icq.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/icq.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- icq.c 2001/11/10 01:48:17 1.1 +++ icq.c 2001/11/10 08:02:39 1.2 @@ -6,16 +6,162 @@ #define FAIM_INTERNAL #include <aim.h> +faim_export int aim_icq_reqofflinemsgs(aim_session_t *sess) +{ + aim_conn_t *conn; + aim_frame_t *fr; + aim_snacid_t snacid; + int bslen; + + if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) + return -EINVAL; + + bslen = 2 + 4 + 2 + 2; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); + + /* For simplicity, don't bother using a tlvlist */ + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, bslen); + + aimbs_putle16(&fr->data, bslen - 2); + aimbs_putle32(&fr->data, atoi(sess->sn)); + aimbs_putle16(&fr->data, 0x003c); /* I command thee. */ + aimbs_putle16(&fr->data, snacid); /* eh. */ + + aim_tx_enqueue(sess, fr); + + return 0; +} + +faim_export int aim_icq_ackofflinemsgs(aim_session_t *sess) +{ + aim_conn_t *conn; + aim_frame_t *fr; + aim_snacid_t snacid; + int bslen; + + if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) + return -EINVAL; + + bslen = 2 + 4 + 2 + 2; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); + + /* For simplicity, don't bother using a tlvlist */ + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, bslen); + + aimbs_putle16(&fr->data, bslen - 2); + aimbs_putle32(&fr->data, atoi(sess->sn)); + aimbs_putle16(&fr->data, 0x003e); /* I command thee. */ + aimbs_putle16(&fr->data, snacid); /* eh. */ + + aim_tx_enqueue(sess, fr); + + return 0; +} + +faim_export int aim_icq_sendxmlreq(aim_session_t *sess, const char *xml) +{ + aim_conn_t *conn; + aim_frame_t *fr; + aim_snacid_t snacid; + int bslen; + + if (!xml || !strlen(xml)) + return -EINVAL; + + if (!sess || !(conn = aim_conn_findbygroup(sess, 0x0015))) + return -EINVAL; + + bslen = 2 + 10 + 2 + strlen(xml) + 1; + + if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 4 + bslen))) + return -ENOMEM; + + snacid = aim_cachesnac(sess, 0x0015, 0x0002, 0x0000, NULL, 0); + aim_putsnac(&fr->data, 0x0015, 0x0002, 0x0000, snacid); + + /* For simplicity, don't bother using a tlvlist */ + aimbs_put16(&fr->data, 0x0001); + aimbs_put16(&fr->data, bslen); + + aimbs_putle16(&fr->data, bslen - 2); + aimbs_putle32(&fr->data, atoi(sess->sn)); + aimbs_putle16(&fr->data, 0x07d0); /* I command thee. */ + aimbs_putle16(&fr->data, snacid); /* eh. */ + aimbs_putle16(&fr->data, 0x0998); /* shrug. */ + aimbs_putle16(&fr->data, strlen(xml) + 1); + aimbs_putraw(&fr->data, xml, strlen(xml) + 1); + + aim_tx_enqueue(sess, fr); + + return 0; +} + /* * Response to 15/2, contains an ICQ packet. */ static int icqresponse(aim_session_t *sess, aim_module_t *mod, aim_frame_t *rx, aim_modsnac_t *snac, aim_bstream_t *bs) { int ret = 0; - aim_rxcallback_t userfunc; + aim_tlvlist_t *tl; + aim_tlv_t *datatlv; + aim_bstream_t qbs; + fu32_t ouruin; + fu16_t cmdlen, cmd, reqid; - if ((userfunc = aim_callhandler(sess, rx->conn, snac->family, snac->subtype))) - ret = userfunc(sess, rx); + if (!(tl = aim_readtlvchain(bs)) || !(datatlv = aim_gettlv(tl, 0x0001, 1))) { + faimdprintf(sess, 0, "corrupt ICQ response\n"); + return 0; + } + + aim_bstream_init(&qbs, datatlv->value, datatlv->length); + + cmdlen = aimbs_getle16(&qbs); + ouruin = aimbs_getle32(&qbs); + cmd = aimbs_getle16(&qbs); + reqid = aimbs_getle16(&qbs); + + faimdprintf(sess, 1, "icq response: %d bytes, %ld, 0x%04x, 0x%04x\n", cmdlen, ouruin, cmd, reqid); + + if (cmd == 0x0041) { + fu16_t msglen; + struct aim_icq_offlinemsg msg; + aim_rxcallback_t userfunc; + + memset(&msg, 0, sizeof(msg)); + + msg.sender = aimbs_getle32(&qbs); + msg.year = aimbs_getle16(&qbs); + msg.month = aimbs_getle8(&qbs); + msg.day = aimbs_getle8(&qbs); + msg.hour = aimbs_getle8(&qbs); + msg.minute = aimbs_getle8(&qbs); + msg.type = aimbs_getle16(&qbs); + msglen = aimbs_getle16(&qbs); + msg.msg = aimbs_getstr(&qbs, msglen); + + if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG))) + ret = userfunc(sess, rx, &msg); + + free(msg.msg); + + } else if (cmd == 0x0042) { + aim_rxcallback_t userfunc; + + if ((userfunc = aim_callhandler(sess, rx->conn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE))) + ret = userfunc(sess, rx); + } return ret; } Index: oscar.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/oscar.c,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- oscar.c 2001/11/10 02:07:37 1.62 +++ oscar.c 2001/11/10 08:02:39 1.63 @@ -240,6 +240,8 @@ static int gaim_parse_genericerr (aim_session_t *, aim_frame_t *, ...); static int gaim_memrequest (aim_session_t *, aim_frame_t*, ...); static int gaim_selfinfo (aim_session_t *, aim_frame_t*, ...); +static int gaim_offlinemsg (aim_session_t *, aim_frame_t*, ...); +static int gaim_offlinemsgdone (aim_session_t *, aim_frame_t*, ...); static int gaim_directim_initiate (aim_session_t *, aim_frame_t *, ...); static int gaim_directim_incoming (aim_session_t *, aim_frame_t *, ...); @@ -445,8 +447,11 @@ odata->icq = TRUE; /* this is odd but it's necessary for a proper do_import and do_export */ gc->protocol = PROTO_ICQ; - } else + gc->checkbox = _("Send offline message"); + } else { gc->protocol = PROTO_TOC; + gc->flags |= OPT_CONN_HTML; + } sess = g_new0(aim_session_t, 1); @@ -645,6 +650,8 @@ aim_conn_addhandler(sess, bosconn, 0x0009, 0x0001, gaim_parse_genericerr, 0); aim_conn_addhandler(sess, bosconn, 0x0001, 0x001f, gaim_memrequest, 0); aim_conn_addhandler(sess, bosconn, 0x0001, 0x000f, gaim_selfinfo, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSG, gaim_offlinemsg, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_ICQ, AIM_CB_ICQ_OFFLINEMSGCOMPLETE, gaim_offlinemsgdone, 0); ((struct oscar_data *)gc->proto_data)->conn = bosconn; for (i = 0; i < (int)strlen(info->bosip); i++) { @@ -1979,11 +1986,40 @@ aim_clientready(sess, fr->conn); + aim_icq_reqofflinemsgs(sess); + aim_reqservice(sess, fr->conn, AIM_CONN_TYPE_CHATNAV); return 1; } +static int gaim_offlinemsg(aim_session_t *sess, aim_frame_t *fr, ...) { + va_list ap; + struct aim_icq_offlinemsg *msg; + struct gaim_connection *gc = sess->aux_data; + + va_start(ap, fr); + msg = va_arg(ap, struct aim_icq_offlinemsg *); + va_end(ap); + + if (msg->type == 0x0001) { + char sender[32]; + time_t t = get_time(msg->year, msg->month, msg->day, msg->hour, msg->minute, 0); + g_snprintf(sender, sizeof(sender), "%lu", msg->sender); + serv_got_im(gc, sender, msg->msg, 0, t); + } else { + debug_printf("unknown offline message type 0x%04x\n", msg->type); + } + + return 1; +} + +static int gaim_offlinemsgdone(aim_session_t *sess, aim_frame_t *fr, ...) +{ + aim_icq_ackofflinemsgs(sess); + return 1; +} + static int gaim_parse_searchreply(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; char *address, *SNs; @@ -2088,9 +2124,11 @@ if (dim) { ret = aim_send_im_direct(odata->sess, dim->conn, message); } else { - if (imflags & IM_FLAG_AWAY) + if (imflags & IM_FLAG_AWAY) { ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_AWAY, message); - else { + } else if (imflags & IM_FLAG_CHECKBOX) { + ret = aim_send_im(odata->sess, name, AIM_IMFLAGS_OFFLINE, message); + } else { struct aim_sendimext_args args; GSList *h = odata->hasicons; struct icon_req *ir = NULL; @@ -2771,7 +2809,7 @@ void oscar_init(struct prpl *ret) { ret->protocol = PROTO_OSCAR; - ret->options = OPT_PROTO_HTML | OPT_PROTO_BUDDY_ICON; + ret->options = OPT_PROTO_BUDDY_ICON; ret->name = oscar_name; ret->list_icon = oscar_list_icon; ret->away_states = oscar_away_states; Index: rxqueue.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/rxqueue.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- rxqueue.c 2001/09/12 00:39:51 1.3 +++ rxqueue.c 2001/11/10 08:02:39 1.4 @@ -149,6 +149,39 @@ return aimutil_get32(bs->data + bs->offset - 4); } +faim_internal fu8_t aimbs_getle8(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 1) + return 0; /* XXX throw an exception */ + + bs->offset++; + + return aimutil_getle8(bs->data + bs->offset - 1); +} + +faim_internal fu16_t aimbs_getle16(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 2) + return 0; /* XXX throw an exception */ + + bs->offset += 2; + + return aimutil_getle16(bs->data + bs->offset - 2); +} + +faim_internal fu32_t aimbs_getle32(aim_bstream_t *bs) +{ + + if (aim_bstream_empty(bs) < 4) + return 0; /* XXX throw an exception */ + + bs->offset += 4; + + return aimutil_getle32(bs->data + bs->offset - 4); +} + faim_internal int aimbs_put8(aim_bstream_t *bs, fu8_t v) { @@ -178,6 +211,39 @@ return 0; /* XXX throw an exception */ bs->offset += aimutil_put32(bs->data + bs->offset, v); + + return 1; +} + +faim_internal int aimbs_putle8(aim_bstream_t *bs, fu8_t v) +{ + + if (aim_bstream_empty(bs) < 1) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_putle8(bs->data + bs->offset, v); + + return 1; +} + +faim_internal int aimbs_putle16(aim_bstream_t *bs, fu16_t v) +{ + + if (aim_bstream_empty(bs) < 2) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_putle16(bs->data + bs->offset, v); + + return 2; +} + +faim_internal int aimbs_putle32(aim_bstream_t *bs, fu32_t v) +{ + + if (aim_bstream_empty(bs) < 4) + return 0; /* XXX throw an exception */ + + bs->offset += aimutil_putle32(bs->data + bs->offset, v); return 1; } |