In trying to figure out what is going on in imclient_write, I simplified struct imclient, and moved from pointers to indices - a matter of taste, I know, but it seems the reply buffer is handled that way.. (One could also s/writelen/imclient->outlen/g)
Cheers, Patrick Index: imclient.c =================================================================== RCS file: /cvs/src/cyrus/lib/imclient.c,v retrieving revision 1.77 diff -u -r1.77 imclient.c --- imclient.c 13 Feb 2003 20:15:40 -0000 1.77 +++ imclient.c 4 Apr 2003 19:37:33 -0000 @@ -120,9 +120,7 @@ /* Data to be output to server */ char outbuf[IMCLIENT_BUFSIZE]; - char *outptr; - size_t outleft; - char *outstart; + size_t outlen; /* Replies being received from server */ char *replybuf; @@ -263,8 +261,10 @@ (*imclient)->saslconn = NULL; (*imclient)->saslcompleted = 0; (*imclient)->servername = xstrdup(hp->h_name); - (*imclient)->outptr = (*imclient)->outstart = (*imclient)->outbuf; - (*imclient)->outleft = (*imclient)->maxplain = sizeof((*imclient)->outbuf); + (*imclient)->outlen = 0; + (*imclient)->replylen = 0; + (*imclient)->alloc_replybuf = 0; + (*imclient)->maxplain = sizeof((*imclient)->outbuf); (*imclient)->interact_results = NULL; imclient_addcallback(*imclient, "", 0, (imclient_proc_t *) 0, (void *)0, @@ -626,41 +625,50 @@ */ void imclient_write(struct imclient *imclient, const char *s, size_t len) { + size_t outleft; + assert(imclient); assert(s); - /* If no data pending for output, reset the buffer */ - if (imclient->outptr == imclient->outstart) { - imclient->outstart = imclient->outptr = imclient->outbuf; - imclient->outleft = imclient->maxplain; - } - + outleft = imclient->maxplain - imclient->outlen; /* While we don't have room to buffer all the output */ - while (len > imclient->outleft) { - /* Copy as much data as will fit in output buffer */ - memcpy(imclient->outptr, s, imclient->outleft); - imclient->outptr += imclient->outleft; - s += imclient->outleft; - len -= imclient->outleft; - imclient->outleft = 0; - - /* Process events until output buffer is flushed */ - while (imclient->outptr != imclient->outstart) { - imclient_processoneevent(imclient); - } - - /* Reset the buffer */ - imclient->outstart = imclient->outptr = imclient->outbuf; - imclient->outleft = imclient->maxplain; + while (len > outleft) { + /* Copy as much data as will fit in output buffer */ + memcpy(imclient->outbuf+imclient->outlen, s, outleft); + imclient->outlen += outleft; + s += outleft; + len -= outleft; + + /* Process events until output buffer is flushed */ + while (imclient->outlen) { + imclient_processoneevent(imclient); + } /* Should only be called once. If not, then not all plain text + * was successfully writen in non sasl case + */ + outleft = imclient->maxplain; /* - imclient->outlen; == 0 */ } /* Copy remaining data to output buffer */ - memcpy(imclient->outptr, s, len); - imclient->outptr += len; - imclient->outleft -= len; + memcpy(imclient->outbuf+imclient->outlen, s, len); + imclient->outlen += len; } /* + * http://bugzilla.andrew.cmu.edu/show_bug.cgi?id=333 + * + * Opened: 2000-10-13 00:02 + * + * imclient doesn't correctly parse literals. this will bite any + * serious imclient application that consistently fetches things with + * literals. + * + * imclient.c, around line 730, uses the variable 'len' in a place + * where it clearly isn't applicable. this is the heart of the bug, + * but we need to fix it so that literals that don't end lines are + * still handled correctly. + */ + +/* * On the connection 'imclient', handle the input 'buf' of size 'len' * from the server. Invoke callbacks as appropriate. */ @@ -1006,13 +1014,13 @@ assert(imclient); for (;;) { - writelen = imclient->outptr - imclient->outstart; + writelen = imclient->outlen; if ((imclient->saslcompleted==1) && (writelen>0)) { unsigned int cryptlen=0; const char *cryptptr=NULL; - if (sasl_encode(imclient->saslconn, imclient->outstart, writelen, + if (sasl_encode(imclient->saslconn, imclient->outbuf, writelen, &cryptptr,&cryptlen)!=SASL_OK) { /* XXX encoding error */ @@ -1032,7 +1040,7 @@ #endif /* HAVE_SSL */ if (n > 0) { - imclient->outstart += writelen; + imclient->outlen = 0; /* what if cryptlen != n ? */ return; } @@ -1047,17 +1055,17 @@ #ifdef HAVE_SSL if (imclient->tls_on==1) { - n = SSL_write(imclient->tls_conn, imclient->outstart, writelen); + n = SSL_write(imclient->tls_conn, imclient->outbuf, writelen); } else { - n = write(imclient->fd, imclient->outstart, writelen); + n = write(imclient->fd, imclient->outbuf, writelen); } #else /* HAVE_SSL */ - n = write(imclient->fd, imclient->outstart, writelen); + n = write(imclient->fd, imclient->outbuf, writelen); #endif /* HAVE_SSL */ if (n > 0) { - imclient->outstart += n; + imclient->outlen -= n; return; } /* XXX Also EPIPE & the like? */