Source for file compose.php

Documentation is available at compose.php

  1. <?php
  2. /**
  3.  * compose.php
  4.  *
  5.  * This code sends a mail.
  6.  *
  7.  * There are 4 modes of operation:
  8.  *    - Start new mail
  9.  *    - Add an attachment
  10.  *    - Send mail
  11.  *    - Save As Draft
  12.  *
  13.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  14.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  15.  * @version $Id: compose.php,v 1.450 2006/09/29 09:02:22 stekkel Exp $
  16.  * @package squirrelmail
  17.  */
  18.  
  19. /**
  20.  * Include the SquirrelMail initialization file.
  21.  */
  22. require('../include/init.php');
  23.  
  24. /* SquirrelMail required files. */
  25. require_once(SM_PATH 'functions/imap_general.php');
  26. require_once(SM_PATH 'functions/imap_messages.php');
  27. require_once(SM_PATH 'functions/date.php');
  28. require_once(SM_PATH 'functions/mime.php');
  29. require_once(SM_PATH 'class/deliver/Deliver.class.php');
  30. require_once(SM_PATH 'functions/addressbook.php');
  31. require_once(SM_PATH 'functions/forms.php');
  32. require_once(SM_PATH 'functions/identity.php');
  33.  
  34. /* --------------------- Get globals ------------------------------------- */
  35.  
  36. /** SESSION VARS */
  37. sqgetGlobalVar('delimiter'$delimiter,     SQ_SESSION);
  38.  
  39. sqgetGlobalVar('composesession',    $composesession,    SQ_SESSION);
  40. sqgetGlobalVar('compose_messages',  $compose_messages,  SQ_SESSION);
  41. sqgetGlobalVar('delayed_errors',  $delayed_errors,  SQ_SESSION);
  42.  
  43. // Turn on delayed error handling in case we wind up redirecting below
  44. $oErrorHandler->setDelayedErrors(true);
  45.  
  46. /** SESSION/POST/GET VARS */
  47. sqgetGlobalVar('session',$session);
  48. sqgetGlobalVar('mailbox',$mailbox);
  49. if(!sqgetGlobalVar('identity',$identity)) {
  50.     $identity=0;
  51. }
  52. sqgetGlobalVar('send_to',$send_to);
  53. sqgetGlobalVar('send_to_cc',$send_to_cc);
  54. sqgetGlobalVar('send_to_bcc',$send_to_bcc);
  55. sqgetGlobalVar('subject',$subject);
  56. sqgetGlobalVar('body',$body);
  57. sqgetGlobalVar('mailprio',$mailprio);
  58. sqgetGlobalVar('request_mdn',$request_mdn);
  59. sqgetGlobalVar('request_dr',$request_dr);
  60. sqgetGlobalVar('html_addr_search',$html_addr_search);
  61. sqgetGlobalVar('mail_sent',$mail_sent);
  62. sqgetGlobalVar('passed_id',$passed_id);
  63. sqgetGlobalVar('passed_ent_id',$passed_ent_id);
  64. sqgetGlobalVar('send',$send);
  65.  
  66. sqgetGlobalVar('attach',$attach);
  67.  
  68. sqgetGlobalVar('draft',$draft);
  69. sqgetGlobalVar('draft_id',$draft_id);
  70. sqgetGlobalVar('ent_num',$ent_num);
  71. sqgetGlobalVar('saved_draft',$saved_draft);
  72. sqgetGlobalVar('delete_draft',$delete_draft);
  73. if sqgetGlobalVar('startMessage',$startMessage) ) {
  74.     $startMessage = (int)$startMessage;
  75. else {
  76.     $startMessage 1;
  77. }
  78.  
  79.  
  80. /** POST VARS */
  81. sqgetGlobalVar('sigappend',             $sigappend,                 SQ_POST);
  82. sqgetGlobalVar('from_htmladdr_search',  $from_htmladdr_search,      SQ_POST);
  83. sqgetGlobalVar('addr_search_done',      $html_addr_search_done,     SQ_POST);
  84. sqgetGlobalVar('addr_search_cancel',    $html_addr_search_cancel,   SQ_POST);
  85. sqgetGlobalVar('send_to_search',        $send_to_search,            SQ_POST);
  86. sqgetGlobalVar('do_delete',             $do_delete,                 SQ_POST);
  87. sqgetGlobalVar('delete',                $delete,                    SQ_POST);
  88. sqgetGlobalVar('restoremessages',       $restoremessages,           SQ_POST);
  89. if sqgetGlobalVar('return'$tempSQ_POST) ) {
  90.     $html_addr_search_done 'Use Addresses';
  91. }
  92.  
  93. /** GET VARS */
  94. sqgetGlobalVar('attachedmessages'$attachedmessagesSQ_GET);
  95. if sqgetGlobalVar('account'$temp,  SQ_GET) ) {
  96.     $iAccount = (int) $temp;
  97. else {
  98.     $iAccount 0;
  99. }
  100.  
  101.  
  102. /** get smaction */
  103. if !sqgetGlobalVar('smaction',$action) )
  104. {
  105.     if sqgetGlobalVar('smaction_reply',$tmp) )      $action 'reply';
  106.     if sqgetGlobalVar('smaction_reply_all',$tmp) )  $action 'reply_all';
  107.     if sqgetGlobalVar('smaction_forward',$tmp) )    $action 'forward';
  108.     if sqgetGlobalVar('smaction_attache',$tmp) )    $action 'forward_as_attachment';
  109.     if sqgetGlobalVar('smaction_draft',$tmp) )      $action 'draft';
  110.     if sqgetGlobalVar('smaction_edit_new',$tmp) )   $action 'edit_as_new';
  111. }
  112.  
  113. /* Location (For HTTP 1.1 Header("Location: ...") redirects) */
  114. $location get_location();
  115. /* Identities (fetch only once) */
  116. $idents get_identities();
  117.  
  118. /* --------------------- Specific Functions ------------------------------ */
  119.  
  120. function replyAllString($header{
  121.     global $include_self_reply_all$idents;
  122.     $excl_ar array();
  123.     /**
  124.      * 1) Remove the addresses we'll be sending the message 'to'
  125.      */
  126.     if (isset($header->replyto)) {
  127.         $excl_ar $header->getAddr_a('replyto');
  128.     }
  129.     /**
  130.      * 2) Remove our identities from the CC list (they still can be in the
  131.      * TO list) only if $include_self_reply_all is turned off
  132.      */
  133.     if (!$include_self_reply_all{
  134.         foreach($idents as $id{
  135.             $excl_ar[strtolower(trim($id['email_address']))'';
  136.         }
  137.     }
  138.  
  139.     /**
  140.      * 3) get the addresses.
  141.      */
  142.     $url_replytoall_ar $header->getAddr_a(array('to','cc')$excl_ar);
  143.  
  144.     /**
  145.      * 4) generate the string.
  146.      */
  147.     $url_replytoallcc '';
  148.     foreach$url_replytoall_ar as $email => $personal{
  149.         if ($personal{
  150.             // if personal name contains address separator then surround
  151.             // the personal name with double quotes.
  152.             if (strpos($personal,','!== false{
  153.                 $personal '"'.$personal.'"';
  154.             }
  155.             $url_replytoallcc .= "$personal <$email>";
  156.         else {
  157.             $url_replytoallcc .= ', '$email;
  158.         }
  159.     }
  160.     $url_replytoallcc substr($url_replytoallcc,2);
  161.  
  162.     return $url_replytoallcc;
  163. }
  164.  
  165. /**
  166.  * creates top line in reply citations
  167.  *
  168.  * Line style depends on user preferences.
  169.  * $orig_date argument is available only from 1.4.3 and 1.5.1 version.
  170.  * @param object $orig_from From: header object.
  171.  * @param integer $orig_date email's timestamp
  172.  * @return string reply citation
  173.  */
  174. function getReplyCitation($orig_from$orig_date{
  175.     global $reply_citation_style$reply_citation_start$reply_citation_end;
  176.  
  177.     if (!is_object($orig_from)) {
  178.         $sOrig_from '';
  179.     else {
  180.         $sOrig_from decodeHeader($orig_from->getAddress(false),false,false,true);
  181.     }
  182.  
  183.     /* First, return an empty string when no citation style selected. */
  184.     if (($reply_citation_style == ''|| ($reply_citation_style == 'none')) {
  185.         return '';
  186.     }
  187.  
  188.     /* Make sure our final value isn't an empty string. */
  189.     if ($sOrig_from == ''{
  190.         return '';
  191.     }
  192.  
  193.     /* Otherwise, try to select the desired citation style. */
  194.     switch ($reply_citation_style{
  195.     case 'author_said':
  196.         /**
  197.          * To translators: %s is for author's name
  198.          */
  199.         $full_reply_citation sprintf(_("%s wrote:"),$sOrig_from);
  200.         break;
  201.     case 'quote_who':
  202.         $start '<quote who="';
  203.         $end   '">';
  204.         $full_reply_citation $start $sOrig_from $end;
  205.         break;
  206.     case 'date_time_author':
  207.         /**
  208.          * To translators:
  209.          *  first %s is for date string, second %s is for author's name. Date uses
  210.          *  formating from "D, F j, Y g:i a" and "D, F j, Y H:i" translations.
  211.          * Example string:
  212.          *  "On Sat, December 24, 2004 23:59, Santa wrote:"
  213.          * If you have to put author's name in front of date string, check comments about
  214.          * argument swapping at http://www.php.net/sprintf
  215.          */
  216.         $full_reply_citation sprintf(_("On %s, %s wrote:")getLongDateString($orig_date)$sOrig_from);
  217.         break;
  218.     case 'user-defined':
  219.         $start $reply_citation_start .
  220.             ($reply_citation_start == '' '' ' ');
  221.         $end   $reply_citation_end;
  222.         $full_reply_citation $start $sOrig_from $end;
  223.         break;
  224.     default:
  225.         return '';
  226.     }
  227.  
  228.     /* Add line feed and return the citation string. */
  229.     return ($full_reply_citation "\n");
  230. }
  231.  
  232. /**
  233.  * Creates header fields in forwarded email body
  234.  *
  235.  * $default_charset global must be set correctly before you call this function.
  236.  * @param object $orig_header 
  237.  * @return $string 
  238.  */
  239. function getforwardHeader($orig_header{
  240.     global $editor_size$default_charset;
  241.  
  242.     // using own strlen function in order to detect correct string length
  243.     $display array_("Subject"=> sq_strlen(_("Subject"),$default_charset),
  244.             _("From")    => sq_strlen(_("From"),$default_charset),
  245.             _("Date")    => sq_strlen(_("Date"),$default_charset),
  246.             _("To")      => sq_strlen(_("To"),$default_charset),
  247.             _("Cc")      => sq_strlen(_("Cc"),$default_charset) );
  248.     $maxsize max($display);
  249.     $indent str_pad('',$maxsize+2);
  250.     foreach($display as $key => $val{
  251.         $display[$key$key .': 'str_pad(''$maxsize $val);
  252.     }
  253.     $from decodeHeader($orig_header->getAddr_s('from',"\n$indent"),false,false,true);
  254.     $from str_replace('&nbsp;',' ',$from);
  255.     $to decodeHeader($orig_header->getAddr_s('to',"\n$indent"),false,false,true);
  256.     $to str_replace('&nbsp;',' ',$to);
  257.     $subject decodeHeader($orig_header->subject,false,false,true);
  258.     $subject str_replace('&nbsp;',' ',$subject);
  259.  
  260.     // using own str_pad function in order to create correct string pad
  261.     $bodyTop =  sq_str_pad(' '._("Original Message").' ',$editor_size -2,'-',STR_PAD_BOTH,$default_charset.
  262.         "\n"$display[_("Subject")$subject "\n" .
  263.         $display[_("From")$from "\n" .
  264.         $display[_("Date")getLongDateString$orig_header->date )"\n" .
  265.         $display[_("To")$to "\n";
  266.     if ($orig_header->cc != array(&& $orig_header->cc !=''{
  267.         $cc decodeHeader($orig_header->getAddr_s('cc',"\n$indent"),false,false,true);
  268.         $cc str_replace('&nbsp;',' ',$cc);
  269.         $bodyTop .= $display[_("Cc").$cc "\n";
  270.     }
  271.     $bodyTop .= str_pad(''$editor_size -'-'.
  272.         "\n\n";
  273.     return $bodyTop;
  274. }
  275. /* ----------------------------------------------------------------------- */
  276.  
  277. /*
  278.  * If the session is expired during a post this restores the compose session
  279.  * vars.
  280.  */
  281. if (sqsession_is_registered('session_expired_post')) {
  282.     sqgetGlobalVar('session_expired_post'$session_expired_postSQ_SESSION);
  283.     /*
  284.      * extra check for username so we don't display previous post data from
  285.      * another user during this session.
  286.      */
  287.     if ($session_expired_post['username'!= $username{
  288.         unset($session_expired_post);
  289.         sqsession_unregister('session_expired_post');
  290.         session_write_close();
  291.     else {
  292.         // these are the vars that we can set from the expired composed session   
  293.                 $compo_var_list array 'send_to''send_to_cc','body','startMessage',
  294.             'passed_body','use_signature','signature','attachments','subject','newmail',
  295.             'send_to_bcc''passed_id''mailbox''from_htmladdr_search''identity',
  296.             'draft_id''delete_draft''mailprio''edit_as_new''compose_messsages',
  297.             'composesession''request_mdn''request_dr');
  298.  
  299.         foreach ($compo_var_list as $var{
  300.             if isset($session_expired_post[$var]&& !isset($$var) ) {
  301.                $$var $session_expired_post[$var];
  302.             }
  303.         }
  304.  
  305.         $compose_messages unserialize(urldecode($restoremessages));
  306.         sqsession_register($compose_messages,'compose_messages');
  307.         sqsession_register($composesession,'composesession');
  308.         if (isset($send)) {
  309.             unset($send);
  310.         }
  311.         $session_expired true;
  312.     }
  313.     unset($session_expired_post);
  314.     sqsession_unregister('session_expired_post');
  315.     if (!isset($mailbox)) {
  316.         $mailbox '';
  317.     }
  318.     if ($compose_new_win == '1'{
  319.         compose_Header($color$mailbox);
  320.     else {
  321.         $sHeaderJs (isset($sHeaderJs)) $sHeaderJs '';
  322.         if (strpos($action'reply'!== false && $reply_focus{
  323.             $sBodyTagJs 'onload="checkForm(\''.$replyfocus.'\');"';
  324.         else {
  325.             $sBodyTagJs 'onload="checkForm();"';
  326.         }
  327.         displayPageHeader($color$mailbox,$sHeaderJs,$sBodyTagJs);
  328.     }
  329.     showInputForm($sessionfalse);
  330.     exit();
  331. }
  332. if (!isset($composesession)) {
  333.     $composesession 0;
  334.     sqsession_register(0,'composesession');
  335. }
  336.  
  337. if (!isset($session|| (isset($newmessage&& $newmessage)) {
  338.     sqsession_unregister('composesession');
  339.     $session "$composesession+1;
  340.     $composesession $session;
  341.     sqsession_register($composesession,'composesession');
  342. }
  343. if (!isset($compose_messages)) {
  344.     $compose_messages array();
  345. }
  346.  
  347. if (!isset($compose_messages[$session]|| ($compose_messages[$session== NULL)) {
  348.     $composeMessage new Message();
  349.     $rfc822_header new Rfc822Header();
  350.     $composeMessage->rfc822_header $rfc822_header;
  351.     $composeMessage->reply_rfc822_header '';
  352.     $compose_messages[$session$composeMessage;
  353.  
  354.     sqsession_register($compose_messages,'compose_messages');
  355. else {
  356.     $composeMessage=$compose_messages[$session];
  357. }
  358.  
  359. if (!isset($mailbox|| $mailbox == '' || ($mailbox == 'None')) {
  360.     $mailbox 'INBOX';
  361. }
  362.  
  363. if ($draft{
  364.     /*
  365.      * Set $default_charset to correspond with the user's selection
  366.      * of language interface.
  367.      */
  368.     set_my_charset();
  369.     $composeMessage=$compose_messages[$session];
  370.     if (deliverMessage($composeMessagetrue)) {
  371.         showInputForm($session);
  372.         exit();
  373.     else {
  374.         unset($compose_messages[$session]);
  375.         $draft_message _("Draft Email Saved");
  376.         /* If this is a resumed draft, then delete the original */
  377.         if(isset($delete_draft)) {
  378.             $imap_stream sqimap_login($usernamefalse$imapServerAddress$imapPortfalse);
  379.             sqimap_mailbox_select($imap_stream$draft_folder);
  380.             // force bypass_trash=true because message should be saved when deliverMessage() returns true.
  381.             // in current implementation of sqimap_msgs_list_flag() single message id can
  382.             // be submitted as string. docs state that it should be array.
  383.                         sqimap_msgs_list_delete($imap_stream$draft_folder$delete_drafttrue);
  384.             if ($auto_expunge{
  385.                 sqimap_mailbox_expunge($imap_stream$draft_foldertrue);
  386.             }
  387.             sqimap_logout($imap_stream);
  388.         }
  389.         
  390.         $oErrorHandler->saveDelayedErrors();
  391.         session_write_close();
  392.  
  393.         if ($compose_new_win == '1'{
  394.             if !isset($pageheader_sent|| !$pageheader_sent {
  395.                 Header("Location$location/compose.php?saved_draft=yes&session=$composesession");
  396.             else {
  397.                 echo '   <br><br><div style="text-align: center;"><a href="' $location
  398.                     . '/compose.php?saved_sent=yes&amp;session=' $composesession '">'
  399.                     . _("Return"'</a></div>';
  400.             }
  401.             exit();
  402.         else {
  403.             if !isset($pageheader_sent|| !$pageheader_sent {
  404.                 Header("Location$location/right_main.php?mailbox=urlencode($draft_folder.
  405.                    "&startMessage=1&note=".urlencode($draft_message));
  406.             else {
  407.                 echo '   <br><br><div style="text-align: center;"><a href="' $location
  408.                     . '/right_main.php?mailbox=' urlencode($draft_folder)
  409.                     . '&amp;startMessage=1&amp;note=' urlencode($draft_message.'">'
  410.                     . _("Return"'</a></div>';
  411.             }
  412.             exit();
  413.         }
  414.     }
  415. }
  416.  
  417. if ($send{
  418.     if (isset($_FILES['attachfile']&&
  419.             $_FILES['attachfile']['tmp_name'&&
  420.             $_FILES['attachfile']['tmp_name'!= 'none'{
  421.         $AttachFailure saveAttachedFiles($session);
  422.     }
  423.     if (checkInput(false&& !isset($AttachFailure)) {
  424.         if ($mailbox == "All Folders"{
  425.             /* We entered compose via the search results page */
  426.             $mailbox 'INBOX'/* Send 'em to INBOX, that's safe enough */
  427.         }
  428.         $urlMailbox urlencode (trim($mailbox));
  429.         if (isset($passed_id)) {
  430.             $passed_id 0;
  431.         }
  432.         /**
  433.          * Set $default_charset to correspond with the user's selection
  434.          * of language interface.
  435.          */
  436.         set_my_charset();
  437.         /**
  438.          * This is to change all newlines to \n
  439.          * We'll change them to \r\n later (in the sendMessage function)
  440.          */
  441.         $body str_replace("\r\n""\n"$body);
  442.         $body str_replace("\r""\n"$body);
  443.  
  444.         /**
  445.          * Rewrap $body so that no line is bigger than $editor_size
  446.          */
  447.         $body explode("\n"$body);
  448.         $newBody '';
  449.         foreach ($body as $line{
  450.             if$line <> '-- ' {
  451.                 $line rtrim($line);
  452.             }
  453.             if (sq_strlen($line,$default_charset<= $editor_size 1{
  454.                 $newBody .= $line "\n";
  455.             else {
  456.                 sqWordWrap($line$editor_size,$default_charset);
  457.                 $newBody .= $line "\n";
  458.  
  459.             }
  460.  
  461.         }
  462.         $body $newBody;
  463.  
  464.         $composeMessage=$compose_messages[$session];
  465.  
  466.         $Result deliverMessage($composeMessage);
  467.  
  468. <