/* libsmtp is a library to send mail via SMTP This part will encode data into quoted-printable format Copyright 2001 Kevin Read This software is available under the GNU Lesser Public License as described in the COPYING file. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Kevin Read Thu Aug 16 2001 */ /* This will only be included when MIME is enabled */ #include "gb_common.h" /* #ifndef __G_LIB_H__ */ #include /* #endif */ /* Encoded line length (max 76)*/ #define LINELEN 72 //#include "../config.h" #include "libsmtp.h" #include "libsmtp_mime.h" /* This function will send data in a part, encoded in quoted printable format. It will not perform any checks whatsoever. */ int libsmtp_int_send_quoted (char *libsmtp_int_data, unsigned int libsmtp_int_length, struct libsmtp_session_struct *libsmtp_session) { /* These are the input buffer and the output buffer */ char libsmtp_int_ogroup[2056], libsmtp_int_obuffer[4]; unsigned char libsmtp_int_char; unsigned char libsmtp_int_last_char; int libsmtp_int_finished=0, libsmtp_int_outbytes=0, libsmtp_int_width=0; int libsmtp_int_newline=0; /* This points into the data stream to the byte we are reading ATM */ unsigned int libsmtp_int_data_ptr=0; /* Lets clear the buffers */ bzero (libsmtp_int_obuffer, 4); bzero (libsmtp_int_ogroup, 2056); libsmtp_int_char = 0; /* The main parsing loop */ while (!libsmtp_int_finished) { /* We fetch a character from the input buffer */ libsmtp_int_last_char = libsmtp_int_char; libsmtp_int_char = libsmtp_int_data[libsmtp_int_data_ptr++]; /* Lets check that we don't read over the end of the input buffer */ if (libsmtp_int_data_ptr >= libsmtp_int_length) libsmtp_int_finished = 1; /* We decide which characters to encode and which not */ switch (libsmtp_int_char) { /* Don't encode whitespace (except at end of line - we check for that below */ case 9: case 32: libsmtp_int_obuffer[0]=0; break; /* We need to encode 61 */ case '=': strcpy(libsmtp_int_obuffer, "=3D"); break; /* Newlines need special observation */ case '\n': /* Newline characters don't need to be encoded, but if they follow whitespace, the whitespace has to be suffixed with = */ libsmtp_int_obuffer[0]=0; libsmtp_int_newline=1; break; default: /* All values below 33 need to be encoded except newline/CR and tab which we have already dealt with above. All values above 126 needs to be encoded as well */ if ((libsmtp_int_char < 33) || (libsmtp_int_char > 126 )) sprintf (libsmtp_int_obuffer, "=%02X", libsmtp_int_char); else if (libsmtp_int_char == '.' && libsmtp_int_width == 0) strcpy(libsmtp_int_obuffer, "=2E"); else /* The rest can go unencoded */ libsmtp_int_obuffer[0]=0; break; } /* Lets see ... */ if (libsmtp_int_obuffer[0]) { /* Something encoded */ strcpy(&libsmtp_int_ogroup[libsmtp_int_outbytes], libsmtp_int_obuffer); libsmtp_int_outbytes+=3; libsmtp_int_width+=3; #ifdef LIBSMTP_QUOTED_DEBUG printf ("Got encoded: %c = %s. Group: %s (%d)\n", libsmtp_int_char, libsmtp_int_obuffer, libsmtp_int_ogroup, libsmtp_int_outbytes); #endif } else { /* An unencoded char */ if (libsmtp_int_newline) { libsmtp_int_newline=0; /* We have to check if the char before us is whitespace */ if (libsmtp_int_outbytes) { if (libsmtp_int_ogroup[libsmtp_int_outbytes-1] <= ' ') { /* We need to add a = after the whitespace */ strcpy(&libsmtp_int_ogroup[libsmtp_int_outbytes], "=\r\n"); //libsmtp_int_ogroup[libsmtp_int_outbytes+1]= libsmtp_int_char; //libsmtp_int_ogroup[libsmtp_int_outbytes+2]=0; libsmtp_int_outbytes += 3; /* We have a new line */ libsmtp_int_width=0; } } strcpy(&libsmtp_int_ogroup[libsmtp_int_outbytes], "\r\n"); libsmtp_int_outbytes += 2; } else { /* An unencoded character is added */ libsmtp_int_ogroup[libsmtp_int_outbytes] = libsmtp_int_char; libsmtp_int_ogroup[libsmtp_int_outbytes+1] = 0; libsmtp_int_outbytes++; libsmtp_int_width++; } #ifdef LIBSMTP_QUOTED_DEBUG printf ("Got unencoded: %c = %s. Group: %s (%d)\n", libsmtp_int_char, libsmtp_int_obuffer, libsmtp_int_ogroup, libsmtp_int_outbytes); #endif } /* After LINELEN characters in a line we need a soft linebreak */ if (libsmtp_int_width >= LINELEN ) { libsmtp_int_ogroup[libsmtp_int_outbytes++]='='; libsmtp_int_ogroup[libsmtp_int_outbytes++]='\r'; libsmtp_int_ogroup[libsmtp_int_outbytes++]='\n'; libsmtp_int_width=0; } /* If we have more than 2K of data, we send it */ if (libsmtp_int_outbytes > 2048) { if (libsmtp_int_send_body (libsmtp_int_ogroup, 2048, libsmtp_session)) return LIBSMTP_ERRORSENDFATAL; #ifdef LIBSMTP_DEBUG printf ("libsmtp_send_quoted: out: %s\n", libsmtp_int_ogroup); #endif /* We reset the pointer into our outbuffer, too */ libsmtp_int_outbytes -= 2048; memcpy(libsmtp_int_ogroup, &libsmtp_int_ogroup[2048], libsmtp_int_outbytes); } } /* We send the rest of the data out anyway. */ /*libsmtp_int_ogroup[libsmtp_int_outbytes++]='\r'; libsmtp_int_ogroup[libsmtp_int_outbytes++]='\n'; libsmtp_int_ogroup[libsmtp_int_outbytes]='\0';*/ if (libsmtp_int_send_body (libsmtp_int_ogroup, libsmtp_int_outbytes, libsmtp_session)) return LIBSMTP_ERRORSENDFATAL; #ifdef LIBSMTP_DEBUG printf ("libsmtp_send_quoted: out: %s\n", libsmtp_int_ogroup); #endif return LIBSMTP_NOERR; } static const char _utf8_char_length[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 }; /* This function will send data in an header, encoded in utf-8 quoted printable format. It will not perform any checks whatsoever. */ int libsmtp_int_send_quoted_header (const char *header, char *libsmtp_int_data, unsigned int libsmtp_int_length, struct libsmtp_session_struct *libsmtp_session) { /* These are the input buffer and the output buffer */ char libsmtp_int_ogroup[2056], libsmtp_int_obuffer[4]; unsigned char libsmtp_int_char; unsigned char libsmtp_int_last_char; int libsmtp_int_finished=0, libsmtp_int_outbytes=0, libsmtp_int_width=0; /* This points into the data stream to the byte we are reading ATM */ unsigned int libsmtp_int_data_ptr=0; int len; /* Lets clear the buffers */ bzero (libsmtp_int_obuffer, 4); bzero (libsmtp_int_ogroup, 2056); libsmtp_int_char = 0; /* Adds the header name */ libsmtp_int_outbytes = sprintf(libsmtp_int_ogroup, "%s =?utf-8?q?", header); libsmtp_int_width = libsmtp_int_outbytes; /* The main parsing loop */ while (!libsmtp_int_finished) { /* We fetch a character from the input buffer */ libsmtp_int_last_char = libsmtp_int_char; libsmtp_int_char = libsmtp_int_data[libsmtp_int_data_ptr++]; libsmtp_int_obuffer[0] = 0; len = 1; if (libsmtp_int_char == 32) libsmtp_int_char = '_'; else if (libsmtp_int_char < 33 || libsmtp_int_char > 126 || libsmtp_int_char == '_' || libsmtp_int_char == 61) len = sprintf(libsmtp_int_obuffer, "=%02X", libsmtp_int_char); if (libsmtp_int_char >= 128) len += (_utf8_char_length[libsmtp_int_char] - 1) * 3; /* After LINELEN characters in a line we need a soft linebreak */ if ((libsmtp_int_width + len) >= LINELEN) { libsmtp_int_outbytes += sprintf(&libsmtp_int_ogroup[libsmtp_int_outbytes], "?=\r\n"); libsmtp_int_width = sprintf(&libsmtp_int_ogroup[libsmtp_int_outbytes], " =?utf-8?q?"); libsmtp_int_outbytes += libsmtp_int_width; } /* Lets see ... */ if (libsmtp_int_obuffer[0]) { /* Something encoded */ strcpy(&libsmtp_int_ogroup[libsmtp_int_outbytes], libsmtp_int_obuffer); libsmtp_int_outbytes += 3; libsmtp_int_width += 3; #ifdef LIBSMTP_QUOTED_DEBUG printf ("Got encoded: %c = %s. Group: %s (%d)\n", libsmtp_int_char, libsmtp_int_obuffer, libsmtp_int_ogroup, libsmtp_int_outbytes); #endif } else { /* An unencoded character is added */ libsmtp_int_ogroup[libsmtp_int_outbytes] = libsmtp_int_char; libsmtp_int_ogroup[libsmtp_int_outbytes + 1] = 0; libsmtp_int_outbytes++; libsmtp_int_width++; #ifdef LIBSMTP_QUOTED_DEBUG printf ("Got unencoded: %c = %s. Group: %s (%d)\n", libsmtp_int_char, libsmtp_int_obuffer, libsmtp_int_ogroup, libsmtp_int_outbytes); #endif } /* Lets check that we don't read over the end of the input buffer */ if (libsmtp_int_data_ptr >= libsmtp_int_length) { libsmtp_int_finished = TRUE; libsmtp_int_outbytes += sprintf(&libsmtp_int_ogroup[libsmtp_int_outbytes], "?=\r\n"); } /* If we have more than 2K of data, we send it */ if (libsmtp_int_outbytes >= 2048 || libsmtp_int_finished) { libsmtp_int_ogroup[libsmtp_int_outbytes] = 0; if (libsmtp_int_send_body (libsmtp_int_ogroup, libsmtp_int_outbytes, libsmtp_session)) return LIBSMTP_ERRORSENDFATAL; #ifdef LIBSMTP_DEBUG printf ("libsmtp_send_quoted: out: %s\n", libsmtp_int_ogroup); #endif /* We reset the pointer into our outbuffer, too */ libsmtp_int_outbytes=0; } } return LIBSMTP_NOERR; }