From: Luke S. <lsc...@re...> - 2002-09-19 01:54:46
|
On Wed, Sep 18, 2002 at 08:49:41PM -0400, William T. Mahan wrote: > Hi, > > I was annoyed by not being able to receive files from friends on AIM > without switching to the crippled TOC protocol. As a result I made lots of people are, but few people want to look at code. > some changes (patch attached) to add support for receiving files to > the Oscar protocol handler. At present I only handle the case in > which one's buddy initiates the connection (probably using a Windows > client). > > The patch is still unrefined, but I am able to use it to reliably > receive files of various sizes, and I would like to make it available > for comments and further testing. If people find my changes useful, I > am interested in polishing them some more, and then perhaps adding > support for file sending and initiating connections. > > Other notes: > * This patch is against current CVS (for GTK 2), but I originally > developed it for the 0.59.x tree; I can provide a diff for the stable > series if people are interested. 0.59.x is not accepting new features, 0.60cvs is indeed the appropriate place. > * Significant implementation of file-transfer support was already in > place, albeit disabled. Much of my work involved re-enabling old code > and updating it to a compilable state. > * I didn't introduce any GTK into the protocol handler. :-) good. > * I am particularly interested in comments regarding my save-as > dialog (i.e. the bottom of dialogs.c). This is the only place that > the patch touches generic code, and suggestions would be welcome > because I don't have a lot of experience with GTK. yeah! someone who listened and did a generic interface!. yes, your code is of interest, please post a patch to www.sf.net/projects/gaim, and i'll direct interested parties to try it and send you comments. i do not promise, will not promise that a developer will look at it or merge it in soon, chances are that won't be the case, but you will get the comments from users you seem to desire. luke > > -- Wil > Index: src/dialogs.c > =================================================================== > RCS file: /cvsroot/gaim/gaim/src/dialogs.c,v > retrieving revision 1.339 > diff -u -r1.339 dialogs.c > --- src/dialogs.c 17 Sep 2002 16:43:59 -0000 1.339 > +++ src/dialogs.c 19 Sep 2002 00:07:21 -0000 > @@ -5247,3 +5247,61 @@ > /* End dialog for setting v-card info */ > /*------------------------------------------------------------------------*/ > > +/*------------------------------------------------------------------------*/ > +/* Generic save-as dialog by Wil Mahan <wt...@du...> */ > +/*------------------------------------------------------------------------*/ > +struct save_as_s { > + GtkWidget *w; > + void (*ok)(); > + void (*cancel)(); > + void *data; > +}; > + > +static void save_as_cancel(gpointer a, struct save_as_s *sa) { > + if (sa->w) { > + gtk_widget_destroy(sa->w); > + sa->w = NULL; > + > + sa->cancel(NULL, sa->data); > + } > +} > + > +static void save_as_ok(gpointer a, struct save_as_s *sa) { > + if (sa->w) { > + char *name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(sa->w))); > + > + gtk_widget_destroy(sa->w); > + sa->w = NULL; > + > + sa->ok(NULL, name, sa->data); > + } > +} > + > +void do_save_as_dialog(char *name, void *ok_callback, > + void *cancel_callback, void *data) { > + GtkWidget *window; > + struct save_as_s *sa = g_new0(struct save_as_s, 1); > + char initstr[BUF_LONG]; > + > + window = gtk_file_selection_new(_("Gaim - Save As...")); > + g_snprintf(initstr, sizeof(initstr), "%s/%s", > + g_get_home_dir(), name); > + > + sa->w = window; > + sa->ok = ok_callback; > + sa->cancel = cancel_callback; > + sa->data = data; > + > + gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), initstr); > + > + gtk_signal_connect(GTK_OBJECT(window), "delete_event", > + GTK_SIGNAL_FUNC(save_as_cancel), sa); > + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->cancel_button), > + "clicked", GTK_SIGNAL_FUNC(save_as_cancel), sa); > + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(window)->ok_button), > + "clicked", GTK_SIGNAL_FUNC(save_as_ok), sa); > + > + gtk_widget_show(window); > +} > + > + > Index: src/protocols/oscar/aim.h > =================================================================== > RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/aim.h,v > retrieving revision 1.46 > diff -u -r1.46 aim.h > --- src/protocols/oscar/aim.h 29 Aug 2002 01:47:15 -0000 1.46 > +++ src/protocols/oscar/aim.h 19 Sep 2002 00:07:21 -0000 > @@ -695,6 +695,13 @@ > char ip[30]; > int state; > struct aim_fileheader_t fh; > + > + int files; > + char *filename; > + FILE *file; > + int recvsize; > + int totsize; > + int inpa; > }; > > struct aim_chat_roominfo { > @@ -950,7 +957,7 @@ > #define AIM_TRANSFER_DENY_DECLINE 0x0001 > #define AIM_TRANSFER_DENY_NOTACCEPTING 0x0002 > faim_export int aim_denytransfer(aim_session_t *sess, const char *sender, const char *cookie, unsigned short code); > -faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, fu16_t listingfiles, fu16_t listingtotsize, fu16_t listingsize, fu32_t listingchecksum, fu16_t rendid); > +faim_export aim_conn_t *aim_accepttransfer(aim_session_t *sess, aim_conn_t *conn, const char *sn, const fu8_t *cookie, const fu8_t *ip, const fu16_t port, fu16_t listingfiles, fu16_t listingtotsize, fu16_t listingsize, fu32_t listingchecksum, fu16_t rendid); > > faim_export int aim_getinfo(aim_session_t *, aim_conn_t *, const char *, unsigned short); > faim_export int aim_sendbuddyoncoming(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *info); > Index: src/protocols/oscar/aim_internal.h > =================================================================== > RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/aim_internal.h,v > retrieving revision 1.12 > diff -u -r1.12 aim_internal.h > --- src/protocols/oscar/aim_internal.h 10 Dec 2001 00:48:27 -0000 1.12 > +++ src/protocols/oscar/aim_internal.h 19 Sep 2002 00:07:22 -0000 > @@ -91,7 +91,7 @@ > > faim_internal int aim_tx_sendframe(aim_session_t *sess, aim_frame_t *cur); > faim_internal flap_seqnum_t aim_get_next_txseqnum(aim_conn_t *); > -faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen); > +faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen); > faim_internal void aim_frame_destroy(aim_frame_t *); > faim_internal int aim_tx_enqueue(aim_session_t *, aim_frame_t *); > faim_internal int aim_tx_printqueue(aim_session_t *); > Index: src/protocols/oscar/ft.c > =================================================================== > RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/ft.c,v > retrieving revision 1.16 > diff -u -r1.16 ft.c > --- src/protocols/oscar/ft.c 12 Mar 2002 17:21:44 -0000 1.16 > +++ src/protocols/oscar/ft.c 19 Sep 2002 00:07:22 -0000 > @@ -32,6 +32,7 @@ > }; > > static int listenestablish(fu16_t portnum); > +static struct aim_fileheader_t *aim_oft_getfh(unsigned char *hdr); > > /** > * aim_handlerendconnect - call this to accept OFT connections and set up the required structures > @@ -547,26 +548,32 @@ > aim_conn_t *conn, > const char *sn, const fu8_t *cookie, > const fu8_t *ip, > + const fu16_t port, > fu16_t listingfiles, > fu16_t listingtotsize, > fu16_t listingsize, > fu32_t listingchecksum, > fu16_t rendid) > { > - return NULL; > -#if 0 > - struct command_tx_struct *newpacket, *newoft; > - struct aim_conn_t *newconn; > + aim_frame_t *newpacket, *newoft; > + aim_conn_t *newconn; > struct aim_fileheader_t *fh; > struct aim_filetransfer_priv *priv; > - struct aim_msgcookie_t *cachedcook; > - int curbyte, i; > + aim_msgcookie_t *cachedcook; > + int i; > + char addr[21]; > > if (!sess || !conn || !sn || !cookie || !ip) { > return NULL; > } > > - newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, ip); > + g_snprintf(addr, sizeof(addr), "%s:%d", ip, port); > + newconn = aim_newconn(sess, AIM_CONN_TYPE_RENDEZVOUS, addr); > + > + if (newconn->status & AIM_CONN_STATUS_CONNERR) { > + debug_printf("aim_accepttransfer: failed to create connection\n"); > + return NULL; > + } > > if (!newconn || (newconn->fd == -1)) { > perror("aim_newconn"); > @@ -585,6 +592,8 @@ > } > > if (rendid == AIM_CAPS_GETFILE) { > + return NULL; /* This should never happen for now. -- wtm */ > + > newconn->subtype = AIM_CONN_SUBTYPE_OFT_GETFILE; > > faimdprintf(sess, 2, "faim: getfile request accept\n"); > @@ -595,7 +604,6 @@ > return NULL; > } > > - newoft->lock = 1; > memcpy(newoft->hdr.oft.magic, "OFT2", 4); > newoft->hdr.oft.hdr2len = 0x100 - 8; > > @@ -622,7 +630,7 @@ > fh->nrecvd = 0x00000000; > fh->recvcsum = 0x00000000; > memset(fh->idstring, 0, sizeof(fh->idstring)); > - memcpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); > + strncpy(fh->idstring, "OFT_Windows ICBMFT V1.1 32", sizeof(fh->idstring)); > fh->flags = 0x02; > fh->lnameoffset = 0x1a; > fh->lsizeoffset = 0x10; > @@ -633,10 +641,9 @@ > fh->nencode = 0x0000; > fh->nlanguage = 0x0000; > memset(fh->name, 0, sizeof(fh->name)); > - memcpy(fh->name, "listing.txt", sizeof(fh->name)); > + strncpy(fh->name, "listing.txt", sizeof(fh->name)); > > if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { > - newoft->lock = 0; > aim_frame_destroy(newoft); > /* XXX: conn leak */ > perror("calloc (1)"); > @@ -648,10 +655,9 @@ > if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, fh))) > faimdprintf(sess, 1, "eek, bh fail!\n"); > > - newoft->lock = 0; > aim_tx_enqueue(sess, newoft); > > - if (!(cachedcook = (struct aim_msgcookie_t *)calloc(1, sizeof(struct aim_msgcookie_t)))) { > + if (!(cachedcook = (aim_msgcookie_t *)calloc(1, sizeof(aim_msgcookie_t)))) { > faimdprintf(sess, 1, "faim: accepttransfer: couldn't calloc cachedcook. yeep!\n"); > /* XXX: more cleanup, conn leak */ > perror("calloc (2)"); > @@ -668,38 +674,39 @@ > faimdprintf(sess, 1, "faim: ERROR caching message cookie\n"); > > free(fh); > - > - /* OSCAR CAP accept packet */ > - > - if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_OSCAR, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { > - return NULL; > - } > + > + } else if (rendid == AIM_CAPS_SENDFILE) { > + newconn->subtype = AIM_CONN_SUBTYPE_OFT_SENDFILE; > } else { > return NULL; > } > + > + /* OSCAR CAP accept packet */ > + > + > + if (!(newpacket = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x0002, 10+8+2+1+strlen(sn)+4+2+8+16))) { > + return NULL; > + } > > - newpacket->lock = 1; > - curbyte = aim_putsnac(newpacket->data, 0x0004, 0x0006, 0x0000, sess->snac_nextid); > + aim_putsnac(&newpacket->data, 0x0004, 0x0006, 0x0000, sess->snacid_next); > > for (i = 0; i < 8; i++) > - curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]); > + aimbs_put8(&newpacket->data, cookie[i]); > > - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002); > - curbyte += aimutil_put8(newpacket->data+curbyte, strlen(sn)); > - curbyte += aimutil_putstr(newpacket->data+curbyte, sn, strlen(sn)); > - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0005); > - curbyte += aimutil_put16(newpacket->data+curbyte, 0x001a); > - curbyte += aimutil_put16(newpacket->data+curbyte, 0x0002 /* accept*/); > + aimbs_put16(&newpacket->data, 0x0002); > + aimbs_put8(&newpacket->data, strlen(sn)); > + aimbs_putraw(&newpacket->data, sn, strlen(sn)); > + aimbs_put16(&newpacket->data, 0x0005); > + aimbs_put16(&newpacket->data, 0x001a); > + aimbs_put16(&newpacket->data, 0x0002 /* accept*/); > > for (i = 0;i < 8; i++) > - curbyte += aimutil_put8(newpacket->data+curbyte, cookie[i]); > + aimbs_put8(&newpacket->data, cookie[i]); > > - curbyte += aim_putcap(newpacket->data+curbyte, 0x10, rendid); > - newpacket->lock = 0; > + aim_putcap(&newpacket->data, AIM_CAPS_GETFILE); > aim_tx_enqueue(sess, newpacket); > > return newconn; > -#endif > } > > /** > @@ -907,7 +914,6 @@ > > static int getcommand_getfile(aim_session_t *sess, aim_conn_t *conn) > { > -#if 0 > struct aim_filetransfer_priv *ft; > aim_rxcallback_t userfunc; > > @@ -916,7 +922,7 @@ > /* waiting on listing data */ > int ret = 0; > char *listing; > - struct command_tx_struct *newoft; > + aim_frame_t *newoft; > > if (!(listing = malloc(ft->fh.size))) > return -1; > @@ -927,7 +933,6 @@ > > if (!(newoft = aim_tx_new(sess, conn, AIM_FRAMETYPE_OFT, 0x120b, 0))) { > faimdprintf(sess, 2, "faim: aim_get_command_rendezvous: getfile listing: tx_new OFT failed\n"); > - faim_mutex_unlock(&conn->active); > free(listing); > aim_conn_close(conn); > return -1; > @@ -975,9 +980,6 @@ > } > > return 0; > -#else > - return -1; > -#endif > } > > static void connclose_sendfile(aim_session_t *sess, aim_conn_t *conn) > @@ -988,6 +990,11 @@ > cook = aim_uncachecookie(sess, priv->cookie, AIM_COOKIETYPE_OFTSEND); > aim_cookie_free(sess, cook); > > + if (priv->file) { > + fclose(priv->file); > + priv->file = 0; > + } > + > return; > } > > @@ -1143,7 +1150,7 @@ > struct aim_filetransfer_priv *ft; > struct aim_fileheader_t *fh; > struct aim_msgcookie_t *cook; > - struct command_tx_struct *newoft; > + aim_frame_t *newoft; > aim_rxcallback_t userfunc; > > faimdprintf(sess, 2,"faim: rend: fileget 0x1108\n"); > @@ -1320,15 +1327,16 @@ > > static int handlehdr_getfile_sending(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) > { > -#if 0 > - struct aim_fileheader_t *fh; > struct aim_filetransfer_priv *ft; > - struct aim_msgcookie_t *cook; > - struct command_tx_struct *newoft; > + struct aim_fileheader_t *fh; > + aim_msgcookie_t *cook; > + aim_frame_t *newoft; > aim_rxcallback_t userfunc; > > fh = aim_oft_getfh(hdr); > > + /* It appears that clients send a null cookie.... -- wtm */ > +#if 0 > if (!(cook = aim_checkcookie(sess, fh->bcookie, AIM_COOKIETYPE_OFTGET))) { > free(fh); > return -1; > @@ -1338,10 +1346,18 @@ > > ft = cook->data; > > - ft->state = 3; > - > if (aim_cachecookie(sess, cook) == -1) > return -1; > +#else > + ft = conn->priv; > + memcpy(&(fh->bcookie), ft->cookie, 8); > +#endif > + > + ft->state = 3; > + ft->totsize = fh->totsize; > + > + memcpy(&(ft->fh), fh, sizeof(struct aim_fileheader_t)); > + free(fh); > > faimdprintf(sess, 2, "faim: fileget: %s seems to want to send %s\n", ft->sn, ft->fh.name); > > @@ -1350,7 +1366,6 @@ > return -1; > } > > - newoft->lock = 1; > memcpy(newoft->hdr.oft.magic, "OFT2", 4); > > newoft->hdr.oft.hdr2len = 0x100 - 8; > @@ -1360,18 +1375,18 @@ > return -1; > } > > - aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)); > + if (!aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, > + &(ft->fh))) { > + return -1; > + } > > - newoft->lock = 0; > aim_tx_enqueue(sess, newoft); > > faimdprintf(sess, 2, "faim: OFT: OFT 0x0202 enqueued.\n"); > > if ( (userfunc = aim_callhandler(sess, conn, AIM_CB_FAM_OFT, AIM_CB_OFT_GETFILEFILEREQ)) == NULL) > return 1; > -#else > - return -1; > -#endif > + return userfunc(sess, NULL, conn, ft); > } > > static int handlehdr_getfile_recv(aim_session_t *sess, aim_conn_t *conn, fu8_t *hdr) > @@ -1444,9 +1459,12 @@ > > memset(hdrbuf1, 0, sizeof(hdrbuf1)); > > - /* I guess? I didn't understand any of that mess... */ > - if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE) > - return getcommand_getfile(sess, conn); > + if (conn->subtype == AIM_CONN_SUBTYPE_OFT_GETFILE > + || conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) { > + struct aim_filetransfer_priv *ft = conn->priv; > + if (ft->state != 0) > + return getcommand_getfile(sess, conn); > + } > > /* XXX fix all the error cases here */ > if (aim_recv(conn->fd, hdrbuf1, 6) < 6) { > @@ -1501,7 +1519,6 @@ > return ret; > } > > -#if 0 > /** > * aim_oft_getfh - extracts an &aim_fileheader_t from buffer hdr. > * @hdr: buffer to extract header from > @@ -1572,7 +1589,6 @@ > i += 64; > return fh; > } > -#endif > > /** > * aim_oft_checksum - calculate oft checksum of buffer > @@ -1645,7 +1661,6 @@ > #endif > } > > -#if 0 > /** > * aim_oft_buildheader - fills a buffer with network-order fh data > * @dest: buffer to fill -- pre-alloced > @@ -1655,7 +1670,7 @@ > * DOES NOT DO BOUNDS CHECKING! > * > */ > -static int oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh) > +faim_export int aim_oft_buildheader(unsigned char *dest, struct aim_fileheader_t *fh) > { > int i, curbyte; > if (!dest || !fh) > @@ -1697,7 +1712,6 @@ > curbyte += 64; > return curbyte; > } > -#endif > > /** > * aim_getfile_intitiate - Request an OFT getfile session > @@ -1865,7 +1879,7 @@ > { > return -EINVAL; > #if 0 > - struct command_tx_struct *newoft; > + aim_frame_t *newoft; > struct aim_filetransfer_priv *ft; > if (!sess || !conn || !conn->priv || !name) > return -1; > @@ -1874,9 +1888,6 @@ > faimdprintf(sess, 2, "faim: aim_accepttransfer: tx_new OFT failed\n"); > return -1; > } > - > - newoft->lock = 1; > - > memcpy(newoft->hdr.oft.magic, "OFT2", 4); > newoft->hdr.oft.hdr2len = 0x100 - 8; > > @@ -1892,19 +1903,15 @@ > memset(ft->fh.name+strlen(name), 0, 1); > > if (!(newoft->hdr.oft.hdr2 = (unsigned char *)calloc(1,newoft->hdr.oft.hdr2len))) { > - newoft->lock = 0; > aim_frame_destroy(newoft); > return -1; > } > > if (!(aim_oft_buildheader(newoft->hdr.oft.hdr2, &(ft->fh)))) { > - newoft->lock = 0; > aim_frame_destroy(newoft); > return -1; > } > > - newoft->lock = 0; > - > aim_tx_enqueue(sess, newoft); > return 0; > #endif > @@ -1969,9 +1976,7 @@ > */ > faim_export int aim_oft_getfile_end(aim_session_t *sess, aim_conn_t *conn) > { > - return -EINVAL; > -#if 0 > - struct command_tx_struct *newoft; > + aim_frame_t *newoft; > struct aim_filetransfer_priv *ft; > > if (!sess || !conn || !conn->priv) > @@ -1982,13 +1987,10 @@ > return -1; > } > > - newoft->lock = 1; > - > memcpy(newoft->hdr.oft.magic, "OFT2", 4); > newoft->hdr.oft.hdr2len = 0x100 - 8; > > if (!(newoft->hdr.oft.hdr2 = (char *)calloc(1,newoft->hdr.oft.hdr2len))) { > - newoft->lock = 0; > aim_frame_destroy(newoft); > return -1; > } > @@ -2000,15 +2002,12 @@ > ft->fh.flags = 0x21; > > if (!(aim_oft_buildheader((unsigned char *)newoft->hdr.oft.hdr2, &(ft->fh)))) { > - newoft->lock = 0; > aim_frame_destroy(newoft); > return -1; > } > > - newoft->lock = 0; > aim_tx_enqueue(sess, newoft); > > return 0; > -#endif /* 0 */ > } > > Index: src/protocols/oscar/oscar.c > =================================================================== > RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/oscar.c,v > retrieving revision 1.149 > diff -u -r1.149 oscar.c > --- src/protocols/oscar/oscar.c 13 Sep 2002 06:41:21 -0000 1.149 > +++ src/protocols/oscar/oscar.c 19 Sep 2002 00:07:24 -0000 > @@ -73,7 +73,13 @@ > > #define AIMHASHDATA "http://gaim.sourceforge.net/aim_data.php3" > > -static int caps_aim = AIM_CAPS_CHAT | AIM_CAPS_BUDDYICON | AIM_CAPS_IMIMAGE; > + > +extern void do_save_as_dialog(char *name, void *ok_callback, > + void *cancel_callback, void *data); > + > +static int caps_aim = AIM_CAPS_CHAT | AIM_CAPS_BUDDYICON | > + AIM_CAPS_IMIMAGE | AIM_CAPS_SENDFILE; > + > /* What does AIM_CAPS_ICQ actually mean? -SE */ > /* static int caps_icq = AIM_CAPS_ICQ; */ > > @@ -155,6 +161,15 @@ > fu8_t cookie[8]; > }; > > +struct ask_getfile { > + struct gaim_connection *gc; > + char *sn; > + char ip[64]; > + fu16_t port; > + fu8_t cookie[8]; > + char name[64]; > +}; > + > struct icon_req { > char *user; > time_t timestamp; > @@ -288,6 +303,9 @@ > static int gaim_directim_typing (aim_session_t *, aim_frame_t *, ...); > static int gaim_update_ui (aim_session_t *, aim_frame_t *, ...); > > +static int gaim_getfile_handle (aim_session_t *, aim_frame_t *, ...); > +static int gaim_getfile_choosefile(aim_session_t *sess, aim_frame_t *fr, ...); > + > static char *msgerrreason[] = { > "Invalid error", > "Invalid SNAC", > @@ -317,6 +335,18 @@ > }; > static int msgerrreasonlen = 25; > > +static void gaim_getfile_disconnect(aim_session_t *sess, aim_conn_t *conn) { > + struct gaim_connection *gc = sess->aux_data; > + struct aim_filetransfer_priv *ft = conn->priv; > + > + aim_oft_getfile_end(sess, conn); > + if (ft->inpa) { > + gaim_input_remove(ft->inpa); > + ft->inpa = 0; > + } > + aim_conn_kill(sess, &conn); > +} > + > static void gaim_directim_disconnect(aim_session_t *sess, aim_conn_t *conn) { > struct gaim_connection *gc = sess->aux_data; > struct oscar_data *od = (struct oscar_data *)gc->proto_data; > @@ -423,6 +453,8 @@ > } else if (conn->type == AIM_CONN_TYPE_RENDEZVOUS) { > if (conn->subtype == AIM_CONN_SUBTYPE_OFT_DIRECTIM) > gaim_directim_disconnect(odata->sess, conn); > + else if (conn->subtype == AIM_CONN_SUBTYPE_OFT_SENDFILE) > + gaim_getfile_disconnect(odata->sess, conn); > else { > debug_printf("No handler for rendezvous disconnect (%d).\n", > source); > @@ -1236,6 +1268,13 @@ > g_free(d); > } > > +static void cancel_getfile(gpointer w, struct ask_getfile *g) { > + debug_printf("Freeing getfile prompts.\n"); > + > + g_free(g->sn); > + g_free(g); > +} > + > static void oscar_directim_callback(gpointer data, gint source, GaimInputCondition condition) { > struct direct_im *dim = data; > struct gaim_connection *gc = dim->gc; > @@ -1273,6 +1312,34 @@ > oscar_callback, dim->conn); > } > > +static void accept_getfile(gpointer w, struct ask_getfile *g) { > + struct gaim_connection *gc = g->gc; > + struct oscar_data *od = (struct oscar_data *)gc->proto_data; > + struct aim_filetransfer_priv *ft; > + aim_conn_t *newconn; > + > + newconn = aim_accepttransfer(od->sess, od->conn, g->sn, > + g->cookie, g->ip, > + g->port, 1, 27, 10, 0xffff, > + AIM_CAPS_SENDFILE); > + if (!newconn) { > + char *buf = g_strdup_printf("Couldn't connect to remote host"); > + do_error_dialog(buf, NULL, GAIM_ERROR); > + g_free(buf); > + return; > + } > + > + aim_conn_addhandler(od->sess, newconn, AIM_CB_FAM_OFT, > + AIM_CB_OFT_GETFILEFILEREQ, gaim_getfile_choosefile, > + 0); > + > + ft = newconn->priv; > + ft->inpa = gaim_input_add(newconn->fd, GAIM_INPUT_READ, > + oscar_callback, newconn); > + > + return; > +} > + > static int accept_direct_im(gpointer w, struct ask_direct *d) { > struct gaim_connection *gc = d->gc; > struct oscar_data *od = (struct oscar_data *)gc->proto_data; > @@ -1417,8 +1484,14 @@ > > debug_printf("rendezvous status %d (%s)\n", args->status, userinfo->sn); > > - if (args->status != AIM_RENDEZVOUS_PROPOSE) > + > + if (args->status != AIM_RENDEZVOUS_PROPOSE) { > + /* XXX We should do something sane when the other side > + * aborts (AIM_RENDEZVOUS_CANCEL), but how do we get > + * the appropriate aim_conn_t? -- wtm > + */ > return 1; > + } > > if (args->reqclass & AIM_CAPS_CHAT) { > char *name = extract_name(args->info.chat.roominfo.name); > @@ -1435,6 +1508,21 @@ > if (name) > g_free(name); > } else if (args->reqclass & AIM_CAPS_SENDFILE) { > + struct ask_getfile *g = g_new0(struct ask_getfile, 1); > + char buf[256]; > + > + debug_printf("%s (%s) requests to send a file to %s\n", > + userinfo->sn, args->verifiedip, gc->username); > + > + g->gc = gc; > + g->sn = g_strdup(userinfo->sn); > + strncpy(g->ip, args->verifiedip, sizeof(g->ip)); > + g->port = args->port; > + memcpy(g->cookie, args->cookie, 8); > + > + g_snprintf(buf, sizeof buf, "%s requests to send a file to %s.", > + userinfo->sn, gc->username); > + do_ask_dialog(buf, g, accept_getfile, cancel_getfile); > } else if (args->reqclass & AIM_CAPS_GETFILE) { > } else if (args->reqclass & AIM_CAPS_VOICE) { > } else if (args->reqclass & AIM_CAPS_BUDDYICON) { > @@ -3483,6 +3571,113 @@ > if (uc & UC_NORMAL) > return (char **)free_icon_xpm; > return NULL; > +} > + > +static void gaim_getfile_callback(gpointer data, gint source, > + GaimInputCondition condition) { > + aim_conn_t *conn = (aim_conn_t *)data; > + aim_session_t *sess = aim_conn_getsess(conn); > + struct aim_filetransfer_priv *ft = conn->priv; > + int rt, i; > + char buf[BUF_LONG]; > + > + if (condition & GAIM_INPUT_READ) { > + rt = read(conn->fd, buf, > + MIN(ft->totsize - ft->recvsize, 1024)); > + > + if (rt < 0) { > + do_error_dialog("File transfer failed; other side probably canceled.", > + NULL, GAIM_ERROR); > + gaim_getfile_disconnect(sess, conn); > + return; > + } > + > + ft->recvsize += rt; > + for (i = 0; i < rt; i++) > + fprintf(ft->file, "%c", buf[i]); > + > + if (ft->recvsize == ft->totsize) { > + char *buf = g_strdup_printf(_("File transfer from %s completed successfully."), ft->sn); > + do_error_dialog(buf, NULL, GAIM_INFO); > + g_free(buf); > + gaim_getfile_disconnect(sess, conn); > + return; > + } > + } > +} > + > +static int gaim_getfile_choosefile_ok(gpointer w, char *name, > + aim_conn_t *conn) { > + struct aim_filetransfer_priv *ft = conn->priv; > + > + ft->file = fopen(name, "w"); > + if (!ft->file) { > + char *buf = g_strdup_printf(_("Could not open %s for writing."), > + name); > + do_error_dialog(buf, NULL, GAIM_ERROR); > + g_free(buf); > + return; > + } > + > + g_free(name); > + > + /* Now we can handle the incoming data. */ > + aim_conn_addhandler(aim_conn_getsess(conn), conn, AIM_CB_FAM_OFT, > + AIM_CB_OFT_GETFILERECEIVE, gaim_getfile_handle, > + 0); > + ft->inpa = gaim_input_add(conn->fd, GAIM_INPUT_READ, > + oscar_callback, conn); > + > + return 0; > +} > + > +static int gaim_getfile_choosefile_cancel(gpointer w, aim_conn_t *conn) { > + gaim_getfile_disconnect(aim_conn_getsess(conn), conn); > + return 0; > +} > + > +static int gaim_getfile_choosefile(aim_session_t *sess, aim_frame_t *fr, ...) { > + va_list ap; > + aim_conn_t *conn; > + struct aim_filetransfer_priv *ft; > + > + va_start(ap, fr); > + conn = va_arg(ap, aim_conn_t *); > + ft = va_arg(ap, struct aim_filetransfer_priv *); > + va_end(ap); > + > + /* We can't handle the raw data until we've opened > + * the output file. */ > + gaim_input_remove(ft->inpa); > + > + if (ft->fh.totfiles != 1) { > + do_error_dialog(_("For now, only receiving one file at a time is supported."), > + NULL, GAIM_ERROR); > + gaim_getfile_disconnect(sess, conn); > + return; > + } > + > + do_save_as_dialog(ft->fh.name, gaim_getfile_choosefile_ok, > + gaim_getfile_choosefile_cancel, conn); > +} > + > +static int gaim_getfile_handle(aim_session_t *sess, aim_frame_t *fr, ...) { > + va_list ap; > + aim_conn_t *conn; > + struct aim_filetransfer_priv *ft; > + > + va_start(ap, fr); > + conn = va_arg(ap, aim_conn_t *); > + ft = va_arg(ap, struct aim_filetransfer_priv *); > + va_end(ap); > + > + gaim_input_remove(ft->inpa); > + ft->inpa = gaim_input_add(conn->fd, GAIM_INPUT_READ, > + gaim_getfile_callback, conn); > + > + gaim_getfile_callback(conn, 0, GAIM_INPUT_READ); > + > + return 0; > } > > static int gaim_directim_initiate(aim_session_t *sess, aim_frame_t *fr, ...) { > Index: src/protocols/oscar/txqueue.c > =================================================================== > RCS file: /cvsroot/gaim/gaim/src/protocols/oscar/txqueue.c,v > retrieving revision 1.5 > diff -u -r1.5 txqueue.c > --- src/protocols/oscar/txqueue.c 15 Mar 2002 00:56:15 -0000 1.5 > +++ src/protocols/oscar/txqueue.c 19 Sep 2002 00:07:24 -0000 > @@ -24,7 +24,7 @@ > * chan = channel for FLAP, hdrtype for OFT > * > */ > -faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu8_t chan, int datalen) > +faim_internal aim_frame_t *aim_tx_new(aim_session_t *sess, aim_conn_t *conn, fu8_t framing, fu16_t chan, int datalen) > { > aim_frame_t *fr; > -- -This email is made of 100% recycled electrons. -If something can go wrong.... FIX IT! If it's Microsoft...delete it. -There are three ways to get something done: (1) Do it yourself. (2) Hire someone to do it for you. (3) Forbid your kids to do it. |