@@ -764,6 +764,70 @@ static int __attribute__ ((nonnull (2, 3, 9, 16))) try_send(struct smtp_session
764764
765765cleanup :
766766 free_if (saslstr );
767+ if (strlen (buf ) >= 4 && buf [3 ] == '-' && (buf [0 ] == '4' || buf [0 ] == '5' )) {
768+ /* If we got the beginning of a multiline response when the error was received,
769+ * keep reading so we can get the entire message, in case we send a bounce,
770+ * as we'll want to include the whole response. */
771+
772+ /* Temporary buf for reading full response
773+ * There's no inherent guarantee that a multiline response in its entirety would
774+ * fit in the max space allocated for one line, but it's very unlikely that it wouldn't.
775+ * We use the same size so that at the end, we can just copy it into the readline buffer that was used,
776+ * so if truncation occurs, so be it. */
777+ char respbuf [SMTP_MAX_BUFSIZE ] = "" ;
778+ char * respptr = respbuf ;
779+ size_t respbuflen = sizeof (respbuf );
780+ size_t bytesleft = respbuflen ;
781+ /* If we aborted due to a nonfinal response, before we quit, continue reading the rest
782+ * of the response, since we probably want the whole thing to include in our bounce message. */
783+ SAFE_FAST_APPEND (respbuf , respbuflen , respptr , bytesleft , "%s" , buf );
784+ for (;;) {
785+ char * continuation ;
786+ int e1 , e2 , e3 ;
787+ char emsg [3 ];
788+ ssize_t rres = bbs_readline (smtpclient .client .rfd , & smtpclient .client .rldata , "\r\n" , SEC_MS (1 ));
789+ if (rres < 0 ) {
790+ bbs_warning ("Unexpected end of response (so far: '%s')\n" , respbuf );
791+ break ;
792+ }
793+ /* Skip the first four characters since this is a continuation of the response */
794+ if (rres < 4 ) {
795+ bbs_warning ("Unexpected end of response: '%s' (so far: '%s')\n" , buf , respbuf );
796+ break ;
797+ }
798+ continuation = buf + 3 ; /* That will skip e.g. "550-" or "550 " */
799+ /* ... but if we have something like "550-5.1.1 text..." or "550 5.1.1 text...", then we need to skip until after the next space
800+ * We don't assume that we necessarily have an enhanced status code, this accomodates either case. */
801+ while (* continuation != ' ' ) {
802+ continuation ++ ;
803+ }
804+ if (!* continuation ) {
805+ break ;
806+ }
807+ continuation ++ ; /* Skip the space, what lies afterwards is the message continuation */
808+ /* This handles the case for something like 550 5.1.1 text... we need to skip the enhanced status code.
809+ * However, note that the enhanced status codes could be variable length (not always X.Y.Z, could be X.Y.ZZ, etc. )
810+ * Hence, if we see something here that looks like an enhanced status code (which can only happen for the last line),
811+ * skip it. */
812+ if (buf [3 ] == ' ' && sscanf (continuation , "%d.%d.%d %1s" , & e1 , & e2 , & e3 , emsg ) == 4 ) {
813+ /* Skip until after the next space, again */
814+ while (* continuation != ' ' ) {
815+ continuation ++ ;
816+ }
817+ continuation ++ ; /* We know this is valid since sscanf already parsed the string */
818+ }
819+ SAFE_FAST_APPEND (respbuf , respbuflen , respptr , bytesleft , "%s" , continuation ); /* automatically adds space inbetween */
820+ if (buf [3 ] != '-' ) {
821+ /* Response is done */
822+ bbs_debug (6 , "Full multi-line response: '%s'\n" , respbuf );
823+ break ;
824+ }
825+ }
826+ /* Afterwards, copy the ENTIRE response back into the readline buffer.
827+ * Yes, this will clobber it since it'll screw up its bookkeeping, but we are done with it at this point.
828+ * This allows us to conveniently shove the full response into the buffer in which the response is already expected. */
829+ strcpy (buf , respbuf ); /* Safe, because the buffers are the same size */
830+ }
767831 if (res > 0 ) {
768832 bbs_smtp_client_send (& smtpclient , "QUIT\r\n" );
769833 }
@@ -1399,7 +1463,7 @@ static int skip_qfile(struct mailq_run *qrun, struct mailq_file *mqf, const char
13991463static int process_queue_file (struct mailq_run * qrun , struct mailq_file * mqf )
14001464{
14011465 int res = -1 ;
1402- char buf [256 ] = "" ;
1466+ char buf [SMTP_MAX_BUFSIZE ] = "" ; /* Long enough to store a full response line */
14031467 struct stringlist * static_routes ;
14041468 struct smtp_tx_data tx ;
14051469 time_t message_age ;
0 commit comments