home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mksmtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  44.1 KB  |  1,571 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * state machine to speak SMTP
  20.  */
  21.  
  22. /* Please leave outside of ifdef for windows precompiled headers */
  23. #include "rosetta.h"
  24. #include "mkutils.h"
  25.  
  26. #if defined(MOZILLA_CLIENT) || defined(LIBNET_SMTP)
  27. #if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)
  28.  
  29. #include "mkgeturl.h"
  30. #include "mksmtp.h"
  31. #include "mime.h"
  32. #include "glhist.h"
  33. #include "mktcp.h"
  34. #include "mkparse.h"
  35. #include "msgcom.h"
  36. #include "msgnet.h"
  37. #include "xp_time.h"
  38. #include "xp_thrmo.h"
  39. #include "merrors.h"
  40. #include "ssl.h"
  41. #include "imap.h"
  42.  
  43. #include "xp_error.h"
  44. #include "prefapi.h"
  45.  
  46. #ifdef AUTH_SKEY_DEFINED
  47. extern int btoa8(char *out, char*in);
  48. #endif
  49.  
  50. extern void NET_SetPopPassword2(const char *password);
  51.  
  52. /* for XP_GetString() */
  53. #include "xpgetstr.h"
  54. extern int XP_PROGRESS_MAILSENT;
  55. extern int MK_COULD_NOT_GET_USERS_MAIL_ADDRESS;
  56. extern int MK_COULD_NOT_LOGIN_TO_SMTP_SERVER;
  57. extern int MK_ERROR_SENDING_DATA_COMMAND;
  58. extern int MK_ERROR_SENDING_FROM_COMMAND;
  59. extern int MK_ERROR_SENDING_MESSAGE;
  60. extern int MK_ERROR_SENDING_RCPT_COMMAND;
  61. extern int MK_OUT_OF_MEMORY;
  62. extern int MK_SMTP_SERVER_ERROR;
  63. extern int MK_TCP_READ_ERROR;
  64. extern int XP_MESSAGE_SENT_WAITING_MAIL_REPLY;
  65. extern int MK_MSG_DELIV_MAIL;
  66. extern int MK_MSG_NO_SMTP_HOST;
  67. extern int MK_MIME_NO_RECIPIENTS;
  68.  
  69. extern int MK_POP3_USERNAME_UNDEFINED;
  70. extern int MK_POP3_PASSWORD_UNDEFINED;
  71. extern int XP_PASSWORD_FOR_POP3_USER;
  72. extern int XP_RETURN_RECEIPT_NOT_SUPPORT;
  73. extern int XP_SENDMAIL_BAD_TLS;
  74.  
  75. #define SMTP_PORT 25
  76.  
  77. /* definitions of state for the state machine design
  78.  */
  79. #define SMTP_RESPONSE               0
  80. #define SMTP_START_CONNECT          1
  81. #define SMTP_FINISH_CONNECT         2
  82. #define SMTP_LOGIN_RESPONSE         3
  83. #define SMTP_SEND_HELO_RESPONSE     4
  84. #define SMTP_SEND_VRFY_RESPONSE     5
  85. #define SMTP_SEND_MAIL_RESPONSE     6
  86. #define SMTP_SEND_RCPT_RESPONSE     7
  87. #define SMTP_SEND_DATA_RESPONSE        8
  88. #define SMTP_SEND_POST_DATA            9
  89. #define SMTP_SEND_MESSAGE_RESPONSE  10
  90. #define SMTP_DONE                   11
  91. #define SMTP_ERROR_DONE             12
  92. #define SMTP_FREE                   13
  93. #define SMTP_EXTN_LOGIN_RESPONSE    14
  94. #define SMTP_SEND_EHLO_RESPONSE        15
  95.  
  96. #define SMTP_SEND_AUTH_LOGIN_USERNAME 16
  97. #define SMTP_SEND_AUTH_LOGIN_PASSWORD 17
  98. #define SMTP_AUTH_LOGIN_RESPONSE      18
  99. #define SMTP_AUTH_RESPONSE            19
  100.  
  101.  
  102. HG08747
  103.  
  104. /* structure to hold data pertaining to the active state of
  105.  * a transfer in progress.
  106.  *
  107.  */
  108. typedef struct _SMTPConData {
  109.     int     next_state;                   /* the next state or action to be taken */
  110.     int     next_state_after_response;  /* the state after the response one */
  111.     Bool    pause_for_read;               /* Pause now for next read? */
  112. #ifdef XP_WIN
  113.     Bool    calling_netlib_all_the_time;
  114. #endif
  115.     char   *response_text;
  116.     int     response_code;
  117.     char   *data_buffer;
  118.     int32  data_buffer_size;
  119.     char   *address_copy;
  120.     char   *mail_to_address_ptr;
  121.     int     mail_to_addresses_left;
  122.     TCP_ConData * tcp_con_data;
  123.     int     continuation_response;
  124.     char   *hostname;
  125.     char   *verify_address;
  126.     void   *write_post_data_data;      /* a data object for the 
  127.                                         * WritePostData function
  128.                                          */
  129.     int32   total_amt_written;
  130.     uint32  total_message_size;
  131.     unsigned long last_time;
  132.     XP_Bool    ehlo_dsn_enabled;
  133.     XP_Bool auth_login_enabled;
  134. HG60917
  135. } SMTPConData;
  136.  
  137. /* macro's to simplify variable names */
  138. #define CD_NEXT_STATE                  cd->next_state
  139. #define CD_NEXT_STATE_AFTER_RESPONSE  cd->next_state_after_response
  140. #define CD_PAUSE_FOR_READ              cd->pause_for_read
  141. #define CD_RESPONSE_TXT                  cd->response_text
  142. #define CD_RESPONSE_CODE              cd->response_code
  143. #define CD_DATA_BUFFER                  cd->data_buffer
  144. #define CD_DATA_BUFFER_SIZE              cd->data_buffer_size
  145. #define CD_ADDRESS_COPY                  cd->address_copy
  146. #define CD_MAIL_TO_ADDRESS_PTR        cd->mail_to_address_ptr
  147. #define CD_MAIL_TO_ADDRESSES_LEFT     cd->mail_to_addresses_left
  148. #define CD_TCP_CON_DATA                  cd->tcp_con_data
  149. #define CD_CONTINUATION_RESPONSE      cd->continuation_response
  150. #define CD_HOSTNAME                        cd->hostname
  151. #define CD_VERIFY_ADDRESS              cd->verify_address
  152. #define CD_TOTAL_AMT_WRITTEN          cd->total_amt_written
  153. #define CD_TOTAL_MESSAGE_SIZE         cd->total_message_size
  154. #define CD_EHLO_DSN_ENABLED              cd->ehlo_dsn_enabled
  155.  
  156. #define CD_AUTH_LOGIN_ENABLED         cd->auth_login_enabled
  157. HG82493
  158.  
  159. #define CE_URL_S            cur_entry->URL_s
  160. #define CE_SOCK             cur_entry->socket
  161. #define CE_CON_SOCK         cur_entry->con_sock
  162. #define CE_STATUS           cur_entry->status
  163. #define CE_WINDOW_ID        cur_entry->window_id
  164. #define CE_BYTES_RECEIVED   cur_entry->bytes_received
  165. #define CE_FORMAT_OUT       cur_entry->format_out
  166.  
  167. PRIVATE char *net_smtp_relay_host=0;
  168. PRIVATE char *net_smtp_password=0;
  169.  
  170. /* forward decl */
  171. PRIVATE int32 net_ProcessMailto (ActiveEntry *cur_entry);
  172.  
  173. /* fix Mac warning of missing prototype */
  174. MODULE_PRIVATE char *
  175. NET_MailRelayHost(MWContext *context);
  176.  
  177. MODULE_PRIVATE char *
  178. NET_MailRelayHost(MWContext *context)
  179. {
  180.     if(net_smtp_relay_host)
  181.         return(net_smtp_relay_host);
  182.     else
  183.         return("");    /* caller now checks for empty string and returns MK_MSG_NO_SMTP_HOST */
  184. }
  185.  
  186. PUBLIC void
  187. NET_SetMailRelayHost(char * host)
  188. {
  189.     char * at = NULL;
  190.  
  191.     /*
  192.     ** If we are called with data like "fred@bedrock.com", then we will
  193.     ** help the user by ignoring the stuff before the "@".  People with
  194.     ** @ signs in their host names will be hosed.  They also can't possibly
  195.     ** be current happy internet users.
  196.     */
  197.     if (host) at = XP_STRCHR(host, '@');
  198.     if (at != NULL) host = at + 1;
  199.     StrAllocCopy(net_smtp_relay_host, host);
  200. }
  201.  
  202. /*
  203.  * gets user domian name out from FE_UsersMailAddress()
  204.  */
  205. PRIVATE const char *
  206. net_smtp_get_user_domain_name()
  207. {
  208.     const char *mail_addr, *at_sign = NULL;
  209.     mail_addr = FE_UsersMailAddress();
  210.     at_sign = XP_STRCHR(mail_addr, '@');
  211.     return (at_sign ? at_sign+1 : mail_addr);
  212. }
  213.  
  214. /* RFC 1891 -- extended smtp value encoding scheme
  215.  
  216.   5. Additional parameters for RCPT and MAIL commands
  217.  
  218.      The extended RCPT and MAIL commands are issued by a client when it wishes to request a DSN from the
  219.      server, under certain conditions, for a particular recipient. The extended RCPT and MAIL commands are
  220.      identical to the RCPT and MAIL commands defined in [1], except that one or more of the following parameters
  221.      appear after the sender or recipient address, respectively. The general syntax for extended SMTP commands is
  222.      defined in [4]. 
  223.  
  224.      NOTE: Although RFC 822 ABNF is used to describe the syntax of these parameters, they are not, in the
  225.      language of that document, "structured field bodies". Therefore, while parentheses MAY appear within an
  226.      emstp-value, they are not recognized as comment delimiters. 
  227.  
  228.      The syntax for "esmtp-value" in [4] does not allow SP, "=", control characters, or characters outside the
  229.      traditional ASCII range of 1- 127 decimal to be transmitted in an esmtp-value. Because the ENVID and
  230.      ORCPT parameters may need to convey values outside this range, the esmtp-values for these parameters are
  231.      encoded as "xtext". "xtext" is formally defined as follows: 
  232.  
  233.      xtext = *( xchar / hexchar ) 
  234.  
  235.      xchar = any ASCII CHAR between "!" (33) and "~" (126) inclusive, except for "+" and "=". 
  236.  
  237.     ; "hexchar"s are intended to encode octets that cannot appear
  238.     ; as ASCII characters within an esmtp-value.
  239.  
  240.          hexchar = ASCII "+" immediately followed by two upper case hexadecimal digits 
  241.  
  242.     When encoding an octet sequence as xtext:
  243.  
  244.     + Any ASCII CHAR between "!" and "~" inclusive, except for "+" and "=",
  245.          MAY be encoded as itself. (A CHAR in this range MAY instead be encoded as a "hexchar", at the
  246.          implementor's discretion.) 
  247.  
  248.     + ASCII CHARs that fall outside the range above must be encoded as
  249.          "hexchar". 
  250.  
  251.  */
  252. /* caller must free the return buffer */
  253. PRIVATE char *
  254. esmtp_value_encode(char *addr)
  255. {
  256.     char *buffer = XP_ALLOC(512); /* esmpt ORCPT allow up to 500 chars encoded addresses */
  257.     char *bp = buffer, *bpEnd = buffer+500;
  258.     int len, i;
  259.  
  260.     if (!buffer) return NULL;
  261.  
  262.     *bp=0;
  263.     if (! addr || *addr == 0) /* this will never happen */
  264.         return buffer;
  265.  
  266.     for (i=0, len=XP_STRLEN(addr); i < len && bp < bpEnd; i++)
  267.     {
  268.         if (*addr >= 0x21 && 
  269.             *addr <= 0x7E &&
  270.             *addr != '+' &&
  271.             *addr != '=')
  272.         {
  273.             *bp++ = *addr++;
  274.         }
  275.         else
  276.         {
  277.             PR_snprintf(bp, bpEnd-bp, "+%.2X", ((int)*addr++));
  278.             bp += XP_STRLEN(bp);
  279.         }
  280.     }
  281.     *bp=0;
  282.     return buffer;
  283. }
  284.  
  285. /*
  286.  * gets the response code from the nntp server and the
  287.  * response line
  288.  *
  289.  * returns the TCP return code from the read
  290.  */
  291. PRIVATE int
  292. net_smtp_response (ActiveEntry * cur_entry)
  293. {
  294.     char * line;
  295.     char cont_char;
  296.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  297.  
  298.     CE_STATUS = NET_BufferedReadLine(CE_SOCK, &line, &CD_DATA_BUFFER,
  299.                                             &CD_DATA_BUFFER_SIZE, &CD_PAUSE_FOR_READ);
  300.  
  301.     if(CE_STATUS == 0)
  302.       {
  303.         CD_NEXT_STATE = SMTP_ERROR_DONE;
  304.         CD_PAUSE_FOR_READ = FALSE;
  305.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_SMTP_SERVER_ERROR,
  306.                                                       CD_RESPONSE_TXT);
  307.         CE_STATUS = MK_SMTP_SERVER_ERROR;
  308.         return(MK_SMTP_SERVER_ERROR);
  309.       }
  310.  
  311.     /* if TCP error of if there is not a full line yet return
  312.      */
  313.     if(CE_STATUS < 0)
  314.       {
  315.         CE_URL_S->error_msg =
  316.           NET_ExplainErrorDetails(MK_TCP_READ_ERROR, SOCKET_ERRNO);
  317.  
  318.         /* return TCP error
  319.          */
  320.         return MK_TCP_READ_ERROR;
  321.       }
  322.     else if(!line)
  323.       {
  324.          return CE_STATUS;
  325.       }
  326.  
  327.     TRACEMSG(("SMTP Rx: %s\n", line));
  328.  
  329.     cont_char = ' '; /* default */
  330.     sscanf(line, "%d%c", &CD_RESPONSE_CODE, &cont_char);
  331.  
  332.      if(CD_CONTINUATION_RESPONSE == -1)
  333.        {
  334.          if (cont_char == '-')  /* begin continuation */
  335.              CD_CONTINUATION_RESPONSE = CD_RESPONSE_CODE;
  336.  
  337.          if(XP_STRLEN(line) > 3)
  338.              StrAllocCopy(CD_RESPONSE_TXT, line+4);
  339.        }
  340.      else
  341.        {    /* have to continue */
  342.          if (CD_CONTINUATION_RESPONSE == CD_RESPONSE_CODE && cont_char == ' ')
  343.              CD_CONTINUATION_RESPONSE = -1;    /* ended */
  344.  
  345.          StrAllocCat(CD_RESPONSE_TXT, "\n");
  346.          if(XP_STRLEN(line) > 3)
  347.              StrAllocCat(CD_RESPONSE_TXT, line+4);
  348.        }
  349.  
  350.      if(CD_CONTINUATION_RESPONSE == -1)  /* all done with this response? */
  351.        {
  352.          CD_NEXT_STATE = CD_NEXT_STATE_AFTER_RESPONSE;
  353.          CD_PAUSE_FOR_READ = FALSE; /* don't pause */
  354.        }
  355.  
  356.     return(0);  /* everything ok */
  357. }
  358.  
  359. PRIVATE int
  360. net_smtp_login_response(ActiveEntry *cur_entry)
  361. {
  362.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  363.     char buffer[356];
  364.  
  365.     if(CD_RESPONSE_CODE != 220)
  366.       {
  367.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
  368.         return(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
  369.       }
  370.  
  371.  
  372.     PR_snprintf(buffer, sizeof(buffer), "HELO %.256s" CRLF, 
  373.                 net_smtp_get_user_domain_name());
  374.      
  375.     TRACEMSG(("Tx: %s", buffer));
  376.  
  377.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  378.  
  379.     CD_NEXT_STATE = SMTP_RESPONSE;
  380.     CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_HELO_RESPONSE;
  381.     CD_PAUSE_FOR_READ = TRUE;
  382.  
  383.     return(CE_STATUS);
  384. }
  385.     
  386.  
  387. PRIVATE int
  388. net_smtp_extension_login_response(ActiveEntry *cur_entry)
  389. {
  390.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  391.     char buffer[356];
  392.  
  393.     if(CD_RESPONSE_CODE != 220)
  394.       {
  395.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
  396.         return(MK_COULD_NOT_LOGIN_TO_SMTP_SERVER);
  397.       }
  398.  
  399.     PR_snprintf(buffer, sizeof(buffer), "EHLO %.256s" CRLF, 
  400.                 net_smtp_get_user_domain_name());
  401.  
  402.     TRACEMSG(("Tx: %s", buffer));
  403.  
  404.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  405.  
  406.     CD_NEXT_STATE = SMTP_RESPONSE;
  407.     CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_EHLO_RESPONSE;
  408.     CD_PAUSE_FOR_READ = TRUE;
  409.  
  410.     return(CE_STATUS);
  411. }
  412.     
  413.  
  414. PRIVATE int
  415. net_smtp_send_helo_response(ActiveEntry *cur_entry)
  416. {
  417.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  418.     char buffer[620];
  419.     const char *mail_add = FE_UsersMailAddress();
  420.  
  421.     /* don't check for a HELO response because it can be bogus and
  422.      * we don't care
  423.      */
  424.  
  425.     if(!mail_add)
  426.       {
  427.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_COULD_NOT_GET_USERS_MAIL_ADDRESS);
  428.         return(MK_COULD_NOT_GET_USERS_MAIL_ADDRESS);
  429.       }
  430.  
  431.     if(CD_VERIFY_ADDRESS)
  432.       {
  433.         PR_snprintf(buffer, sizeof(buffer), "VRFY %.256s" CRLF, CD_VERIFY_ADDRESS);
  434.       }
  435.     else
  436.       {
  437.         /* else send the MAIL FROM: command */
  438.         char *s = MSG_MakeFullAddress (NULL, mail_add);
  439.         if (!s)
  440.           {
  441.             CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  442.             return(MK_OUT_OF_MEMORY);
  443.           }
  444.         if (CE_URL_S->msg_pane) {
  445.             if (MSG_RequestForReturnReceipt(CE_URL_S->msg_pane)) {
  446.                 if (CD_EHLO_DSN_ENABLED) {
  447.                     PR_snprintf(buffer, sizeof(buffer), 
  448.                                 "MAIL FROM:<%.256s> RET=FULL ENVID=NS40112696JT" CRLF,
  449.                                 s);
  450.                 }
  451.                 else {
  452.                     FE_Alert (CE_WINDOW_ID, XP_GetString(XP_RETURN_RECEIPT_NOT_SUPPORT));
  453.                     PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, s);
  454.                 }
  455.             }
  456.             else if (MSG_SendingMDNInProgress(CE_URL_S->msg_pane)) {
  457.                 PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, "");
  458.             }
  459.             else {
  460.                 PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, s);
  461.             }
  462.         }
  463.         else {
  464.             PR_snprintf(buffer, sizeof(buffer), "MAIL FROM:<%.256s>" CRLF, s);
  465.         }
  466.         XP_FREE (s);
  467.       }
  468.  
  469.     TRACEMSG(("Tx: %s", buffer));
  470.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  471.  
  472.     CD_NEXT_STATE = SMTP_RESPONSE;
  473.  
  474.     if(CD_VERIFY_ADDRESS)
  475.         CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_VRFY_RESPONSE;
  476.     else
  477.         CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_MAIL_RESPONSE;
  478.     CD_PAUSE_FOR_READ = TRUE;
  479.  
  480.     return(CE_STATUS);
  481. }
  482.  
  483.  
  484. PRIVATE int
  485. net_smtp_send_ehlo_response(ActiveEntry *cur_entry)
  486. {
  487.   SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  488.  
  489.   if (CD_RESPONSE_CODE != 250) {
  490.     /* EHLO not implemented */
  491.     char buffer[384];
  492.  
  493. HG85890
  494.  
  495.     PR_snprintf(buffer, sizeof(buffer), "HELO %.256s" CRLF, 
  496.                 net_smtp_get_user_domain_name());
  497.  
  498.     TRACEMSG(("Tx: %s", buffer));
  499.  
  500.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  501.  
  502.     CD_NEXT_STATE = SMTP_RESPONSE;
  503.     CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_HELO_RESPONSE;
  504.     CD_PAUSE_FOR_READ = TRUE;
  505.     return (CE_STATUS);
  506.   }
  507.   else {
  508.     char *ptr = NULL;
  509. HG09714
  510.  
  511.     ptr = strcasestr(CD_RESPONSE_TXT, "DSN");
  512.     CD_EHLO_DSN_ENABLED = (ptr && XP_TO_UPPER(*(ptr-1)) != 'X');
  513.     /* should we use auth login */
  514.     PREF_GetBoolPref("mail.auth_login", &(CD_AUTH_LOGIN_ENABLED));
  515.     if (CD_AUTH_LOGIN_ENABLED) {
  516.       /* okay user has set to use skey
  517.          let's see does the server have the capability */
  518.       CD_AUTH_LOGIN_ENABLED = (NULL != strcasestr(CD_RESPONSE_TXT, "AUTH=LOGIN"));
  519.     }
  520.  
  521.  
  522. HG90967
  523.     CD_NEXT_STATE = CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_RESPONSE;
  524.  
  525. HG59852
  526.     return (CE_STATUS);
  527.   }
  528. }
  529.  
  530.  
  531. PRIVATE int
  532. net_smtp_auth_login_response(ActiveEntry *cur_entry)
  533. {
  534.   SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  535.  
  536.   switch (CD_RESPONSE_CODE/100) {
  537.   case 2:
  538.       {
  539.           char *pop_password = (char *)NET_GetPopPassword();
  540.           CD_NEXT_STATE = SMTP_SEND_HELO_RESPONSE;
  541.           if (pop_password == NULL)
  542.             NET_SetPopPassword2(net_smtp_password);
  543. #ifdef MOZ_MAIL_NEWS
  544.           if ( IMAP_GetPassword() == NULL )
  545.               IMAP_SetPassword(net_smtp_password);
  546. #endif /* MOZ_MAIL_NEWS */
  547.           XP_FREEIF(pop_password);
  548.       }
  549.     break;
  550.   case 3:
  551.     CD_NEXT_STATE = SMTP_SEND_AUTH_LOGIN_PASSWORD;
  552.     break;
  553.   case 5:
  554.   default:
  555.       {
  556.         char* pop_username = (char *) NET_GetPopUsername();
  557.         /* NET_GetPopUsername () returns pointer to the cached
  558.          * username. It did *NOT* alloc a new string
  559.          */
  560.         XP_FREEIF(net_smtp_password);
  561.         if (FE_PromptUsernameAndPassword(cur_entry->window_id,
  562.                         NULL, &pop_username, &net_smtp_password)) {
  563.             CD_NEXT_STATE = SMTP_SEND_AUTH_LOGIN_USERNAME;
  564.             /* FE_PromptUsernameAndPassword() always alloc a new string
  565.              * for pop_username. The caller has to free it.
  566.              */
  567.             XP_FREEIF(pop_username);
  568.         }
  569.         else {
  570.             /* User hit cancel, but since the client and server both say 
  571.              * they want auth login we're just going to return an error 
  572.              * and not let the msg be sent to the server
  573.              */
  574.             CE_STATUS = MK_POP3_PASSWORD_UNDEFINED;
  575.         }
  576.       }
  577.     break;
  578.   }
  579.   
  580.   return (CE_STATUS);
  581. }
  582.  
  583. PRIVATE int
  584. net_smtp_auth_login_username(ActiveEntry *cur_entry)
  585. {
  586.   SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  587.   char buffer[512];
  588.   char *pop_username = (char *) NET_GetPopUsername();
  589.   char *base64Str = NULL;
  590.  
  591.   if (!pop_username || !*pop_username)
  592.     return (MK_POP3_USERNAME_UNDEFINED);
  593.  
  594. #ifdef MOZ_MAIL_NEWS
  595.   base64Str = NET_Base64Encode(pop_username,
  596.                                XP_STRLEN(pop_username));
  597.   if (base64Str) {
  598.     PR_snprintf(buffer, sizeof(buffer), "AUTH LOGIN %.256s" CRLF, base64Str);
  599.     TRACEMSG(("Tx: %s", buffer));
  600.  
  601.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  602.     CD_NEXT_STATE = SMTP_RESPONSE;
  603.     CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_LOGIN_RESPONSE;
  604.     CD_PAUSE_FOR_READ = TRUE;
  605.     XP_FREEIF(base64Str);
  606.     
  607.     return (CE_STATUS);
  608.   }
  609. #endif /* MOZ_MAIL_NEWS */
  610.  
  611.   return -1;
  612. }
  613.  
  614. PRIVATE int
  615. net_smtp_auth_login_password(ActiveEntry *cur_entry)
  616. {
  617.   SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  618.   char buffer[1024];
  619.  
  620.   /* use cached smtp password first
  621.    * if not then use cached pop password
  622.    * if pop password undefined 
  623.    * sync with smtp password
  624.    */
  625.   
  626.   if (!net_smtp_password || !*net_smtp_password) {
  627.       XP_FREEIF(net_smtp_password); /* in case its an empty string */
  628.       net_smtp_password = (char *) NET_GetPopPassword();
  629.   }
  630.  
  631.   if (!net_smtp_password || !*net_smtp_password) {
  632.     char *fmt = XP_GetString (XP_PASSWORD_FOR_POP3_USER);
  633.     char host[256];
  634.     int len = 256;
  635.     
  636.     XP_MEMSET(host, 0, 256);
  637.     PREF_GetCharPref("network.hosts.smtp_server", host, &len);
  638.     
  639.     PR_snprintf(buffer, sizeof (buffer), 
  640.                 fmt, NET_GetPopUsername(), host);
  641.     XP_FREEIF(net_smtp_password);
  642.     net_smtp_password = FE_PromptPassword(cur_entry->window_id, buffer);
  643.     if (!net_smtp_password)
  644.       return MK_POP3_PASSWORD_UNDEFINED;
  645.   }
  646.  
  647.   XP_ASSERT(net_smtp_password);
  648.   
  649.   if (net_smtp_password) {
  650.     char *base64Str = NULL;
  651.     
  652. #ifdef MOZ_MAIL_NEWS
  653.     base64Str = NET_Base64Encode(net_smtp_password, XP_STRLEN(net_smtp_password));
  654. #endif /* MOZ_MAIL_NEWS */
  655.  
  656.     if (base64Str) {
  657.       PR_snprintf(buffer, sizeof(buffer), "%.256s" CRLF, base64Str);
  658.       TRACEMSG(("Tx: %s", buffer));
  659.  
  660.       CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  661.       CD_NEXT_STATE = SMTP_RESPONSE;
  662.       CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_LOGIN_RESPONSE;
  663.       CD_PAUSE_FOR_READ = TRUE;
  664.       XP_FREEIF(base64Str);
  665.  
  666.       return (CE_STATUS);
  667.     }
  668.   }
  669.  
  670.   return -1;
  671. }
  672.  
  673. PRIVATE int
  674. net_smtp_send_vrfy_response(ActiveEntry *cur_entry)
  675. {
  676. #if 0
  677.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  678.     char buffer[512];
  679.  
  680.     if(CD_RESPONSE_CODE == 250 || CD_RESPONSE_CODE == 251)
  681.         return(MK_USER_VERIFIED_BY_SMTP);
  682.     else
  683.         return(MK_USER_NOT_VERIFIED_BY_SMTP);
  684. #else    
  685.     XP_ASSERT(0);
  686.     return(-1);
  687. #endif
  688. }
  689.  
  690. PRIVATE int
  691. net_smtp_send_mail_response(ActiveEntry *cur_entry)
  692. {
  693.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  694.     char buffer[1024];
  695.  
  696.     if(CD_RESPONSE_CODE != 250)
  697.       {
  698.         CE_URL_S->error_msg = 
  699.           NET_ExplainErrorDetails(MK_ERROR_SENDING_FROM_COMMAND,
  700.                                   CD_RESPONSE_TXT);
  701.         return(MK_ERROR_SENDING_FROM_COMMAND);
  702.       }
  703.  
  704.     /* Send the RCPT TO: command */
  705.     if (CD_EHLO_DSN_ENABLED &&
  706.         (CE_URL_S->msg_pane && 
  707.          MSG_RequestForReturnReceipt(CE_URL_S->msg_pane)))
  708.     {
  709.         char *encodedAddress = esmtp_value_encode(CD_MAIL_TO_ADDRESS_PTR);
  710.  
  711.         if (encodedAddress) {
  712.             PR_snprintf(buffer, sizeof(buffer), 
  713.             "RCPT TO:<%.256s> NOTIFY=SUCCESS,FAILURE ORCPT=rfc822;%.500s" CRLF, 
  714.             CD_MAIL_TO_ADDRESS_PTR, encodedAddress);
  715.             XP_FREEIF(encodedAddress);
  716.         }
  717.         else {
  718.             CE_STATUS = MK_OUT_OF_MEMORY;
  719.             return (CE_STATUS);
  720.         }
  721.     }
  722.     else
  723.     {
  724.         PR_snprintf(buffer, sizeof(buffer), "RCPT TO:<%.256s>" CRLF, CD_MAIL_TO_ADDRESS_PTR);
  725.     }
  726.     /* take the address we sent off the list (move the pointer to just
  727.        past the terminating null.) */
  728.     CD_MAIL_TO_ADDRESS_PTR += XP_STRLEN (CD_MAIL_TO_ADDRESS_PTR) + 1;
  729.     CD_MAIL_TO_ADDRESSES_LEFT--;
  730.  
  731.     TRACEMSG(("Tx: %s", buffer));
  732.     
  733.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));
  734.  
  735.     CD_NEXT_STATE = SMTP_RESPONSE;
  736.     CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_RCPT_RESPONSE;
  737.     CD_PAUSE_FOR_READ = TRUE;
  738.  
  739.     return(CE_STATUS);
  740. }
  741.  
  742. PRIVATE int
  743. net_smtp_send_rcpt_response(ActiveEntry *cur_entry)
  744. {
  745.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  746.     char buffer[16];
  747.  
  748.     if(CD_RESPONSE_CODE != 250 && CD_RESPONSE_CODE != 251)
  749.       {
  750.         CE_URL_S->error_msg =
  751.           NET_ExplainErrorDetails(MK_ERROR_SENDING_RCPT_COMMAND,
  752.                                   CD_RESPONSE_TXT);
  753.         return(MK_ERROR_SENDING_RCPT_COMMAND);
  754.       }
  755.  
  756.     if(CD_MAIL_TO_ADDRESSES_LEFT > 0)
  757.       {
  758.         /* more senders to RCPT to 
  759.          */
  760.         CD_NEXT_STATE = SMTP_SEND_MAIL_RESPONSE; 
  761.         return(0);
  762.       }
  763.  
  764.     /* else send the RCPT TO: command */
  765.     XP_STRCPY(buffer, "DATA" CRLF);
  766.  
  767.     TRACEMSG(("Tx: %s", buffer));
  768.         
  769.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, buffer, XP_STRLEN(buffer));   
  770.  
  771.     CD_NEXT_STATE = SMTP_RESPONSE;  
  772.     CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_DATA_RESPONSE; 
  773.     CD_PAUSE_FOR_READ = TRUE;   
  774.  
  775.     return(CE_STATUS);  
  776. }
  777.  
  778. PRIVATE int
  779. net_smtp_send_data_response(ActiveEntry *cur_entry)
  780. {
  781.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  782.     char * command=0;   
  783.  
  784.     if(CD_RESPONSE_CODE != 354)
  785.       {
  786.         CE_URL_S->error_msg = NET_ExplainErrorDetails(
  787.                                     MK_ERROR_SENDING_DATA_COMMAND,
  788.                                     CD_RESPONSE_TXT ? CD_RESPONSE_TXT : "");
  789.         return(MK_ERROR_SENDING_DATA_COMMAND);
  790.       }
  791.  
  792. #ifdef XP_UNIX
  793.     {
  794.       const char * FE_UsersRealMailAddress(void); /* definition */
  795.       const char *real_name = FE_UsersRealMailAddress();
  796.       char *s = (real_name ? MSG_MakeFullAddress (NULL, real_name) : 0);
  797.       if (real_name && !s)
  798.         {
  799.           CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  800.           return(MK_OUT_OF_MEMORY);
  801.         }
  802.       if(real_name)
  803.         {
  804.           char buffer[512];
  805.           PR_snprintf(buffer, sizeof(buffer), "Sender: %.256s" CRLF, real_name);
  806.           StrAllocCat(command, buffer);
  807.           if(!command)
  808.             {
  809.               CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  810.               return(MK_OUT_OF_MEMORY);
  811.             }
  812.         }
  813.     }
  814.  
  815.     TRACEMSG(("sending extra unix header: %s", command));
  816.  
  817.     CE_STATUS = (int) NET_BlockingWrite(CE_SOCK, command, XP_STRLEN(command));   
  818.     if(CE_STATUS < 0)
  819.     {
  820.         TRACEMSG(("Error sending message"));
  821.     }
  822. #endif /* XP_UNIX */
  823.  
  824.     /* set connect select since we need to select on
  825.      * writes
  826.      */
  827.     NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
  828.     NET_SetConnectSelect(CE_WINDOW_ID, CE_SOCK);
  829. #ifdef XP_WIN
  830.     cd->calling_netlib_all_the_time = TRUE;
  831.     NET_SetCallNetlibAllTheTime(CE_WINDOW_ID, "mksmtp");
  832. #endif
  833.     CE_CON_SOCK = CE_SOCK;
  834.  
  835.     FREE(command);
  836.  
  837.     CD_NEXT_STATE = SMTP_SEND_POST_DATA;
  838.     CD_PAUSE_FOR_READ = FALSE;   /* send data directly */
  839.  
  840.     NET_Progress(CE_WINDOW_ID, XP_GetString(MK_MSG_DELIV_MAIL));
  841.  
  842.     /* get the size of the message */
  843.     if(CE_URL_S->post_data_is_file)
  844.       {
  845.         XP_StatStruct stat_entry;
  846.  
  847.         if(-1 != XP_Stat(CE_URL_S->post_data,
  848.                          &stat_entry,
  849.                          xpFileToPost))
  850.             CD_TOTAL_MESSAGE_SIZE = stat_entry.st_size;
  851.       }
  852.     else
  853.       {
  854.             CD_TOTAL_MESSAGE_SIZE = CE_URL_S->post_data_size;
  855.       }
  856.  
  857.  
  858.     return(CE_STATUS);  
  859. }
  860.  
  861. PRIVATE int
  862. net_smtp_send_post_data(ActiveEntry *cur_entry)
  863. {
  864.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  865.     unsigned long curtime;
  866.  
  867.     /* returns 0 on done and negative on error
  868.      * positive if it needs to continue.
  869.      */
  870.     CE_STATUS = NET_WritePostData(CE_WINDOW_ID, CE_URL_S,
  871.                                   CE_SOCK,
  872.                                   &cd->write_post_data_data,
  873.                                   TRUE);
  874.                                   
  875.     cd->pause_for_read = TRUE;
  876.  
  877.     if(CE_STATUS == 0)
  878.       {
  879.         /* normal done
  880.          */
  881.         XP_STRCPY(cd->data_buffer, CRLF "." CRLF);
  882.         TRACEMSG(("sending %s", cd->data_buffer));
  883.         CE_STATUS = (int) NET_BlockingWrite(CE_SOCK,
  884.                                             cd->data_buffer,
  885.                                             XP_STRLEN(cd->data_buffer));
  886.  
  887.         NET_Progress(CE_WINDOW_ID,
  888.                     XP_GetString(XP_MESSAGE_SENT_WAITING_MAIL_REPLY));
  889.  
  890.         NET_ClearConnectSelect(CE_WINDOW_ID, CE_SOCK);
  891. #ifdef XP_WIN
  892.         if(cd->calling_netlib_all_the_time)
  893.         {
  894.             cd->calling_netlib_all_the_time = FALSE;
  895.             NET_ClearCallNetlibAllTheTime(CE_WINDOW_ID, "mksmtp");
  896.         }
  897. #endif
  898.         NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
  899.         CE_CON_SOCK = 0;
  900.  
  901.         CD_NEXT_STATE = SMTP_RESPONSE;
  902.         CD_NEXT_STATE_AFTER_RESPONSE = SMTP_SEND_MESSAGE_RESPONSE;
  903.         return(0);
  904.       }
  905.  
  906.     CD_TOTAL_AMT_WRITTEN += CE_STATUS;
  907.  
  908.     /* Update the thermo and the status bar.  This is done by hand, rather
  909.        than using the FE_GraphProgress* functions, because there seems to be
  910.        no way to make FE_GraphProgress shut up and not display anything more
  911.        when all the data has arrived.  At the end, we want to show the
  912.        "message sent; waiting for reply" status; FE_GraphProgress gets in
  913.        the way of that.  See bug #23414. */
  914.  
  915.     curtime = XP_TIME();
  916.     if (curtime != cd->last_time) {
  917.         FE_Progress(CE_WINDOW_ID, XP_ProgressText(CD_TOTAL_MESSAGE_SIZE,
  918.                                                   CD_TOTAL_AMT_WRITTEN,
  919.                                                   0, 0));
  920.         cd->last_time = curtime;
  921.     }
  922.  
  923.     if(CD_TOTAL_MESSAGE_SIZE)
  924.         FE_SetProgressBarPercent(CE_WINDOW_ID,
  925.                                CD_TOTAL_AMT_WRITTEN*100/CD_TOTAL_MESSAGE_SIZE);
  926.  
  927.     return(CE_STATUS);
  928. }
  929.  
  930.  
  931.  
  932. PRIVATE int
  933. net_smtp_send_message_response(ActiveEntry *cur_entry)
  934. {
  935.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  936.  
  937.     if(CD_RESPONSE_CODE != 250)
  938.       {
  939.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_ERROR_SENDING_MESSAGE,
  940.                                                       CD_RESPONSE_TXT);
  941.         return(MK_ERROR_SENDING_MESSAGE);
  942.       }
  943.  
  944.     NET_Progress(CE_WINDOW_ID, XP_GetString(XP_PROGRESS_MAILSENT));
  945.  
  946.     /* else */
  947.     CD_NEXT_STATE = SMTP_DONE;
  948.     return(MK_NO_DATA);
  949. }
  950.  
  951.  
  952. PRIVATE int32
  953. net_MailtoLoad (ActiveEntry * cur_entry)
  954. {
  955.     /* get memory for Connection Data */
  956.     SMTPConData * cd = XP_NEW(SMTPConData);
  957.     int32 pref = 0;
  958.  
  959.     cur_entry->con_data = cd;
  960.     if(!cur_entry->con_data)
  961.       {
  962.         CE_URL_S->error_msg = NET_ExplainErrorDetails(MK_OUT_OF_MEMORY);
  963.         CE_STATUS = MK_OUT_OF_MEMORY;
  964.         return (CE_STATUS);
  965.       }
  966.  
  967. /*    GH_UpdateGlobalHistory(cur_entry->URL_s); */
  968.  
  969.     /* init */
  970.     XP_MEMSET(cd, 0, sizeof(SMTPConData));
  971.  
  972.     CD_CONTINUATION_RESPONSE = -1;  /* init */
  973.   
  974.     CE_SOCK = NULL;
  975. HG61365
  976.  
  977.     /* make a copy of the address
  978.      */
  979.     if(CE_URL_S->method == URL_POST_METHOD)
  980.       {
  981.         int status=0;
  982.         char *addrs1 = 0;
  983.         char *addrs2 = 0;
  984.         CD_NEXT_STATE = SMTP_START_CONNECT;
  985.  
  986.         /* Remove duplicates from the list, to prevent people from getting
  987.            more than one copy (the SMTP host may do this too, or it may not.)
  988.            This causes the address list to be parsed twice; this probably
  989.            doesn't matter.
  990.          */
  991.         addrs1 = MSG_RemoveDuplicateAddresses (CE_URL_S->address+7, 0);
  992.  
  993.         /* Extract just the mailboxes from the full RFC822 address list.
  994.            This means that people can post to mailto: URLs which contain
  995.            full RFC822 address specs, and we will still send the right
  996.            thing in the SMTP RCPT command.
  997.          */
  998.         if (addrs1 && *addrs1)
  999.         {
  1000.             status = MSG_ParseRFC822Addresses (addrs1, 0, &addrs2);
  1001.             FREEIF (addrs1);
  1002.         }
  1003.  
  1004.         if (status < 0) return status;
  1005.  
  1006.         if (status == 0 || addrs2 == 0)
  1007.           {
  1008.             CD_NEXT_STATE = SMTP_ERROR_DONE;
  1009.             CD_PAUSE_FOR_READ = FALSE;
  1010.             CE_STATUS = MK_MIME_NO_RECIPIENTS;
  1011.             CE_URL_S->error_msg = NET_ExplainErrorDetails(CE_STATUS);
  1012.             return CE_STATUS;
  1013.           }
  1014.  
  1015.         CD_ADDRESS_COPY = addrs2;
  1016.         CD_MAIL_TO_ADDRESS_PTR = CD_ADDRESS_COPY;
  1017.         CD_MAIL_TO_ADDRESSES_LEFT = status;
  1018.         return(net_ProcessMailto(cur_entry));
  1019.       }
  1020.     else
  1021.       {
  1022.         /* parse special headers and stuff from the search data in the
  1023.            URL address.  This data is of the form
  1024.  
  1025.             mailto:TO_FIELD?FIELD1=VALUE1&FIELD2=VALUE2
  1026.  
  1027.            where TO_FIELD may be empty, VALUEn may (for now) only be
  1028.            one of "cc", "bcc", "subject", "newsgroups", "references",
  1029.            and "attachment".
  1030.  
  1031.            "to" is allowed as a field/value pair as well, for consistency.
  1032.  
  1033.            One additional parameter is allowed, which does not correspond
  1034.            to a visible field: "newshost".  This is the NNTP host (and port)
  1035.            to connect to if newsgroups are specified.  If the value of this
  1036.            field ends in "/secure", then SSL will be used.
  1037.  
  1038.            Each parameter may appear only once, but the order doesn't
  1039.            matter.  All values must be URL-encoded.
  1040.          */
  1041.         char *parms = NET_ParseURL (CE_URL_S->address, GET_SEARCH_PART);
  1042.         char *rest = parms;
  1043.         char *from = 0;                        /* internal only */
  1044.         char *reply_to = 0;                    /* internal only */
  1045.         char *to = 0;
  1046.         char *cc = 0;
  1047.         char *bcc = 0;
  1048.         char *fcc = 0;                        /* internal only */
  1049.         char *newsgroups = 0;
  1050.         char *followup_to = 0;
  1051.         char *html_part = 0;                /* internal only */
  1052.         char *organization = 0;                /* internal only */
  1053.         char *subject = 0;
  1054.         char *references = 0;
  1055.         char *attachment = 0;                /* internal only */
  1056.         char *body = 0;
  1057.         char *other_random_headers = 0;        /* unused (for now) */
  1058.         char *priority = 0;
  1059.         char *newshost = 0;                    /* internal only */
  1060.         XP_Bool encrypt_p = FALSE;
  1061.         XP_Bool sign_p = FALSE;                /* internal only */
  1062.  
  1063.         char *newspost_url = 0;
  1064.         XP_Bool force_plain_text = FALSE;
  1065.         MSG_Pane *cpane = 0;
  1066.  
  1067.         to = NET_ParseURL (CE_URL_S->address, GET_PATH_PART);
  1068.  
  1069.         if (rest && *rest == '?')
  1070.           {
  1071.              /* start past the '?' */
  1072.             rest++;
  1073.             rest = XP_STRTOK (rest, "&");
  1074.             while (rest && *rest)
  1075.               {
  1076.                 char *token = rest;
  1077.                 char *value = 0;
  1078.                 char *eq = XP_STRCHR (token, '=');
  1079.                 if (eq)
  1080.                   {
  1081.                     value = eq+1;
  1082.                     *eq = 0;
  1083.                   }
  1084.                 switch (*token)
  1085.                   {
  1086.                   case 'A': case 'a':
  1087.                     if (!strcasecomp (token, "attachment") &&
  1088.                         CE_URL_S->internal_url)
  1089.                       StrAllocCopy (attachment, value);
  1090.                     break;
  1091.                   case 'B': case 'b':
  1092.                     if (!strcasecomp (token, "bcc"))
  1093.                       {
  1094.                         if (bcc && *bcc)
  1095.                           {
  1096.                             StrAllocCat (bcc, ", ");
  1097.                             StrAllocCat (bcc, value);
  1098.                           }
  1099.                         else
  1100.                           {
  1101.                             StrAllocCopy (bcc, value);
  1102.                           }
  1103.                       }
  1104.                     else if (!strcasecomp (token, "body"))
  1105.                       {
  1106.                         if (body && *body)
  1107.                           {
  1108.                             StrAllocCat (body, "\n");
  1109.                             StrAllocCat (body, value);
  1110.                           }
  1111.                         else
  1112.                           {
  1113.                             StrAllocCopy (body, value);
  1114.                           }
  1115.                       }
  1116.                     break;
  1117.                   case 'C': case 'c':
  1118.                     if (!strcasecomp (token, "cc"))
  1119.                       {
  1120.                         if (cc && *cc)
  1121.                           {
  1122.                             StrAllocCat (cc, ", ");
  1123.                             StrAllocCat (cc, value);
  1124.                           }
  1125.                         else
  1126.                           {
  1127.                             StrAllocCopy (cc, value);
  1128.                           }
  1129.                       }
  1130.                     break;
  1131.                   case 'E': case 'e':
  1132.                     if (!strcasecomp (token, "encrypt") ||
  1133.                         !strcasecomp (token, "encrypted"))
  1134.                       encrypt_p = (!strcasecomp(value, "true") ||
  1135.                                    !strcasecomp(value, "yes"));
  1136.                     break;
  1137.                   case 'F': case 'f':
  1138.                     if (!strcasecomp (token, "followup-to"))
  1139.                       StrAllocCopy (followup_to, value);
  1140.                     else if (!strcasecomp (token, "from") &&
  1141.                              CE_URL_S->internal_url)
  1142.                       StrAllocCopy (from, value);
  1143.                     else if (!strcasecomp (token, "force-plain-text") &&
  1144.                              CE_URL_S->internal_url)
  1145.                         force_plain_text = TRUE;
  1146.                     break;
  1147.                   case 'H': case 'h':
  1148.                       if (!strcasecomp(token, "html-part") &&
  1149.                           CE_URL_S->internal_url) {
  1150.                         StrAllocCopy(html_part, value);
  1151.                       }
  1152.                   case 'N': case 'n':
  1153.                     if (!strcasecomp (token, "newsgroups"))
  1154.                       StrAllocCopy (newsgroups, value);
  1155.                     else if (!strcasecomp (token, "newshost") &&
  1156.                              CE_URL_S->internal_url)
  1157.                       StrAllocCopy (newshost, value);
  1158.                     break;
  1159.                   case 'O': case 'o':
  1160.                     if (!strcasecomp (token, "organization") &&
  1161.                         CE_URL_S->internal_url)
  1162.                       StrAllocCopy (organization, value);
  1163.                     break;
  1164.                   case 'R': case 'r':
  1165.                     if (!strcasecomp (token, "references"))
  1166.                       StrAllocCopy (references, value);
  1167.                     else if (!strcasecomp (token, "reply-to") &&
  1168.                              CE_URL_S->internal_url)
  1169.                       StrAllocCopy (reply_to, value);
  1170.                     break;
  1171.                   case 'S': case 's':
  1172.                     if(!strcasecomp (token, "subject"))
  1173.                       StrAllocCopy (subject, value);
  1174.                     else if ((!strcasecomp (token, "sign") ||
  1175.                               !strcasecomp (token, "signed")) &&
  1176.                              CE_URL_S->internal_url)
  1177.                       sign_p = (!strcasecomp(value, "true") ||
  1178.                                 !strcasecomp(value, "yes"));
  1179.                     break;
  1180.                   case 'P': case 'p':
  1181.                     if (!strcasecomp (token, "priority"))
  1182.                       StrAllocCopy (priority, value);
  1183.                     break;
  1184.                   case 'T': case 't':
  1185.                     if (!strcasecomp (token, "to"))
  1186.                       {
  1187.                         if (to && *to)
  1188.                           {
  1189.                             StrAllocCat (to, ", ");
  1190.                             StrAllocCat (to, value);
  1191.                           }
  1192.                         else
  1193.                           {
  1194.                             StrAllocCopy (to, value);
  1195.                           }
  1196.                       }
  1197.                     break;
  1198.                   }
  1199.                 if (eq)
  1200.                   *eq = '='; /* put it back */
  1201.                 rest = XP_STRTOK (0, "&");
  1202.               }
  1203.           }
  1204.  
  1205.         FREEIF (parms);
  1206.         if (to)
  1207.           NET_UnEscape (to);
  1208.         if (cc)
  1209.           NET_UnEscape (cc);
  1210.         if (subject)
  1211.           NET_UnEscape (subject);
  1212.         if (newsgroups)
  1213.           NET_UnEscape (newsgroups);
  1214.         if (references)
  1215.           NET_UnEscape (references);
  1216.         if (attachment)
  1217.           NET_UnEscape (attachment);
  1218.         if (body)
  1219.           NET_UnEscape (body);
  1220.         if (newshost)
  1221.           NET_UnEscape (newshost);
  1222.  
  1223.         if(newshost)
  1224.           {
  1225.             char *prefix = "news://";
  1226.             char *slash = XP_STRRCHR (newshost, '/');
  1227.             if (slash && !strcasecomp (slash, "/secure"))
  1228.               {
  1229.                 *slash = 0;
  1230.                 prefix = "snews://";
  1231.               }
  1232.             newspost_url = (char *) XP_ALLOC (XP_STRLEN (prefix) +
  1233.                                               XP_STRLEN (newshost) + 10);
  1234.             if (newspost_url)
  1235.               {
  1236.                 XP_STRCPY (newspost_url, prefix);
  1237.                 XP_STRCAT (newspost_url, newshost);
  1238.                 XP_STRCAT (newspost_url, "/");
  1239.               }
  1240.           }
  1241.         else
  1242.           {
  1243.             XP_Bool newsServerIsSecure = FALSE;
  1244.             PREF_GetBoolPref("news.server_is_secure", &newsServerIsSecure);
  1245.  
  1246.             if (newsServerIsSecure)
  1247.                 newspost_url = XP_STRDUP("snews:");
  1248.             else
  1249.                 newspost_url = XP_STRDUP ("news:");
  1250.           }
  1251.  
  1252.         /* Tell the message library and front end to pop up an edit window.
  1253.          */
  1254.         cpane = MSG_ComposeMessage (CE_WINDOW_ID,
  1255.                                     from, reply_to, to, cc, bcc, fcc,
  1256.                                     newsgroups, followup_to, organization,
  1257.                                     subject, references, other_random_headers,
  1258.                                     priority, attachment, newspost_url, body,
  1259.                                     encrypt_p, sign_p, force_plain_text,
  1260.                                     html_part);
  1261.  
  1262.         if (cpane && CE_URL_S->fe_data) {
  1263.             /* Tell libmsg what to do after deliver the message */
  1264.             MSG_SetPostDeliveryActionInfo (cpane, CE_URL_S->fe_data);
  1265.         }
  1266.  
  1267.         FREEIF(from);
  1268.         FREEIF(reply_to);
  1269.         FREEIF(to);
  1270.         FREEIF(cc);
  1271.         FREEIF(bcc);
  1272.         FREEIF(fcc);
  1273.         FREEIF(newsgroups);
  1274.         FREEIF(followup_to);
  1275.         FREEIF(html_part);
  1276.         FREEIF(organization);
  1277.         FREEIF(subject);
  1278.         FREEIF(references);
  1279.         FREEIF(attachment);
  1280.         FREEIF(body);
  1281.         FREEIF(other_random_headers);
  1282.         FREEIF(newshost);
  1283.         FREEIF(priority);
  1284.         FREEIF(newspost_url);
  1285.  
  1286.         CE_STATUS = MK_NO_DATA;
  1287.         XP_FREE(cd);    /* no one else is gonna do it! */
  1288.         return(-1);
  1289.       }
  1290. }
  1291.  
  1292.  
  1293.  
  1294.  
  1295. /*
  1296.     We have connected to the mail relay and the type of authorization/login required
  1297.     has been established. Before we actually send our name and password check
  1298.     and see if we should do anything else for the selected auth mode.
  1299. */
  1300.  
  1301. PRIVATE int
  1302. NET_CheckAuthResponse (ActiveEntry *cur_entry)
  1303. {
  1304.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  1305.     int err = 0;
  1306.  
  1307. HG54978
  1308.  
  1309.     if (CD_AUTH_LOGIN_ENABLED)
  1310.     {
  1311.         CD_NEXT_STATE_AFTER_RESPONSE = SMTP_AUTH_LOGIN_RESPONSE;
  1312.         CD_NEXT_STATE = SMTP_SEND_AUTH_LOGIN_USERNAME;
  1313.         return (CE_STATUS);
  1314.     }
  1315.     CD_NEXT_STATE = SMTP_SEND_HELO_RESPONSE;
  1316.     return (CE_STATUS);
  1317. }
  1318.  
  1319.  
  1320.  
  1321.  
  1322. /*
  1323.  * returns negative if the transfer is finished or error'd out
  1324.  *
  1325.  * returns zero or more if the transfer needs to be continued.
  1326.  */
  1327. PRIVATE int32
  1328. net_ProcessMailto (ActiveEntry *cur_entry)
  1329. {
  1330.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  1331.     char    *mail_relay_host;
  1332.  
  1333.     TRACEMSG(("Entering NET_ProcessSMTP"));
  1334.  
  1335.     CD_PAUSE_FOR_READ = FALSE; /* already paused; reset */
  1336.  
  1337.     while(!CD_PAUSE_FOR_READ)
  1338.       {
  1339.  
  1340.         TRACEMSG(("In NET_ProcessSMTP with state: %d", CD_NEXT_STATE));
  1341.  
  1342.         switch(CD_NEXT_STATE) {
  1343.  
  1344.         case SMTP_RESPONSE:
  1345.             net_smtp_response (cur_entry);
  1346.             break;
  1347.  
  1348.         case SMTP_START_CONNECT:
  1349.             mail_relay_host = NET_MailRelayHost(CE_WINDOW_ID);
  1350.             if (XP_STRLEN(mail_relay_host) == 0)
  1351.             {
  1352.                 CE_STATUS = MK_MSG_NO_SMTP_HOST;
  1353.                 break;
  1354.             }
  1355.             CE_STATUS = NET_BeginConnect(NET_MailRelayHost(CE_WINDOW_ID), 
  1356.                                         NULL,
  1357.                                         "SMTP",
  1358.                                         SMTP_PORT, 
  1359.                                         &CE_SOCK, 
  1360.                                         FALSE, 
  1361.                                         &CD_TCP_CON_DATA, 
  1362.                                         CE_WINDOW_ID,
  1363.                                         &CE_URL_S->error_msg,
  1364.                                          cur_entry->socks_host,
  1365.                                          cur_entry->socks_port);
  1366.             CD_PAUSE_FOR_READ = TRUE;
  1367.             if(CE_STATUS == MK_CONNECTED)
  1368.               {
  1369.                 CD_NEXT_STATE = SMTP_RESPONSE;
  1370.                 CD_NEXT_STATE_AFTER_RESPONSE = SMTP_EXTN_LOGIN_RESPONSE;
  1371.                 NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
  1372.               }
  1373.             else if(CE_STATUS > -1)
  1374.               {
  1375.                 CE_CON_SOCK = CE_SOCK;  /* set con_sock so we can select on it */
  1376.                 NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  1377.                 CD_NEXT_STATE = SMTP_FINISH_CONNECT;
  1378.               }
  1379.             break;
  1380.  
  1381.         case SMTP_FINISH_CONNECT:
  1382.             CE_STATUS = NET_FinishConnect(NET_MailRelayHost(CE_WINDOW_ID), 
  1383.                                           "SMTP", 
  1384.                                           SMTP_PORT, 
  1385.                                           &CE_SOCK, 
  1386.                                           &CD_TCP_CON_DATA, 
  1387.                                           CE_WINDOW_ID,
  1388.                                           &CE_URL_S->error_msg);
  1389.  
  1390.             CD_PAUSE_FOR_READ = TRUE;
  1391. HG18931
  1392.             if(CE_STATUS == MK_CONNECTED)
  1393.               {
  1394.                 CD_NEXT_STATE = SMTP_RESPONSE;
  1395.                 CD_NEXT_STATE_AFTER_RESPONSE = SMTP_EXTN_LOGIN_RESPONSE;
  1396.                 NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  1397.                 CE_CON_SOCK = NULL;  /* reset con_sock so we don't select on it */
  1398.                 NET_SetReadSelect(CE_WINDOW_ID, CE_SOCK);
  1399.               }
  1400.             else
  1401.               {
  1402.                 /* unregister the old CE_SOCK from the select list
  1403.                  * and register the new value in the case that it changes
  1404.                  */
  1405.                 if(CE_CON_SOCK != CE_SOCK)
  1406.                   {
  1407.                     NET_ClearConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  1408.                     CE_CON_SOCK = CE_SOCK;
  1409.                     NET_SetConnectSelect(CE_WINDOW_ID, CE_CON_SOCK);
  1410.                   }
  1411.               }
  1412.             break;
  1413.  
  1414.        case SMTP_AUTH_RESPONSE:
  1415.             CE_STATUS = NET_CheckAuthResponse(cur_entry);
  1416.             break;
  1417.  
  1418.        case SMTP_LOGIN_RESPONSE:
  1419.             CE_STATUS = net_smtp_login_response(cur_entry);
  1420.             break;
  1421.  
  1422.        case SMTP_EXTN_LOGIN_RESPONSE:
  1423.             CE_STATUS = net_smtp_extension_login_response(cur_entry);
  1424.             break;
  1425.  
  1426.        case SMTP_SEND_HELO_RESPONSE:
  1427.             CE_STATUS = net_smtp_send_helo_response(cur_entry);
  1428.             break;
  1429.  
  1430.        case SMTP_SEND_EHLO_RESPONSE:
  1431.             CE_STATUS = net_smtp_send_ehlo_response(cur_entry);
  1432.             break;
  1433.  
  1434.        case SMTP_AUTH_LOGIN_RESPONSE:
  1435.             CE_STATUS = net_smtp_auth_login_response(cur_entry);
  1436.             break;
  1437.             
  1438.        case SMTP_SEND_AUTH_LOGIN_USERNAME:
  1439.             CE_STATUS = net_smtp_auth_login_username(cur_entry);
  1440.             break;
  1441.  
  1442.        case SMTP_SEND_AUTH_LOGIN_PASSWORD:
  1443.             CE_STATUS = net_smtp_auth_login_password(cur_entry);
  1444.             break;
  1445.             
  1446.        case SMTP_SEND_VRFY_RESPONSE:
  1447.             CE_STATUS = net_smtp_send_vrfy_response(cur_entry);
  1448.             break;
  1449.             
  1450.        case SMTP_SEND_MAIL_RESPONSE:
  1451.             CE_STATUS = net_smtp_send_mail_response(cur_entry);
  1452.             break;
  1453.             
  1454.        case SMTP_SEND_RCPT_RESPONSE:
  1455.             CE_STATUS = net_smtp_send_rcpt_response(cur_entry);
  1456.             break;
  1457.             
  1458.        case SMTP_SEND_DATA_RESPONSE:
  1459.             CE_STATUS = net_smtp_send_data_response(cur_entry);
  1460.             break;
  1461.             
  1462.        case SMTP_SEND_POST_DATA:
  1463.             CE_STATUS = net_smtp_send_post_data(cur_entry);
  1464.             break;
  1465.             
  1466.        case SMTP_SEND_MESSAGE_RESPONSE:
  1467.             CE_STATUS = net_smtp_send_message_response(cur_entry);
  1468.             break;
  1469.         
  1470.         case SMTP_DONE:
  1471.             NET_BlockingWrite(CE_SOCK, "QUIT", 4);
  1472.             NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
  1473.             PR_Close(CE_SOCK);
  1474.             CD_NEXT_STATE = SMTP_FREE;
  1475.             break;
  1476.         
  1477.         case SMTP_ERROR_DONE:
  1478.             if(CE_SOCK != NULL)
  1479.               {
  1480.                 /* we only send out quit if user interrupt 
  1481.                  * else must be server error which may not be
  1482.                  * able to blocking write command
  1483.                  */
  1484.                 if (CE_STATUS == MK_INTERRUPTED)
  1485.                     NET_BlockingWrite(CE_SOCK, "QUIT", 4);
  1486.                 NET_ClearReadSelect(CE_WINDOW_ID, CE_SOCK);
  1487.                 NET_ClearConnectSelect(CE_WINDOW_ID, CE_SOCK);
  1488. #ifdef XP_WIN
  1489.                 if(cd->calling_netlib_all_the_time)
  1490.                 {
  1491.                     cd->calling_netlib_all_the_time = FALSE;
  1492.                     NET_ClearCallNetlibAllTheTime(CE_WINDOW_ID, "mksmtp");
  1493.                 }
  1494. #endif /* XP_WIN */
  1495.                 NET_ClearDNSSelect(CE_WINDOW_ID, CE_SOCK);
  1496.                 PR_Close(CE_SOCK);
  1497.               }
  1498.             CD_NEXT_STATE = SMTP_FREE;
  1499.             break;
  1500.         
  1501.         case SMTP_FREE:
  1502.             FREEIF(CD_DATA_BUFFER);
  1503.             FREEIF(CD_ADDRESS_COPY);
  1504.             FREEIF(CD_RESPONSE_TXT);
  1505.             if(CD_TCP_CON_DATA)
  1506.                 NET_FreeTCPConData(CD_TCP_CON_DATA);
  1507.             if (cd->write_post_data_data)
  1508.                 NET_free_write_post_data_object((struct WritePostDataData *) 
  1509.                                                 cd->write_post_data_data);
  1510.             FREE(cd);
  1511.  
  1512.             return(-1); /* final end */
  1513.         
  1514.         default: /* should never happen !!! */
  1515.             TRACEMSG(("SMTP: BAD STATE!"));
  1516.             CD_NEXT_STATE = SMTP_ERROR_DONE;
  1517.             break;
  1518.         }
  1519.  
  1520.         /* check for errors during load and call error 
  1521.          * state if found
  1522.          */
  1523.         if(CE_STATUS < 0 && CD_NEXT_STATE != SMTP_FREE)
  1524.           {
  1525.             CD_NEXT_STATE = SMTP_ERROR_DONE;
  1526.             /* don't exit! loop around again and do the free case */
  1527.             CD_PAUSE_FOR_READ = FALSE;
  1528.           }
  1529.       } /* while(!CD_PAUSE_FOR_READ) */
  1530.     
  1531.     return(CE_STATUS);
  1532. }
  1533.  
  1534. /* abort the connection in progress
  1535.  */
  1536. PRIVATE int32
  1537. net_InterruptMailto(ActiveEntry * cur_entry)
  1538. {
  1539.     SMTPConData * cd = (SMTPConData *)cur_entry->con_data;
  1540.  
  1541.     CD_NEXT_STATE = SMTP_ERROR_DONE;
  1542.     CE_STATUS = MK_INTERRUPTED;
  1543.  
  1544.     return(net_ProcessMailto(cur_entry));
  1545. }
  1546.  
  1547. /* Free any memory that might be used in caching etc.
  1548.  */
  1549. PRIVATE void
  1550. net_CleanupMailto(void)
  1551. {
  1552.     /* nothing so far needs freeing */
  1553.     return;
  1554. }
  1555.  
  1556. MODULE_PRIVATE void
  1557. NET_InitMailtoProtocol(void)
  1558. {
  1559.         static NET_ProtoImpl mailto_proto_impl;
  1560.  
  1561.         mailto_proto_impl.init = net_MailtoLoad;
  1562.         mailto_proto_impl.process = net_ProcessMailto;
  1563.         mailto_proto_impl.interrupt = net_InterruptMailto;
  1564.         mailto_proto_impl.cleanup = net_CleanupMailto;
  1565.  
  1566.         NET_RegisterProtocolImplementation(&mailto_proto_impl, MAILTO_TYPE_URL);
  1567. }
  1568.  
  1569. #endif /* defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE) */
  1570. #endif /* defined(MOZILLA_CLIENT) || defined(LIBNET_SMTP) */
  1571.