www.pudn.com > libsmtp.zip > comm.c


/*
  libsmtp is a library to send mail via SMTP
     This is the MIME handling part for communcating with the server
   
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 */

/* #ifndef __G_LIB_H__ */
  #include 
/* #endif */

#include "../config.h"

#include "libsmtp.h"
#include "libsmtp_mime.h"


/* #define LIBSMTP_DEBUG */

int libsmtp_mime_headers (struct libsmtp_session_struct *libsmtp_session)
{
   /* If we use the MIME functionality, we need to send some stuff */
   int libsmtp_temp;
   GString *libsmtp_temp_gstring;
   gchar *libsmtp_temp_string;
   struct libsmtp_part_struct *libsmtp_temp_part;
   
   libsmtp_temp_gstring=g_string_new (NULL);

  /* Are we at the end of the dialogue stage, but haven't sent the
     DATA yet? */
  if ((libsmtp_session->Stage < LIBSMTP_RECIPIENT_STAGE) || \
      (libsmtp_session->Stage > LIBSMTP_HEADERS_STAGE))
  {
    libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
    return LIBSMTP_BADSTAGE;
  }

  /* Maybe we are already in DATA mode so... */
  if (libsmtp_session->Stage < LIBSMTP_DATA_STAGE)
  {
    /* Great finality. After this no more dialogue can go on */
    g_string_assign (libsmtp_temp_gstring, "DATA\r\n");
  
    if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 2))
      return LIBSMTP_ERRORSENDFATAL;
  
    /* What has he to say to a little bit of DATA? */
  
    if (libsmtp_int_read (libsmtp_temp_gstring, libsmtp_session, 2))
    {
      libsmtp_session->ErrorCode = LIBSMTP_ERRORREADFATAL;
      return LIBSMTP_ERRORREADFATAL;
    }

    if (libsmtp_session->LastResponseCode != 354)
    {
      libsmtp_session->ErrorCode = LIBSMTP_WONTACCEPTDATA;
      close(libsmtp_session->socket);
      libsmtp_session->socket=0;
      return LIBSMTP_WONTACCEPTDATA;
    }

    /* We enter the data stage now */
    libsmtp_session->Stage = LIBSMTP_DATA_STAGE;
  }

  /* If we use the MIME stuff we tell them this, too */
  g_string_assign (libsmtp_temp_gstring, "Mime-Version: 1.0\r\n");
  
  #ifdef LIBSMTP_DEBUG
    printf ("libsmtp_mime_headers: %s", libsmtp_temp_gstring->str);
  #endif

  if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
    return LIBSMTP_ERRORSENDFATAL;

  /* If there are no parts defined by now, we assume its
     text/plain MIME type and US-ASCII charset */

  if (!libsmtp_session->Parts)
  {
    g_string_assign (libsmtp_temp_gstring, "Content-Type: text/plain; charset=\"us-ascii\"\r\n");

    #ifdef LIBSMTP_DEBUG
      printf ("libsmtp_mime_headers: %s", libsmtp_temp_gstring->str);
    #endif

    if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
      return LIBSMTP_ERRORSENDFATAL;
  }
  else
  {
    libsmtp_temp_part=libsmtp_session->Parts->data;

    /* We should check for valied MIME settings first */
    if ((libsmtp_temp=libsmtp_int_check_part (libsmtp_temp_part)))
    {
      libsmtp_session->ErrorCode=libsmtp_temp;
      return libsmtp_temp;
    }

    /* Then we look up the names of the MIME settings of the main body part 
       and send them as headers */

    g_string_sprintf (libsmtp_temp_gstring, "Content-Type: %s/%s", \
       libsmtp_int_lookup_mime_type (libsmtp_temp_part), \
       libsmtp_int_lookup_mime_subtype (libsmtp_temp_part));

    #ifdef LIBSMTP_DEBUG
      printf ("libsmtp_mime_headers: %s. Type: %d/%d\n", libsmtp_temp_gstring->str, \
         libsmtp_temp_part->Type, libsmtp_temp_part->Subtype);
    #endif
    
    if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
      return LIBSMTP_ERRORSENDFATAL;

    /* Multipart parts need a boundary set. We define it as a fixed string
       at the moment, with an added dynamic number. This is always 1 here. */

    if (libsmtp_temp_part->Type==LIBSMTP_MIME_MULTIPART)
    {
      g_string_assign (libsmtp_temp_part->Boundary, \
             "----_=_libsmtp_Nextpart__000_000007DA.3B95D19_1");
             
      #ifdef LIBSMTP_DEBUG
        printf ("libsmtp_mime_headers: %s", libsmtp_temp_part->Boundary->str);
      #endif
      
      g_string_sprintf (libsmtp_temp_gstring, ";  boundary=\"%s\"\n",
          libsmtp_temp_part->Boundary->str);

      if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
        return LIBSMTP_ERRORSENDFATAL;
    }
    
    /* Text and message parts will have a charset setting */
    if ((libsmtp_temp_part->Type==LIBSMTP_MIME_TEXT) ||
        (libsmtp_temp_part->Type==LIBSMTP_MIME_MESSAGE))
      if ((libsmtp_temp_string=libsmtp_int_lookup_mime_charset(libsmtp_temp_part)))
      {
        g_string_sprintf (libsmtp_temp_gstring, "; charset=\"%s\"", \
           libsmtp_temp_string);
       
        if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
          return LIBSMTP_ERRORSENDFATAL;

        #ifdef LIBSMTP_DEBUG
          printf ("libsmtp_mime_headers: %s", libsmtp_temp_gstring->str);
        #endif
      }
    
    /* We need a transfer encoding, too */
    
    g_string_sprintf (libsmtp_temp_gstring, "Content-Transfer-Encoding: %s\n", \
       libsmtp_int_lookup_mime_encoding (libsmtp_temp_part));
    
    #ifdef LIBSMTP_DEBUG
      printf ("libsmtp_mime_headers: %s\n", libsmtp_temp_gstring);
    #endif
    
    if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
      return LIBSMTP_ERRORSENDFATAL;
  }
    
  /* We enter the data stage now */
  libsmtp_session->Stage = LIBSMTP_MIMEHEADERS_STAGE;
  
  return LIBSMTP_NOERR;
}


/* This function sends body data. It can only be used in the appropriate
   stage. The data to be sent will to be formatted according to RFC822 and
   the MIME standards. */

int libsmtp_part_send (char *libsmtp_body_data, unsigned long int libsmtp_body_length, \
            struct libsmtp_session_struct *libsmtp_session)
{

  struct libsmtp_part_struct *libsmtp_temp_part;
  int libsmtp_int_errorstate;
  
  /* Headers must have been sent before body data goes out, but we must
     still be in body stage at most */
  if ((libsmtp_session->Stage < LIBSMTP_MIMEHEADERS_STAGE) ||
      (libsmtp_session->Stage > LIBSMTP_BODY_STAGE))
  {
    libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
    return LIBSMTP_BADSTAGE;
  }

  if (libsmtp_session->Stage != LIBSMTP_BODY_STAGE)
  {
    /* If we just came from the headers stage, we have to send a blank line
     first */
    GString *libsmtp_temp_gstring = g_string_new (NULL);
    g_string_assign (libsmtp_temp_gstring, "\n");  

    if (libsmtp_int_send (libsmtp_temp_gstring, libsmtp_session, 1))
      return LIBSMTP_ERRORSENDFATAL;

    /* We now enter the body stage */
    libsmtp_session->Stage = LIBSMTP_BODY_STAGE;
  }

  /* Check to see if we already are in a part */
  if (!libsmtp_session->PartNow)
  {
    /* We are not at the moment working on one part. Lets see if any parts
       are defined at all! */
    if (!libsmtp_session->Parts)
    {
      /* nope. bad mistake! */
      libsmtp_session->ErrorCode=LIBSMTP_NOPARENT;
      return LIBSMTP_NOPARENT;
    }
    
    /* So we try to lookup the first part that might contain data */
    if (libsmtp_int_nextpart (libsmtp_session))
      return LIBSMTP_PARTSERR;
  }
  /* Ok, we are in a part */
    
  libsmtp_temp_part=libsmtp_session->PartNow;
  
  /* We pass the data on to the encoding and sending function */
  switch (libsmtp_temp_part->Encoding)
  {
    case LIBSMTP_ENC_7BIT:
      libsmtp_int_errorstate = libsmtp_int_send_body (libsmtp_body_data, libsmtp_body_length, libsmtp_session);
    break;
    
    case LIBSMTP_ENC_8BIT:
      libsmtp_int_errorstate = libsmtp_int_send_body (libsmtp_body_data, libsmtp_body_length, libsmtp_session);
    break;
    
    case LIBSMTP_ENC_BINARY:
      libsmtp_int_errorstate = libsmtp_int_send_body (libsmtp_body_data, libsmtp_body_length, libsmtp_session);
    break;
    
    case LIBSMTP_ENC_BASE64:
      libsmtp_int_errorstate = libsmtp_int_send_base64 (libsmtp_body_data, libsmtp_body_length, libsmtp_session);
    break;
  
    case LIBSMTP_ENC_QUOTED:
      libsmtp_int_errorstate = libsmtp_int_send_quoted (libsmtp_body_data, libsmtp_body_length, libsmtp_session);
    break;

    default:
      libsmtp_int_errorstate = libsmtp_int_send_body (libsmtp_body_data, libsmtp_body_length, libsmtp_session);
    break;
  }
  
  return libsmtp_int_errorstate;
}

/* This function moves on to the next body part. It can only be used in the
   appropriate stage. */

int libsmtp_part_next (struct libsmtp_session_struct *libsmtp_session)
{

/*  struct libsmtp_part_struct *libsmtp_temp_part;
  GString *libsmtp_temp_gstring; */
  int libsmtp_int_errorstate;
  
  /* Headers must have been sent before body data goes out, but we must
     still be in body stage at most */
  if ((libsmtp_session->Stage < LIBSMTP_MIMEHEADERS_STAGE) ||
      (libsmtp_session->Stage > LIBSMTP_BODY_STAGE))
  {
    libsmtp_session->ErrorCode = LIBSMTP_BADSTAGE;
    return LIBSMTP_BADSTAGE;
  }

  /* Check to see if we already are in a part */
  if (!libsmtp_session->PartNow)
  {
    /* We are not at the moment working on one part. Lets see if any parts
       are defined at all! */
    if (!libsmtp_session->Parts)
    {
      /* nope. bad mistake! */
      libsmtp_session->ErrorCode=LIBSMTP_NOPARENT;
      return LIBSMTP_NOPARENT;
    }
  }
    
  /* If we aren't in any stages, this will lookup the first stage for us.
     Otherwise it will just move on to the next stage */

  if ((libsmtp_int_errorstate = libsmtp_int_nextpart (libsmtp_session)))
    return libsmtp_int_errorstate;
    
  return LIBSMTP_NOERR;
}