Project

General

Profile

Download (92.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
// $Id: smtp.module,v 1.15 2007/05/28 20:02:41 lukelast Exp $
3

    
4
/**
5
 * @file
6
 * Enables drupal to send email directly to an SMTP server using authentication.
7
 * Uses the PHPMailer class by Brent R. Matzelle.
8
 * 
9
 * Overriding mail handling in drupal requires setting the smtp_library variable with the
10
 * filename of a file containing a user_mail_wrapper() function.
11
 * This module sets the smtp_library value to point back to this file which contains the
12
 * user_mail_wrapper() function that uses the PHPMailer to send email instead of the
13
 * PHP mail() class.
14
 *
15
 * @link http://phpmailer.sourceforge.net
16
 */
17

    
18
/**
19
 * Implementation of hook_menu().
20
 */
21
function smtp_menu($may_cache) {
22
  $items = array();
23
  if ($may_cache) {
24
    $items[] = array(
25
      'path' => 'admin/settings/smtp',
26
      'title' => t('SMTP support'),
27
      'description' => t('Allows the sending of site email to an SMTP server of your choice.'),
28
      'callback' => 'drupal_get_form',
29
      'callback arguments' => 'smtp_admin_settings',
30
      'type' => MENU_NORMAL_ITEM,
31
    );
32
  }
33
  return $items;
34
}
35

    
36
/**
37
 * Settings Hook
38
 *
39
 * @return
40
 *   An array containing form items to place on the module settings page.
41
 */
42
function smtp_admin_settings() {
43
  // only administrators can access this module
44
  if (!user_access('administer site configuration')) {
45
    return message_access();
46
  }
47

    
48
  //Override the smtp_library variable.
49
  if (variable_get('smtp_on', 0)) {
50
    $smtp_path = drupal_get_filename('module', 'smtp');
51
    if ($smtp_path){
52
      variable_set('smtp_library', $smtp_path);
53
      drupal_set_message(t('SMTP.module is active.'));
54
    }
55
    else { //If drupal can't find the path to the module.
56
      drupal_set_message(t("SMTP.module error: Can't find file."), 'error');
57
    }
58
  }
59
  else { //If smtp is turned off delete the variable.
60
    variable_del('smtp_library');
61
    drupal_set_message(t('SMTP.module is INACTIVE.'));
62
  }
63
  
64
  $form['onoff'] = array('#type' => 'fieldset', '#title' => t('Install options'));
65
  $form['onoff']['smtp_on'] = array(
66
    '#type' => 'radios',
67
    '#title' => t('Turn this module On or Off'),
68
    '#default_value' => variable_get('smtp_on', 1),
69
    '#options' => array(1 => 'On', 0 => 'Off'),
70
    '#description' => t('To uninstall this module you must turn it off here first.'));
71
  
72
  $form['server'] = array('#type' => 'fieldset', '#title' => t('SMTP server settings'));
73
  $form['server']['smtp_host'] = array(
74
    '#type' => 'textfield',
75
    '#title' => t('SMTP Server'),
76
    '#default_value' => variable_get('smtp_host', ''),
77
    '#description' => t('The address of your outgoing SMTP server.'));
78
  $form['server']['smtp_hostbackup'] = array(
79
    '#type' => 'textfield',
80
    '#title' => t('SMTP Backup Server'),
81
    '#default_value' => variable_get('smtp_hostbackup', ''),
82
    '#description' => t('The address of your outgoing SMTP backup server. If the primary server can\'t be found this one will be tried. This is optional.'));
83
  $form['server']['smtp_port'] = array(
84
    '#type' => 'textfield',
85
    '#title' => t('SMTP port'),
86
    '#size' => 4,
87
    '#maxlength' => 4,
88
    '#default_value' => variable_get('smtp_port', '25'),
89
    '#description' => t('The default SMTP port is 25, if that is being blocked try 80. Gmail uses 465.'));
90
  if (function_exists('openssl_open')){ //Only display the option if openssl is installed.
91
    $form['server']['smtp_protocol'] = array(
92
      '#type' => 'select',
93
      '#title' => t('Use encrypted protocol'),
94
      '#default_value' => variable_get('smtp_protocol', 'standard'),
95
      '#options' => array('standard' => t('No'), 'ssl' => t('Use SSL'), 'tls' => t('Use TLS')),
96
      '#description' => t('This allows connection to an SMTP server that requires SSL encryption such as gmail.'));
97
  }
98
  else{ //If openssl is not installed use normal protocol.
99
    variable_set('smtp_protocol', 'standard');
100
  }
101
  
102
  $form['auth'] = array('#type' => 'fieldset', '#title' => t('SMTP Authentication'), '#description' => t('Leave blank if your SMTP server does not require authentication.'));
103
  $form['auth']['smtp_username'] = array(
104
    '#type' => 'textfield',
105
    '#title' => t('Username'),
106
    '#default_value' => variable_get('smtp_username', ''),
107
    '#description' => t('SMTP Username.'));
108
  $form['auth']['smtp_password'] = array(
109
    '#type' => 'textfield',
110
    '#title' => t('Password'),
111
    '#default_value' => variable_get('smtp_password', ''),
112
    '#description' => t('SMTP password.'));
113
    
114
  $form['email_options'] = array('#type' => 'fieldset', '#title' => t('E-mail options'));
115
  $form['email_options']['smtp_from'] = array(
116
    '#type' => 'textfield',
117
    '#title' => t('E-mail from'),
118
    '#default_value' => variable_get('smtp_from', ''),
119
    '#description' => t('The E-mail-address that all emails will be from.')
120
    );
121
  $form['email_options']['smtp_fromname'] = array(
122
    '#type' => 'textfield',
123
    '#title' => t('E-mail from Name'),
124
    '#default_value' => variable_get('smtp_fromname', ''),
125
    '#description' => t('The name that all emails will be from. If left blank will use the site name of: ') . variable_get('site_name', 'Drupal powered site'));
126
    
127
  //If an address was given, send a test email message.
128
  $test_address = variable_get('smtp_test_address', '');
129
  if ($test_address != ''){
130
    variable_del('smtp_test_address'); //Clear the variable so only one message is sent.
131
    drupal_mail('smtp-test', $test_address, t('Drupal test email'), t('If you receive this message it means your site is capable of sending email.'), variable_get('site_mail', ini_get('sendmail_from')));
132
    drupal_set_message(t('A test E-mail has been sent to @email. You may want to !check for any error messages.', array('@email' => $test_address, '!check' => l(t('check the logs'), 'admin/logs/watchdog'))));
133
  }
134

    
135
  $form['email_test'] = array('#type' => 'fieldset', '#title' => t('Send test E-mail'));
136
  $form['email_test']['smtp_test_address'] = array(
137
    '#type' => 'textfield',
138
    '#title' => t('E-mail address to send test email too'),
139
    '#default_value' => '',
140
    '#description' => t('Type in an address to have a test email sent there.'));
141
    
142
  return system_settings_form($form);
143
}
144

    
145
/**
146
 * Sends out the email.
147
 *
148
 * @param $mailkey
149
 *   A key to identify the mail sent, for altering.
150
 * @param $to
151
 *   string email address to send to.
152
 * @param $subject
153
 *   string subject of email.
154
 * @param $body
155
 *   string body of message.
156
 * @param $header
157
 *   string of header lines seperated by "\n".
158
 */
159
function drupal_mail_wrapper($mailkey, $to, $subject, $body, $from, $header) {
160
	$mail = new phpmailer(); //Create a new phpmailer object.
161
	$username = variable_get('smtp_username', '');
162
	$password = variable_get('smtp_password', '');
163
	
164
	//Set the default name emails should be from. If value is not defined in settings use site_name.
165
	if (variable_get('smtp_fromname', '') != ''){
166
    $from_name = variable_get('smtp_fromname', '');
167
	}
168
	else{
169
	  $from_name = variable_get('site_name', '');
170
	}
171
	
172
	if (variable_get('smtp_from', '') != ''){
173
	    $from = variable_get('smtp_from', '');
174
	}
175
	
176
	//Decide whether to use SMTP Authorization. Do so if username and password are given.
177
	if ($username != '' and $password != '') {
178
	  $auth = TRUE;
179
	} else {
180
	  $auth = FALSE;
181
	}
182
	
183
	
184
	//Take care of the email headers.
185
	foreach ($header as $key => $value) {
186
	  //watchdog('error', 'Key: ' . $key . ' Value: ' . $value);
187
	  if (strtolower($key) == 'from') {
188
	    if ($from == NULL or trim($from) == '') {
189
	      $from = $value; //If a from value was already given then set based on header.
190
	    }
191

    
192
	  } else if (strtolower($key) == 'content-type'){
193
        $mail->IsHTML(strtolower($value) == 'text/html');
194
        
195
	  } else if (strtolower($key) == 'reply-to'){
196
        $mail->AddReplyTo = $value;
197

    
198
	  } else if (strtolower($key) == 'return-path'){
199
	    if(trim($value) !=  '') $mail->Sender = $value;
200

    
201
	  } else if (strtolower($key) == 'content-transfer-encoding'){
202
        $mail->Encoding = $value;
203
        
204
	  } else if (strtolower($key) == 'mime-version'){
205
	    // just ommit MIME-Version it since it will be set by PHP-Mailer
206

    
207
	  } else { 
208
	    //Else the header key is not special, just add it
209
	    $mail->AddCustomHeader($key . ": " . $value); //Add header line.
210
	  }
211
	}
212
	
213
	//If no from address has been set than use a default.
214
	if ($from == NULL or trim($from) == ''){
215
     	$from = variable_get('site_mail', 'test@example.com'); //If no from can be found use site_mail variable.
216
	}
217

    
218
	//Set the correct protocol prefix to append to the smtp host.
219
	switch(variable_get('smtp_protocol', 'standard')){
220
	  case "ssl":
221
	    $mail->Protocol = 'ssl://';
222
	    break;
223
	  case "tls":
224
	    $mail->Protocol = 'tls://';
225
	    break;
226
	  case "standard":
227
	    $mail->Protocol = '';
228
	}
229
	
230
	$mail->Host = variable_get('smtp_host', '') . ';' . variable_get('smtp_hostbackup', '');
231
	$mail->Port = variable_get('smtp_port', '25');
232
	$mail->Mailer = "smtp";
233
	$mail->SMTPAuth = $auth;
234
	$mail->Username = $username;
235
	$mail->Password = $password;
236
	$mail->CharSet = 'utf-8';
237
	
238
	$mail->From = $from;
239
	$mail->FromName = $from_name;
240
	$mail->AddAddress($to);
241
	$mail->Subject = ($subject ? $subject : 'No Subject');
242
	$mail->Body = ($body ? $body : 'No Body');
243
	
244
	$mail->SMTPDebug = false; // false, true 1, 2, 3
245
	
246
	watchdog("info", "About to send email to: " . $to);
247
	
248
	if($mail->SMTPDebug){
249
		watchdog("debug", "<ul>
250
		<li>Username: $username,  Password: $password</li>
251
		<li>From:$mail->From, To: $to </li>
252
		<li>Mailer:$mail->Mailer Host: $mail->Protocol$mail->Host</li>
253
		<li>Subject: $mail->Subject</li>
254
		<li>Body: $mail->Body</li>
255
		</ul>");
256
	}
257
	
258
	//Try to send email, if it fails set watchdog entry.
259
	if(!$mail->Send()) {
260
		watchdog("error", "Error sending email: \"" . $mail->ErrorInfo . "\" From: \"$from\" To: \"$to\"");
261
		return false;
262
	}
263
	
264
	$mail->SmtpClose();
265
	return true;
266
}
267

    
268

    
269
/**
270
 * PHPMailer language settings.  
271
 * English Version
272
 * Pulled from phpmailer.lang-en.php and t() functions added for drupal translations.
273
 * This function is called in the line "$this->language = _smtp_initialize_language();" around line 794.
274
 */
275
function _smtp_initialize_language(){
276
  $PHPMAILER_LANG = array();
277
  $PHPMAILER_LANG["provide_address"] = t('You must provide at least one recipient email address.');
278
  $PHPMAILER_LANG["mailer_not_supported"] = ' ' . t('mailer is not supported.');
279
  $PHPMAILER_LANG["execute"] = t('Could not execute:') . ' ';
280
  $PHPMAILER_LANG["instantiate"] = t('Could not instantiate mail function.');
281
  $PHPMAILER_LANG["authenticate"] = t('SMTP Error: Could not authenticate.');
282
  $PHPMAILER_LANG["from_failed"] = t('The following From address failed:') . ' ';
283
  $PHPMAILER_LANG["recipients_failed"] = t('SMTP Error: The following recipients failed:') . ' ';
284
  $PHPMAILER_LANG["data_not_accepted"] = t('SMTP Error: Data not accepted.');
285
  $PHPMAILER_LANG["connect_host"] = t('SMTP Error: Could not connect to SMTP host.');
286
  $PHPMAILER_LANG["file_access"] = t('Could not access file:') . ' ';
287
  $PHPMAILER_LANG["file_open"] = t('File Error: Could not open file:') . ' ';
288
  $PHPMAILER_LANG["encoding"] = t('Unknown encoding:') . ' ';
289
  return $PHPMAILER_LANG;
290
}
291

    
292

    
293
/**************************************************************************************************
294
 * Changes to the PHPMailer class's are as follows.
295
 * Commented out line "include_once($this->PluginDir . "class.smtp.php");" from function SmtpSend().
296
 * Commented out everything in function SetLanguage() except "$this->language = $PHPMAILER_LANG; return TRUE".
297
 * Changed line "$this->language = $PHPMAILER_LANG;" to "$this->language = _smtp_initialize_language();"
298
 * Changed line "while($str = fgets($this->smtp_conn,515)) {" to "while($str = @fgets($this->smtp_conn,515)) {"
299
 * Changed line "$this->smtp_conn = fsockopen($host,    # the host of the server" to "$this->smtp_conn = fsockopen($this->protocol . $host,    # the host of the server"
300
 * Added "var $protocol = '';" to the smtp class variables.
301
 * After line "if($this->smtp == NULL) { $this->smtp = new SMTP(); }" Added "$this->smtp->protocol = $this->Protocol;"
302
 * Added "var $Protocol = '';" to the PHPMailer class variables.
303
 **************************************************************************************************/
304

    
305

    
306
////////////////////////////////////////////////////
307
// PHPMailer - PHP email class
308
//
309
// Class for sending email using either
310
// sendmail, PHP mail(), or SMTP.  Methods are
311
// based upon the standard AspEmail(tm) classes.
312
//
313
// Copyright (C) 2001 - 2003  Brent R. Matzelle
314
//
315
// License: LGPL, see LICENSE
316
////////////////////////////////////////////////////
317

    
318
/**
319
 * PHPMailer - PHP email transport class
320
 * @package PHPMailer
321
 * @author Brent R. Matzelle
322
 * @copyright 2001 - 2003 Brent R. Matzelle
323
 */
324
class PHPMailer
325
{
326
    /////////////////////////////////////////////////
327
    // PUBLIC VARIABLES
328
    /////////////////////////////////////////////////
329
    
330
    var $Protocol = ''; //Custom variable added for ssl support.
331

    
332
    /**
333
     * Email priority (1 = High, 3 = Normal, 5 = low).
334
     * @var int
335
     */
336
    var $Priority          = 3;
337

    
338
    /**
339
     * Sets the CharSet of the message.
340
     * @var string
341
     */
342
    var $CharSet           = "iso-8859-1";
343

    
344
    /**
345
     * Sets the Content-type of the message.
346
     * @var string
347
     */
348
    var $ContentType        = "text/plain";
349

    
350
    /**
351
     * Sets the Encoding of the message. Options for this are "8bit",
352
     * "7bit", "binary", "base64", and "quoted-printable".
353
     * @var string
354
     */
355
    var $Encoding          = "8bit";
356

    
357
    /**
358
     * Holds the most recent mailer error message.
359
     * @var string
360
     */
361
    var $ErrorInfo         = "";
362

    
363
    /**
364
     * Sets the From email address for the message.
365
     * @var string
366
     */
367
    var $From               = "root@localhost";
368

    
369
    /**
370
     * Sets the From name of the message.
371
     * @var string
372
     */
373
    var $FromName           = "Root User";
374

    
375
    /**
376
     * Sets the Sender email (Return-Path) of the message.  If not empty,
377
     * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
378
     * @var string
379
     */
380
    var $Sender            = "";
381

    
382
    /**
383
     * Sets the Subject of the message.
384
     * @var string
385
     */
386
    var $Subject           = "";
387

    
388
    /**
389
     * Sets the Body of the message.  This can be either an HTML or text body.
390
     * If HTML then run IsHTML(true).
391
     * @var string
392
     */
393
    var $Body               = "";
394

    
395
    /**
396
     * Sets the text-only body of the message.  This automatically sets the
397
     * email to multipart/alternative.  This body can be read by mail
398
     * clients that do not have HTML email capability such as mutt. Clients
399
     * that can read HTML will view the normal Body.
400
     * @var string
401
     */
402
    var $AltBody           = "";
403

    
404
    /**
405
     * Sets word wrapping on the body of the message to a given number of 
406
     * characters.
407
     * @var int
408
     */
409
    var $WordWrap          = 0;
410

    
411
    /**
412
     * Method to send mail: ("mail", "sendmail", or "smtp").
413
     * @var string
414
     */
415
    var $Mailer            = "mail";
416

    
417
    /**
418
     * Sets the path of the sendmail program.
419
     * @var string
420
     */
421
    var $Sendmail          = "/usr/sbin/sendmail";
422
    
423
    /**
424
     * Path to PHPMailer plugins.  This is now only useful if the SMTP class 
425
     * is in a different directory than the PHP include path.  
426
     * @var string
427
     */
428
    var $PluginDir         = "";
429

    
430
    /**
431
     *  Holds PHPMailer version.
432
     *  @var string
433
     */
434
    var $Version           = "1.73";
435

    
436
    /**
437
     * Sets the email address that a reading confirmation will be sent.
438
     * @var string
439
     */
440
    var $ConfirmReadingTo  = "";
441

    
442
    /**
443
     *  Sets the hostname to use in Message-Id and Received headers
444
     *  and as default HELO string. If empty, the value returned
445
     *  by SERVER_NAME is used or 'localhost.localdomain'.
446
     *  @var string
447
     */
448
    var $Hostname          = "";
449

    
450
    /////////////////////////////////////////////////
451
    // SMTP VARIABLES
452
    /////////////////////////////////////////////////
453

    
454
    /**
455
     *  Sets the SMTP hosts.  All hosts must be separated by a
456
     *  semicolon.  You can also specify a different port
457
     *  for each host by using this format: [hostname:port]
458
     *  (e.g. "smtp1.example.com:25;smtp2.example.com").
459
     *  Hosts will be tried in order.
460
     *  @var string
461
     */
462
    var $Host        = "localhost";
463

    
464
    /**
465
     *  Sets the default SMTP server port.
466
     *  @var int
467
     */
468
    var $Port        = 25;
469

    
470
    /**
471
     *  Sets the SMTP HELO of the message (Default is $Hostname).
472
     *  @var string
473
     */
474
    var $Helo        = "";
475

    
476
    /**
477
     *  Sets SMTP authentication. Utilizes the Username and Password variables.
478
     *  @var bool
479
     */
480
    var $SMTPAuth     = false;
481

    
482
    /**
483
     *  Sets SMTP username.
484
     *  @var string
485
     */
486
    var $Username     = "";
487

    
488
    /**
489
     *  Sets SMTP password.
490
     *  @var string
491
     */
492
    var $Password     = "";
493

    
494
    /**
495
     *  Sets the SMTP server timeout in seconds. This function will not 
496
     *  work with the win32 version.
497
     *  @var int
498
     */
499
    var $Timeout      = 10;
500

    
501
    /**
502
     *  Sets SMTP class debugging on or off.
503
     *  @var bool
504
     */
505
    var $SMTPDebug    = false;
506

    
507
    /**
508
     * Prevents the SMTP connection from being closed after each mail 
509
     * sending.  If this is set to true then to close the connection 
510
     * requires an explicit call to SmtpClose(). 
511
     * @var bool
512
     */
513
    var $SMTPKeepAlive = false;
514

    
515
    /**#@+
516
     * @access private
517
     */
518
    var $smtp            = NULL;
519
    var $to              = array();
520
    var $cc              = array();
521
    var $bcc             = array();
522
    var $ReplyTo         = array();
523
    var $attachment      = array();
524
    var $CustomHeader    = array();
525
    var $message_type    = "";
526
    var $boundary        = array();
527
    var $language        = array();
528
    var $error_count     = 0;
529
    var $LE              = "\n";
530
    /**#@-*/
531
    
532
    /////////////////////////////////////////////////
533
    // VARIABLE METHODS
534
    /////////////////////////////////////////////////
535

    
536
    /**
537
     * Sets message type to HTML.  
538
     * @param bool $bool
539
     * @return void
540
     */
541
    function IsHTML($bool) {
542
        if($bool == true)
543
            $this->ContentType = "text/html";
544
        else
545
            $this->ContentType = "text/plain";
546
    }
547

    
548
    /**
549
     * Sets Mailer to send message using SMTP.
550
     * @return void
551
     */
552
    function IsSMTP() {
553
        $this->Mailer = "smtp";
554
    }
555

    
556
    /**
557
     * Sets Mailer to send message using PHP mail() function.
558
     * @return void
559
     */
560
    function IsMail() {
561
        $this->Mailer = "mail";
562
    }
563

    
564
    /**
565
     * Sets Mailer to send message using the $Sendmail program.
566
     * @return void
567
     */
568
    function IsSendmail() {
569
        $this->Mailer = "sendmail";
570
    }
571

    
572
    /**
573
     * Sets Mailer to send message using the qmail MTA. 
574
     * @return void
575
     */
576
    function IsQmail() {
577
        $this->Sendmail = "/var/qmail/bin/sendmail";
578
        $this->Mailer = "sendmail";
579
    }
580

    
581

    
582
    /////////////////////////////////////////////////
583
    // RECIPIENT METHODS
584
    /////////////////////////////////////////////////
585

    
586
    /**
587
     * Adds a "To" address.  
588
     * @param string $address
589
     * @param string $name
590
     * @return void
591
     */
592
    function AddAddress($address, $name = "") {
593
        $cur = count($this->to);
594
        $this->to[$cur][0] = trim($address);
595
        $this->to[$cur][1] = $name;
596
    }
597

    
598
    /**
599
     * Adds a "Cc" address. Note: this function works
600
     * with the SMTP mailer on win32, not with the "mail"
601
     * mailer.  
602
     * @param string $address
603
     * @param string $name
604
     * @return void
605
    */
606
    function AddCC($address, $name = "") {
607
        $cur = count($this->cc);
608
        $this->cc[$cur][0] = trim($address);
609
        $this->cc[$cur][1] = $name;
610
    }
611

    
612
    /**
613
     * Adds a "Bcc" address. Note: this function works
614
     * with the SMTP mailer on win32, not with the "mail"
615
     * mailer.  
616
     * @param string $address
617
     * @param string $name
618
     * @return void
619
     */
620
    function AddBCC($address, $name = "") {
621
        $cur = count($this->bcc);
622
        $this->bcc[$cur][0] = trim($address);
623
        $this->bcc[$cur][1] = $name;
624
    }
625

    
626
    /**
627
     * Adds a "Reply-to" address.  
628
     * @param string $address
629
     * @param string $name
630
     * @return void
631
     */
632
    function AddReplyTo($address, $name = "") {
633
        $cur = count($this->ReplyTo);
634
        $this->ReplyTo[$cur][0] = trim($address);
635
        $this->ReplyTo[$cur][1] = $name;
636
    }
637

    
638

    
639
    /////////////////////////////////////////////////
640
    // MAIL SENDING METHODS
641
    /////////////////////////////////////////////////
642

    
643
    /**
644
     * Creates message and assigns Mailer. If the message is
645
     * not sent successfully then it returns false.  Use the ErrorInfo
646
     * variable to view description of the error.  
647
     * @return bool
648
     */
649
    function Send() {
650
        $header = "";
651
        $body = "";
652
        $result = true;
653

    
654
        if((count($this->to) + count($this->cc) + count($this->bcc)) < 1)
655
        {
656
            $this->SetError($this->Lang("provide_address"));
657
            return false;
658
        }
659

    
660
        // Set whether the message is multipart/alternative
661
        if(!empty($this->AltBody))
662
            $this->ContentType = "multipart/alternative";
663

    
664
        $this->error_count = 0; // reset errors
665
        $this->SetMessageType();
666
        $header .= $this->CreateHeader();
667
        $body = $this->CreateBody();
668

    
669
        if($body == "") { return false; }
670

    
671
        // Choose the mailer
672
        switch($this->Mailer)
673
        {
674
            case "sendmail":
675
                $result = $this->SendmailSend($header, $body);
676
                break;
677
            case "mail":
678
                $result = $this->MailSend($header, $body);
679
                break;
680
            case "smtp":
681
                $result = $this->SmtpSend($header, $body);
682
                break;
683
            default:
684
            $this->SetError($this->Mailer . $this->Lang("mailer_not_supported"));
685
                $result = false;
686
                break;
687
        }
688

    
689
        return $result;
690
    }
691
    
692
    /**
693
     * Sends mail using the $Sendmail program.  
694
     * @access private
695
     * @return bool
696
     */
697
    function SendmailSend($header, $body) {
698
        if ($this->Sender != "")
699
            $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, $this->Sender);
700
        else
701
            $sendmail = sprintf("%s -oi -t", $this->Sendmail);
702

    
703
        if(!@$mail = popen($sendmail, "w"))
704
        {
705
            $this->SetError($this->Lang("execute") . $this->Sendmail);
706
            return false;
707
        }
708

    
709
        fputs($mail, $header);
710
        fputs($mail, $body);
711
        
712
        $result = pclose($mail) >> 8 & 0xFF;
713
        if($result != 0)
714
        {
715
            $this->SetError($this->Lang("execute") . $this->Sendmail);
716
            return false;
717
        }
718

    
719
        return true;
720
    }
721

    
722
    /**
723
     * Sends mail using the PHP mail() function.  
724
     * @access private
725
     * @return bool
726
     */
727
    function MailSend($header, $body) {
728
        $to = "";
729
        for($i = 0; $i < count($this->to); $i++)
730
        {
731
            if($i != 0) { $to .= ", "; }
732
            $to .= $this->to[$i][0];
733
        }
734

    
735
        if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1)
736
        {
737
            $old_from = ini_get("sendmail_from");
738
            ini_set("sendmail_from", $this->Sender);
739
            $params = sprintf("-oi -f %s", $this->Sender);
740
            $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, 
741
                        $header, $params);
742
        }
743
        else
744
            $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header);
745

    
746
        if (isset($old_from))
747
            ini_set("sendmail_from", $old_from);
748

    
749
        if(!$rt)
750
        {
751
            $this->SetError($this->Lang("instantiate"));
752
            return false;
753
        }
754

    
755
        return true;
756
    }
757

    
758
    /**
759
     * Sends mail via SMTP using PhpSMTP (Author:
760
     * Chris Ryan).  Returns bool.  Returns false if there is a
761
     * bad MAIL FROM, RCPT, or DATA input.
762
     * @access private
763
     * @return bool
764
     */
765
    function SmtpSend($header, $body) {
766
        //include_once($this->PluginDir . "class.smtp.php");
767
        $error = "";
768
        $bad_rcpt = array();
769

    
770
        if(!$this->SmtpConnect())
771
            return false;
772

    
773
        $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender;
774
        if(!$this->smtp->Mail($smtp_from))
775
        {
776
            $error = $this->Lang("from_failed") . $smtp_from;
777
            $this->SetError($error);
778
            $this->smtp->Reset();
779
            return false;
780
        }
781

    
782
        // Attempt to send attach all recipients
783
        for($i = 0; $i < count($this->to); $i++)
784
        {
785
            if(!$this->smtp->Recipient($this->to[$i][0]))
786
                $bad_rcpt[] = $this->to[$i][0];
787
        }
788
        for($i = 0; $i < count($this->cc); $i++)
789
        {
790
            if(!$this->smtp->Recipient($this->cc[$i][0]))
791
                $bad_rcpt[] = $this->cc[$i][0];
792
        }
793
        for($i = 0; $i < count($this->bcc); $i++)
794
        {
795
            if(!$this->smtp->Recipient($this->bcc[$i][0]))
796
                $bad_rcpt[] = $this->bcc[$i][0];
797
        }
798

    
799
        if(count($bad_rcpt) > 0) // Create error message
800
        {
801
            for($i = 0; $i < count($bad_rcpt); $i++)
802
            {
803
                if($i != 0) { $error .= ", "; }
804
                $error .= $bad_rcpt[$i];
805
            }
806
            $error = $this->Lang("recipients_failed") . $error;
807
            $this->SetError($error);
808
            $this->smtp->Reset();
809
            return false;
810
        }
811

    
812
        if(!$this->smtp->Data($header . $body))
813
        {
814
            $this->SetError($this->Lang("data_not_accepted"));
815
            $this->smtp->Reset();
816
            return false;
817
        }
818
        if($this->SMTPKeepAlive == true)
819
            $this->smtp->Reset();
820
        else
821
            $this->SmtpClose();
822

    
823
        return true;
824
    }
825

    
826
    /**
827
     * Initiates a connection to an SMTP server.  Returns false if the 
828
     * operation failed.
829
     * @access private
830
     * @return bool
831
     */
832
    function SmtpConnect() {
833
        if($this->smtp == NULL) { $this->smtp = new SMTP(); }
834
        
835
        $this->smtp->protocol = $this->Protocol; //Custom line added for ssl support.
836

    
837
        $this->smtp->do_debug = $this->SMTPDebug;
838
        $hosts = explode(";", $this->Host);
839
        $index = 0;
840
        $connection = ($this->smtp->Connected()); 
841

    
842
        // Retry while there is no connection
843
        while($index < count($hosts) && $connection == false)
844
        {
845
            if(strstr($hosts[$index], ":"))
846
                list($host, $port) = explode(":", $hosts[$index]);
847
            else
848
            {
849
                $host = $hosts[$index];
850
                $port = $this->Port;
851
            }
852

    
853
            if($this->smtp->Connect($host, $port, $this->Timeout))
854
            {
855
                if ($this->Helo != '')
856
                    $this->smtp->Hello($this->Helo);
857
                else
858
                    $this->smtp->Hello($this->ServerHostname());
859
        
860
                if($this->SMTPAuth)
861
                {
862
                    if(!$this->smtp->Authenticate($this->Username, 
863
                                                  $this->Password))
864
                    {
865
                        $this->SetError($this->Lang("authenticate"));
866
                        $this->smtp->Reset();
867
                        $connection = false;
868
                    }
869
                }
870
                $connection = true;
871
            }
872
            $index++;
873
        }
874
        if(!$connection)
875
            $this->SetError($this->Lang("connect_host"));
876

    
877
        return $connection;
878
    }
879

    
880
    /**
881
     * Closes the active SMTP session if one exists.
882
     * @return void
883
     */
884
    function SmtpClose() {
885
        if($this->smtp != NULL)
886
        {
887
            if($this->smtp->Connected())
888
            {
889
                $this->smtp->Quit();
890
                $this->smtp->Close();
891
            }
892
        }
893
    }
894

    
895
    /**
896
     * Sets the language for all class error messages.  Returns false 
897
     * if it cannot load the language file.  The default language type
898
     * is English.
899
     * @param string $lang_type Type of language (e.g. Portuguese: "br")
900
     * @param string $lang_path Path to the language file directory
901
     * @access public
902
     * @return bool
903
     */
904
    function SetLanguage($lang_type, $lang_path = "language/") {
905
      /*
906
        if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php'))
907
            include($lang_path.'phpmailer.lang-'.$lang_type.'.php');
908
        else if(file_exists($lang_path.'phpmailer.lang-en.php'))
909
            include($lang_path.'phpmailer.lang-en.php');
910
        else
911
        {
912
            $this->SetError("Could not load language file");
913
            return false;
914
        }*/
915
        $this->language = _smtp_initialize_language();
916

    
917
        return true;
918
    }
919

    
920
    /////////////////////////////////////////////////
921
    // MESSAGE CREATION METHODS
922
    /////////////////////////////////////////////////
923

    
924
    /**
925
     * Creates recipient headers.  
926
     * @access private
927
     * @return string
928
     */
929
    function AddrAppend($type, $addr) {
930
        $addr_str = $type . ": ";
931
        $addr_str .= $this->AddrFormat($addr[0]);
932
        if(count($addr) > 1)
933
        {
934
            for($i = 1; $i < count($addr); $i++)
935
                $addr_str .= ", " . $this->AddrFormat($addr[$i]);
936
        }
937
        $addr_str .= $this->LE;
938

    
939
        return $addr_str;
940
    }
941
    
942
    /**
943
     * Formats an address correctly. 
944
     * @access private
945
     * @return string
946
     */
947
    function AddrFormat($addr) {
948
        if(empty($addr[1]))
949
            $formatted = $addr[0];
950
        else
951
        {
952
            $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" . 
953
                         $addr[0] . ">";
954
        }
955

    
956
        return $formatted;
957
    }
958

    
959
    /**
960
     * Wraps message for use with mailers that do not
961
     * automatically perform wrapping and for quoted-printable.
962
     * Original written by philippe.  
963
     * @access private
964
     * @return string
965
     */
966
    function WrapText($message, $length, $qp_mode = false) {
967
        $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
968

    
969
        $message = $this->FixEOL($message);
970
        if (substr($message, -1) == $this->LE)
971
            $message = substr($message, 0, -1);
972

    
973
        $line = explode($this->LE, $message);
974
        $message = "";
975
        for ($i=0 ;$i < count($line); $i++)
976
        {
977
          $line_part = explode(" ", $line[$i]);
978
          $buf = "";
979
          for ($e = 0; $e<count($line_part); $e++)
980
          {
981
              $word = $line_part[$e];
982
              if ($qp_mode and (strlen($word) > $length))
983
              {
984
                $space_left = $length - strlen($buf) - 1;
985
                if ($e != 0)
986
                {
987
                    if ($space_left > 20)
988
                    {
989
                        $len = $space_left;
990
                        if (substr($word, $len - 1, 1) == "=")
991
                          $len--;
992
                        elseif (substr($word, $len - 2, 1) == "=")
993
                          $len -= 2;
994
                        $part = substr($word, 0, $len);
995
                        $word = substr($word, $len);
996
                        $buf .= " " . $part;
997
                        $message .= $buf . sprintf("=%s", $this->LE);
998
                    }
999
                    else
1000
                    {
1001
                        $message .= $buf . $soft_break;
1002
                    }
1003
                    $buf = "";
1004
                }
1005
                while (strlen($word) > 0)
1006
                {
1007
                    $len = $length;
1008
                    if (substr($word, $len - 1, 1) == "=")
1009
                        $len--;
1010
                    elseif (substr($word, $len - 2, 1) == "=")
1011
                        $len -= 2;
1012
                    $part = substr($word, 0, $len);
1013
                    $word = substr($word, $len);
1014

    
1015
                    if (strlen($word) > 0)
1016
                        $message .= $part . sprintf("=%s", $this->LE);
1017
                    else
1018
                        $buf = $part;
1019
                }
1020
              }
1021
              else
1022
              {
1023
                $buf_o = $buf;
1024
                $buf .= ($e == 0) ? $word : (" " . $word); 
1025

    
1026
                if (strlen($buf) > $length and $buf_o != "")
1027
                {
1028
                    $message .= $buf_o . $soft_break;
1029
                    $buf = $word;
1030
                }
1031
              }
1032
          }
1033
          $message .= $buf . $this->LE;
1034
        }
1035

    
1036
        return $message;
1037
    }
1038
    
1039
    /**
1040
     * Set the body wrapping.
1041
     * @access private
1042
     * @return void
1043
     */
1044
    function SetWordWrap() {
1045
        if($this->WordWrap < 1)
1046
            return;
1047
            
1048
        switch($this->message_type)
1049
        {
1050
           case "alt":
1051
              // fall through
1052
           case "alt_attachments":
1053
              $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
1054
              break;
1055
           default:
1056
              $this->Body = $this->WrapText($this->Body, $this->WordWrap);
1057
              break;
1058
        }
1059
    }
1060

    
1061
    /**
1062
     * Assembles message header.  
1063
     * @access private
1064
     * @return string
1065
     */
1066
    function CreateHeader() {
1067
        $result = "";
1068
        
1069
        // Set the boundaries
1070
        $uniq_id = md5(uniqid(time()));
1071
        $this->boundary[1] = "b1_" . $uniq_id;
1072
        $this->boundary[2] = "b2_" . $uniq_id;
1073

    
1074
        $result .= $this->HeaderLine("Date", $this->RFCDate());
1075
        if($this->Sender == "")
1076
            $result .= $this->HeaderLine("Return-Path", trim($this->From));
1077
        else
1078
            $result .= $this->HeaderLine("Return-Path", trim($this->Sender));
1079
        
1080
        // To be created automatically by mail()
1081
        if($this->Mailer != "mail")
1082
        {
1083
            if(count($this->to) > 0)
1084
                $result .= $this->AddrAppend("To", $this->to);
1085
            else if (count($this->cc) == 0)
1086
                $result .= $this->HeaderLine("To", "undisclosed-recipients:;");
1087
            if(count($this->cc) > 0)
1088
                $result .= $this->AddrAppend("Cc", $this->cc);
1089
        }
1090

    
1091
        $from = array();
1092
        $from[0][0] = trim($this->From);
1093
        $from[0][1] = $this->FromName;
1094
        $result .= $this->AddrAppend("From", $from); 
1095

    
1096
        // sendmail and mail() extract Bcc from the header before sending
1097
        if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0))
1098
            $result .= $this->AddrAppend("Bcc", $this->bcc);
1099

    
1100
        if(count($this->ReplyTo) > 0)
1101
            $result .= $this->AddrAppend("Reply-to", $this->ReplyTo);
1102

    
1103
        // mail() sets the subject itself
1104
        if($this->Mailer != "mail")
1105
            $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject)));
1106

    
1107
        $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
1108
        $result .= $this->HeaderLine("X-Priority", $this->Priority);
1109
        $result .= $this->HeaderLine("X-Mailer", "PHPMailer [version " . $this->Version . "]");
1110
        
1111
        if($this->ConfirmReadingTo != "")
1112
        {
1113
            $result .= $this->HeaderLine("Disposition-Notification-To", 
1114
                       "<" . trim($this->ConfirmReadingTo) . ">");
1115
        }
1116

    
1117
        // Add custom headers
1118
        for($index = 0; $index < count($this->CustomHeader); $index++)
1119
        {
1120
            $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), 
1121
                       $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
1122
        }
1123
        $result .= $this->HeaderLine("MIME-Version", "1.0");
1124

    
1125
        switch($this->message_type)
1126
        {
1127
            case "plain":
1128
                $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding);
1129
                $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
1130
                break;
1131
            case "attachments":
1132
                // fall through
1133
            case "alt_attachments":
1134
                if($this->InlineImageExists())
1135
                {
1136
                    $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 
1137
                                    "multipart/related", $this->LE, $this->LE, 
1138
                                    $this->boundary[1], $this->LE);
1139
                }
1140
                else
1141
                {
1142
                    $result .= $this->HeaderLine("Content-Type", "multipart/mixed;");
1143
                    $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1144
                }
1145
                break;
1146
            case "alt":
1147
                $result .= $this->HeaderLine("Content-Type", "multipart/alternative;");
1148
                $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1149
                break;
1150
        }
1151

    
1152
        if($this->Mailer != "mail")
1153
            $result .= $this->LE.$this->LE;
1154

    
1155
        return $result;
1156
    }
1157

    
1158
    /**
1159
     * Assembles the message body.  Returns an empty string on failure.
1160
     * @access private
1161
     * @return string
1162
     */
1163
    function CreateBody() {
1164
        $result = "";
1165

    
1166
        $this->SetWordWrap();
1167

    
1168
        switch($this->message_type)
1169
        {
1170
            case "alt":
1171
                $result .= $this->GetBoundary($this->boundary[1], "", 
1172
                                              "text/plain", "");
1173
                $result .= $this->EncodeString($this->AltBody, $this->Encoding);
1174
                $result .= $this->LE.$this->LE;
1175
                $result .= $this->GetBoundary($this->boundary[1], "", 
1176
                                              "text/html", "");
1177
                
1178
                $result .= $this->EncodeString($this->Body, $this->Encoding);
1179
                $result .= $this->LE.$this->LE;
1180
    
1181
                $result .= $this->EndBoundary($this->boundary[1]);
1182
                break;
1183
            case "plain":
1184
                $result .= $this->EncodeString($this->Body, $this->Encoding);
1185
                break;
1186
            case "attachments":
1187
                $result .= $this->GetBoundary($this->boundary[1], "", "", "");
1188
                $result .= $this->EncodeString($this->Body, $this->Encoding);
1189
                $result .= $this->LE;
1190
     
1191
                $result .= $this->AttachAll();
1192
                break;
1193
            case "alt_attachments":
1194
                $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1195
                $result .= sprintf("Content-Type: %s;%s" .
1196
                                   "\tboundary=\"%s\"%s",
1197
                                   "multipart/alternative", $this->LE, 
1198
                                   $this->boundary[2], $this->LE.$this->LE);
1199
    
1200
                // Create text body
1201
                $result .= $this->GetBoundary($this->boundary[2], "", 
1202
                                              "text/plain", "") . $this->LE;
1203

    
1204
                $result .= $this->EncodeString($this->AltBody, $this->Encoding);
1205
                $result .= $this->LE.$this->LE;
1206
    
1207
                // Create the HTML body
1208
                $result .= $this->GetBoundary($this->boundary[2], "", 
1209
                                              "text/html", "") . $this->LE;
1210
    
1211
                $result .= $this->EncodeString($this->Body, $this->Encoding);
1212
                $result .= $this->LE.$this->LE;
1213

    
1214
                $result .= $this->EndBoundary($this->boundary[2]);
1215
                
1216
                $result .= $this->AttachAll();
1217
                break;
1218
        }
1219
        if($this->IsError())
1220
            $result = "";
1221

    
1222
        return $result;
1223
    }
1224

    
1225
    /**
1226
     * Returns the start of a message boundary.
1227
     * @access private
1228
     */
1229
    function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1230
        $result = "";
1231
        if($charSet == "") { $charSet = $this->CharSet; }
1232
        if($contentType == "") { $contentType = $this->ContentType; }
1233
        if($encoding == "") { $encoding = $this->Encoding; }
1234

    
1235
        $result .= $this->TextLine("--" . $boundary);
1236
        $result .= sprintf("Content-Type: %s; charset = \"%s\"", 
1237
                            $contentType, $charSet);
1238
        $result .= $this->LE;
1239
        $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding);
1240
        $result .= $this->LE;
1241
       
1242
        return $result;
1243
    }
1244
    
1245
    /**
1246
     * Returns the end of a message boundary.
1247
     * @access private
1248
     */
1249
    function EndBoundary($boundary) {
1250
        return $this->LE . "--" . $boundary . "--" . $this->LE; 
1251
    }
1252
    
1253
    /**
1254
     * Sets the message type.
1255
     * @access private
1256
     * @return void
1257
     */
1258
    function SetMessageType() {
1259
        if(count($this->attachment) < 1 && strlen($this->AltBody) < 1)
1260
            $this->message_type = "plain";
1261
        else
1262
        {
1263
            if(count($this->attachment) > 0)
1264
                $this->message_type = "attachments";
1265
            if(strlen($this->AltBody) > 0 && count($this->attachment) < 1)
1266
                $this->message_type = "alt";
1267
            if(strlen($this->AltBody) > 0 && count($this->attachment) > 0)
1268
                $this->message_type = "alt_attachments";
1269
        }
1270
    }
1271

    
1272
    /**
1273
     * Returns a formatted header line.
1274
     * @access private
1275
     * @return string
1276
     */
1277
    function HeaderLine($name, $value) {
1278
        return $name . ": " . $value . $this->LE;
1279
    }
1280

    
1281
    /**
1282
     * Returns a formatted mail line.
1283
     * @access private
1284
     * @return string
1285
     */
1286
    function TextLine($value) {
1287
        return $value . $this->LE;
1288
    }
1289

    
1290
    /////////////////////////////////////////////////
1291
    // ATTACHMENT METHODS
1292
    /////////////////////////////////////////////////
1293

    
1294
    /**
1295
     * Adds an attachment from a path on the filesystem.
1296
     * Returns false if the file could not be found
1297
     * or accessed.
1298
     * @param string $path Path to the attachment.
1299
     * @param string $name Overrides the attachment name.
1300
     * @param string $encoding File encoding (see $Encoding).
1301
     * @param string $type File extension (MIME) type.
1302
     * @return bool
1303
     */
1304
    function AddAttachment($path, $name = "", $encoding = "base64", 
1305
                           $type = "application/octet-stream") {
1306
        if(!@is_file($path))
1307
        {
1308
            $this->SetError($this->Lang("file_access") . $path);
1309
            return false;
1310
        }
1311

    
1312
        $filename = basename($path);
1313
        if($name == "")
1314
            $name = $filename;
1315

    
1316
        $cur = count($this->attachment);
1317
        $this->attachment[$cur][0] = $path;
1318
        $this->attachment[$cur][1] = $filename;
1319
        $this->attachment[$cur][2] = $name;
1320
        $this->attachment[$cur][3] = $encoding;
1321
        $this->attachment[$cur][4] = $type;
1322
        $this->attachment[$cur][5] = false; // isStringAttachment
1323
        $this->attachment[$cur][6] = "attachment";
1324
        $this->attachment[$cur][7] = 0;
1325

    
1326
        return true;
1327
    }
1328

    
1329
    /**
1330
     * Attaches all fs, string, and binary attachments to the message.
1331
     * Returns an empty string on failure.
1332
     * @access private
1333
     * @return string
1334
     */
1335
    function AttachAll() {
1336
        // Return text of body
1337
        $mime = array();
1338

    
1339
        // Add all attachments
1340
        for($i = 0; $i < count($this->attachment); $i++)
1341
        {
1342
            // Check for string attachment
1343
            $bString = $this->attachment[$i][5];
1344
            if ($bString)
1345
                $string = $this->attachment[$i][0];
1346
            else
1347
                $path = $this->attachment[$i][0];
1348

    
1349
            $filename    = $this->attachment[$i][1];
1350
            $name        = $this->attachment[$i][2];
1351
            $encoding    = $this->attachment[$i][3];
1352
            $type        = $this->attachment[$i][4];
1353
            $disposition = $this->attachment[$i][6];
1354
            $cid         = $this->attachment[$i][7];
1355
            
1356
            $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1357
            $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE);
1358
            $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1359

    
1360
            if($disposition == "inline")
1361
                $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1362

    
1363
            $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", 
1364
                              $disposition, $name, $this->LE.$this->LE);
1365

    
1366
            // Encode as string attachment
1367
            if($bString)
1368
            {
1369
                $mime[] = $this->EncodeString($string, $encoding);
1370
                if($this->IsError()) { return ""; }
1371
                $mime[] = $this->LE.$this->LE;
1372
            }
1373
            else
1374
            {
1375
                $mime[] = $this->EncodeFile($path, $encoding);                
1376
                if($this->IsError()) { return ""; }
1377
                $mime[] = $this->LE.$this->LE;
1378
            }
1379
        }
1380

    
1381
        $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1382

    
1383
        return join("", $mime);
1384
    }
1385
    
1386
    /**
1387
     * Encodes attachment in requested format.  Returns an
1388
     * empty string on failure.
1389
     * @access private
1390
     * @return string
1391
     */
1392
    function EncodeFile ($path, $encoding = "base64") {
1393
        if(!@$fd = fopen($path, "rb"))
1394
        {
1395
            $this->SetError($this->Lang("file_open") . $path);
1396
            return "";
1397
        }
1398
        $magic_quotes = get_magic_quotes_runtime();
1399
        set_magic_quotes_runtime(0);
1400
        $file_buffer = fread($fd, filesize($path));
1401
        $file_buffer = $this->EncodeString($file_buffer, $encoding);
1402
        fclose($fd);
1403
        set_magic_quotes_runtime($magic_quotes);
1404

    
1405
        return $file_buffer;
1406
    }
1407

    
1408
    /**
1409
     * Encodes string to requested format. Returns an
1410
     * empty string on failure.
1411
     * @access private
1412
     * @return string
1413
     */
1414
    function EncodeString ($str, $encoding = "base64") {
1415
        $encoded = "";
1416
        switch(strtolower($encoding)) {
1417
          case "base64":
1418
              // chunk_split is found in PHP >= 3.0.6
1419
              $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1420
              break;
1421
          case "7bit":
1422
          case "8bit":
1423
              $encoded = $this->FixEOL($str);
1424
              if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1425
                $encoded .= $this->LE;
1426
              break;
1427
          case "binary":
1428
              $encoded = $str;
1429
              break;
1430
          case "quoted-printable":
1431
              $encoded = $this->EncodeQP($str);
1432
              break;
1433
          default:
1434
              $this->SetError($this->Lang("encoding") . $encoding);
1435
              break;
1436
        }
1437
        return $encoded;
1438
    }
1439

    
1440
    /**
1441
     * Encode a header string to best of Q, B, quoted or none.  
1442
     * @access private
1443
     * @return string
1444
     */
1445
    function EncodeHeader ($str, $position = 'text') {
1446
      $x = 0;
1447
      
1448
      switch (strtolower($position)) {
1449
        case 'phrase':
1450
          if (!preg_match('/[\200-\377]/', $str)) {
1451
            // Can't use addslashes as we don't know what value has magic_quotes_sybase.
1452
            $encoded = addcslashes($str, "\0..\37\177\\\"");
1453

    
1454
            if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str))
1455
              return ($encoded);
1456
            else
1457
              return ("\"$encoded\"");
1458
          }
1459
          $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1460
          break;
1461
        case 'comment':
1462
          $x = preg_match_all('/[()"]/', $str, $matches);
1463
          // Fall-through
1464
        case 'text':
1465
        default:
1466
          $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1467
          break;
1468
      }
1469

    
1470
      if ($x == 0)
1471
        return ($str);
1472

    
1473
      $maxlen = 75 - 7 - strlen($this->CharSet);
1474
      // Try to select the encoding which should produce the shortest output
1475
      if (strlen($str)/3 < $x) {
1476
        $encoding = 'B';
1477
        $encoded = base64_encode($str);
1478
        $maxlen -= $maxlen % 4;
1479
        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1480
      } else {
1481
        $encoding = 'Q';
1482
        $encoded = $this->EncodeQ($str, $position);
1483
        $encoded = $this->WrapText($encoded, $maxlen, true);
1484
        $encoded = str_replace("=".$this->LE, "\n", trim($encoded));
1485
      }
1486

    
1487
      $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1488
      $encoded = trim(str_replace("\n", $this->LE, $encoded));
1489
      
1490
      return $encoded;
1491
    }
1492
    
1493
    /**
1494
     * Encode string to quoted-printable.  
1495
     * @access private
1496
     * @return string
1497
     */
1498
    function EncodeQP ($str) {
1499
        $encoded = $this->FixEOL($str);
1500
        if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1501
            $encoded .= $this->LE;
1502

    
1503
        // Replace every high ascii, control and = characters
1504
        $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
1505
                  "'='.sprintf('%02X', ord('\\1'))", $encoded);
1506
        // Replace every spaces and tabs when it's the last character on a line
1507
        $encoded = preg_replace("/([\011\040])".$this->LE."/e",
1508
                  "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
1509

    
1510
        // Maximum line length of 76 characters before CRLF (74 + space + '=')
1511
        $encoded = $this->WrapText($encoded, 74, true);
1512

    
1513
        return $encoded;
1514
    }
1515

    
1516
    /**
1517
     * Encode string to q encoding.  
1518
     * @access private
1519
     * @return string
1520
     */
1521
    function EncodeQ ($str, $position = "text") {
1522
        // There should not be any EOL in the string
1523
        $encoded = preg_replace("[\r\n]", "", $str);
1524

    
1525
        switch (strtolower($position)) {
1526
          case "phrase":
1527
            $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1528
            break;
1529
          case "comment":
1530
            $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1531
          case "text":
1532
          default:
1533
            // Replace every high ascii, control =, ? and _ characters
1534
            $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1535
                  "'='.sprintf('%02X', ord('\\1'))", $encoded);
1536
            break;
1537
        }
1538
        
1539
        // Replace every spaces to _ (more readable than =20)
1540
        $encoded = str_replace(" ", "_", $encoded);
1541

    
1542
        return $encoded;
1543
    }
1544

    
1545
    /**
1546
     * Adds a string or binary attachment (non-filesystem) to the list.
1547
     * This method can be used to attach ascii or binary data,
1548
     * such as a BLOB record from a database.
1549
     * @param string $string String attachment data.
1550
     * @param string $filename Name of the attachment.
1551
     * @param string $encoding File encoding (see $Encoding).
1552
     * @param string $type File extension (MIME) type.
1553
     * @return void
1554
     */
1555
    function AddStringAttachment($string, $filename, $encoding = "base64", 
1556
                                 $type = "application/octet-stream") {
1557
        // Append to $attachment array
1558
        $cur = count($this->attachment);
1559
        $this->attachment[$cur][0] = $string;
1560
        $this->attachment[$cur][1] = $filename;
1561
        $this->attachment[$cur][2] = $filename;
1562
        $this->attachment[$cur][3] = $encoding;
1563
        $this->attachment[$cur][4] = $type;
1564
        $this->attachment[$cur][5] = true; // isString
1565
        $this->attachment[$cur][6] = "attachment";
1566
        $this->attachment[$cur][7] = 0;
1567
    }
1568
    
1569
    /**
1570
     * Adds an embedded attachment.  This can include images, sounds, and 
1571
     * just about any other document.  Make sure to set the $type to an 
1572
     * image type.  For JPEG images use "image/jpeg" and for GIF images 
1573
     * use "image/gif".
1574
     * @param string $path Path to the attachment.
1575
     * @param string $cid Content ID of the attachment.  Use this to identify 
1576
     *        the Id for accessing the image in an HTML form.
1577
     * @param string $name Overrides the attachment name.
1578
     * @param string $encoding File encoding (see $Encoding).
1579
     * @param string $type File extension (MIME) type.  
1580
     * @return bool
1581
     */
1582
    function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64", 
1583
                              $type = "application/octet-stream") {
1584
    
1585
        if(!@is_file($path))
1586
        {
1587
            $this->SetError($this->Lang("file_access") . $path);
1588
            return false;
1589
        }
1590

    
1591
        $filename = basename($path);
1592
        if($name == "")
1593
            $name = $filename;
1594

    
1595
        // Append to $attachment array
1596
        $cur = count($this->attachment);
1597
        $this->attachment[$cur][0] = $path;
1598
        $this->attachment[$cur][1] = $filename;
1599
        $this->attachment[$cur][2] = $name;
1600
        $this->attachment[$cur][3] = $encoding;
1601
        $this->attachment[$cur][4] = $type;
1602
        $this->attachment[$cur][5] = false; // isStringAttachment
1603
        $this->attachment[$cur][6] = "inline";
1604
        $this->attachment[$cur][7] = $cid;
1605
    
1606
        return true;
1607
    }
1608
    
1609
    /**
1610
     * Returns true if an inline attachment is present.
1611
     * @access private
1612
     * @return bool
1613
     */
1614
    function InlineImageExists() {
1615
        $result = false;
1616
        for($i = 0; $i < count($this->attachment); $i++)
1617
        {
1618
            if($this->attachment[$i][6] == "inline")
1619
            {
1620
                $result = true;
1621
                break;
1622
            }
1623
        }
1624
        
1625
        return $result;
1626
    }
1627

    
1628
    /////////////////////////////////////////////////
1629
    // MESSAGE RESET METHODS
1630
    /////////////////////////////////////////////////
1631

    
1632
    /**
1633
     * Clears all recipients assigned in the TO array.  Returns void.
1634
     * @return void
1635
     */
1636
    function ClearAddresses() {
1637
        $this->to = array();
1638
    }
1639

    
1640
    /**
1641
     * Clears all recipients assigned in the CC array.  Returns void.
1642
     * @return void
1643
     */
1644
    function ClearCCs() {
1645
        $this->cc = array();
1646
    }
1647

    
1648
    /**
1649
     * Clears all recipients assigned in the BCC array.  Returns void.
1650
     * @return void
1651
     */
1652
    function ClearBCCs() {
1653
        $this->bcc = array();
1654
    }
1655

    
1656
    /**
1657
     * Clears all recipients assigned in the ReplyTo array.  Returns void.
1658
     * @return void
1659
     */
1660
    function ClearReplyTos() {
1661
        $this->ReplyTo = array();
1662
    }
1663

    
1664
    /**
1665
     * Clears all recipients assigned in the TO, CC and BCC
1666
     * array.  Returns void.
1667
     * @return void
1668
     */
1669
    function ClearAllRecipients() {
1670
        $this->to = array();
1671
        $this->cc = array();
1672
        $this->bcc = array();
1673
    }
1674

    
1675
    /**
1676
     * Clears all previously set filesystem, string, and binary
1677
     * attachments.  Returns void.
1678
     * @return void
1679
     */
1680
    function ClearAttachments() {
1681
        $this->attachment = array();
1682
    }
1683

    
1684
    /**
1685
     * Clears all custom headers.  Returns void.
1686
     * @return void
1687
     */
1688
    function ClearCustomHeaders() {
1689
        $this->CustomHeader = array();
1690
    }
1691

    
1692

    
1693
    /////////////////////////////////////////////////
1694
    // MISCELLANEOUS METHODS
1695
    /////////////////////////////////////////////////
1696

    
1697
    /**
1698
     * Adds the error message to the error container.
1699
     * Returns void.
1700
     * @access private
1701
     * @return void
1702
     */
1703
    function SetError($msg) {
1704
        $this->error_count++;
1705
        $this->ErrorInfo = $msg;
1706
    }
1707

    
1708
    /**
1709
     * Returns the proper RFC 822 formatted date. 
1710
     * @access private
1711
     * @return string
1712
     */
1713
    function RFCDate() {
1714
        $tz = date("Z");
1715
        $tzs = ($tz < 0) ? "-" : "+";
1716
        $tz = abs($tz);
1717
        $tz = ($tz/3600)*100 + ($tz%3600)/60;
1718
        $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz);
1719

    
1720
        return $result;
1721
    }
1722
    
1723
    /**
1724
     * Returns the appropriate server variable.  Should work with both 
1725
     * PHP 4.1.0+ as well as older versions.  Returns an empty string 
1726
     * if nothing is found.
1727
     * @access private
1728
     * @return mixed
1729
     */
1730
    function ServerVar($varName) {
1731
        global $HTTP_SERVER_VARS;
1732
        global $HTTP_ENV_VARS;
1733

    
1734
        if(!isset($_SERVER))
1735
        {
1736
            $_SERVER = $HTTP_SERVER_VARS;
1737
            if(!isset($_SERVER["REMOTE_ADDR"]))
1738
                $_SERVER = $HTTP_ENV_VARS; // must be Apache
1739
        }
1740
        
1741
        if(isset($_SERVER[$varName]))
1742
            return $_SERVER[$varName];
1743
        else
1744
            return "";
1745
    }
1746

    
1747
    /**
1748
     * Returns the server hostname or 'localhost.localdomain' if unknown.
1749
     * @access private
1750
     * @return string
1751
     */
1752
    function ServerHostname() {
1753
        if ($this->Hostname != "")
1754
            $result = $this->Hostname;
1755
        elseif ($this->ServerVar('SERVER_NAME') != "")
1756
            $result = $this->ServerVar('SERVER_NAME');
1757
        else
1758
            $result = "localhost.localdomain";
1759

    
1760
        return $result;
1761
    }
1762

    
1763
    /**
1764
     * Returns a message in the appropriate language.
1765
     * @access private
1766
     * @return string
1767
     */
1768
    function Lang($key) {
1769
        if(count($this->language) < 1)
1770
            $this->SetLanguage("en"); // set the default language
1771
    
1772
        if(isset($this->language[$key]))
1773
            return $this->language[$key];
1774
        else
1775
            return "Language string failed to load: " . $key;
1776
    }
1777
    
1778
    /**
1779
     * Returns true if an error occurred.
1780
     * @return bool
1781
     */
1782
    function IsError() {
1783
        return ($this->error_count > 0);
1784
    }
1785

    
1786
    /**
1787
     * Changes every end of line from CR or LF to CRLF.  
1788
     * @access private
1789
     * @return string
1790
     */
1791
    function FixEOL($str) {
1792
        $str = str_replace("\r\n", "\n", $str);
1793
        $str = str_replace("\r", "\n", $str);
1794
        $str = str_replace("\n", $this->LE, $str);
1795
        return $str;
1796
    }
1797

    
1798
    /**
1799
     * Adds a custom header. 
1800
     * @return void
1801
     */
1802
    function AddCustomHeader($custom_header) {
1803
        $this->CustomHeader[] = explode(":", $custom_header, 2);
1804
    }
1805
}
1806

    
1807

    
1808
////////////////////////////////////////////////////
1809
// SMTP - PHP SMTP class
1810
//
1811
// Version 1.02
1812
//
1813
// Define an SMTP class that can be used to connect
1814
// and communicate with any SMTP server. It implements
1815
// all the SMTP functions defined in RFC821 except TURN.
1816
//
1817
// Author: Chris Ryan
1818
//
1819
// License: LGPL, see LICENSE
1820
////////////////////////////////////////////////////
1821

    
1822
/**
1823
 * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
1824
 * commands except TURN which will always return a not implemented
1825
 * error. SMTP also provides some utility methods for sending mail
1826
 * to an SMTP server.
1827
 * @package PHPMailer
1828
 * @author Chris Ryan
1829
 */
1830
class SMTP
1831
{
1832
    var $protocol = '';
1833
    /**
1834
     *  SMTP server port
1835
     *  @var int
1836
     */
1837
    var $SMTP_PORT = 25;
1838
    
1839
    /**
1840
     *  SMTP reply line ending
1841
     *  @var string
1842
     */
1843
    var $CRLF = "\r\n";
1844
    
1845
    /**
1846
     *  Sets whether debugging is turned on
1847
     *  @var bool
1848
     */
1849
    var $do_debug;       # the level of debug to perform
1850

    
1851
    /**#@+
1852
     * @access private
1853
     */
1854
    var $smtp_conn;      # the socket to the server
1855
    var $error;          # error if any on the last call
1856
    var $helo_rply;      # the reply the server sent to us for HELO
1857
    /**#@-*/
1858

    
1859
    /**
1860
     * Initialize the class so that the data is in a known state.
1861
     * @access public
1862
     * @return void
1863
     */
1864
    function SMTP() {
1865
        $this->smtp_conn = 0;
1866
        $this->error = null;
1867
        $this->helo_rply = null;
1868

    
1869
        $this->do_debug = 0;
1870
    }
1871

    
1872
    /*************************************************************
1873
     *                    CONNECTION FUNCTIONS                  *
1874
     ***********************************************************/
1875

    
1876
    /**
1877
     * Connect to the server specified on the port specified.
1878
     * If the port is not specified use the default SMTP_PORT.
1879
     * If tval is specified then a connection will try and be
1880
     * established with the server for that number of seconds.
1881
     * If tval is not specified the default is 30 seconds to
1882
     * try on the connection.
1883
     *
1884
     * SMTP CODE SUCCESS: 220
1885
     * SMTP CODE FAILURE: 421
1886
     * @access public
1887
     * @return bool
1888
     */
1889
    function Connect($host,$port=0,$tval=30) {
1890
        # set the error val to null so there is no confusion
1891
        $this->error = null;
1892

    
1893
        # make sure we are __not__ connected
1894
        if($this->connected()) {
1895
            # ok we are connected! what should we do?
1896
            # for now we will just give an error saying we
1897
            # are already connected
1898
            $this->error =
1899
                array("error" => "Already connected to a server");
1900
            return false;
1901
        }
1902

    
1903
        if(empty($port)) {
1904
            $port = $this->SMTP_PORT;
1905
        }
1906

    
1907
        #connect to the smtp server
1908
        $this->smtp_conn = fsockopen($this->protocol . $host,    # the host of the server
1909
                                     $port,    # the port to use
1910
                                     $errno,   # error number if any
1911
                                     $errstr,  # error message if any
1912
                                     $tval);   # give up after ? secs
1913
        # verify we connected properly
1914
        if(empty($this->smtp_conn)) {
1915
            $this->error = array("error" => "Failed to connect to server",
1916
                                 "errno" => $errno,
1917
                                 "errstr" => $errstr);
1918
            if($this->do_debug >= 1) {
1919
                echo "SMTP -> ERROR: " . $this->error["error"] .
1920
                         ": $errstr ($errno)" . $this->CRLF;
1921
            }
1922
            return false;
1923
        }
1924

    
1925
        # sometimes the SMTP server takes a little longer to respond
1926
        # so we will give it a longer timeout for the first read
1927
        // Windows still does not have support for this timeout function
1928
        if(substr(PHP_OS, 0, 3) != "WIN")
1929
           socket_set_timeout($this->smtp_conn, $tval, 0);
1930

    
1931
        # get any announcement stuff
1932
        $announce = $this->get_lines();
1933

    
1934
        # set the timeout  of any socket functions at 1/10 of a second
1935
        //if(function_exists("socket_set_timeout"))
1936
        //   socket_set_timeout($this->smtp_conn, 0, 100000);
1937

    
1938
        if($this->do_debug >= 2) {
1939
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;
1940
        }
1941

    
1942
        return true;
1943
    }
1944

    
1945
    /**
1946
     * Performs SMTP authentication.  Must be run after running the
1947
     * Hello() method.  Returns true if successfully authenticated.
1948
     * @access public
1949
     * @return bool
1950
     */
1951
    function Authenticate($username, $password) {
1952
        // Start authentication
1953
        fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
1954

    
1955
        $rply = $this->get_lines();
1956
        $code = substr($rply,0,3);
1957

    
1958
        if($code != 334) {
1959
            $this->error =
1960
                array("error" => "AUTH not accepted from server",
1961
                      "smtp_code" => $code,
1962
                      "smtp_msg" => substr($rply,4));
1963
            if($this->do_debug >= 1) {
1964
                echo "SMTP -> ERROR: " . $this->error["error"] .
1965
                         ": " . $rply . $this->CRLF;
1966
            }
1967
            return false;
1968
        }
1969

    
1970
        // Send encoded username
1971
        fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
1972

    
1973
        $rply = $this->get_lines();
1974
        $code = substr($rply,0,3);
1975

    
1976
        if($code != 334) {
1977
            $this->error =
1978
                array("error" => "Username not accepted from server",
1979
                      "smtp_code" => $code,
1980
                      "smtp_msg" => substr($rply,4));
1981
            if($this->do_debug >= 1) {
1982
                echo "SMTP -> ERROR: " . $this->error["error"] .
1983
                         ": " . $rply . $this->CRLF;
1984
            }
1985
            return false;
1986
        }
1987

    
1988
        // Send encoded password
1989
        fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
1990

    
1991
        $rply = $this->get_lines();
1992
        $code = substr($rply,0,3);
1993

    
1994
        if($code != 235) {
1995
            $this->error =
1996
                array("error" => "Password not accepted from server",
1997
                      "smtp_code" => $code,
1998
                      "smtp_msg" => substr($rply,4));
1999
            if($this->do_debug >= 1) {
2000
                echo "SMTP -> ERROR: " . $this->error["error"] .
2001
                         ": " . $rply . $this->CRLF;
2002
            }
2003
            return false;
2004
        }
2005

    
2006
        return true;
2007
    }
2008

    
2009
    /**
2010
     * Returns true if connected to a server otherwise false
2011
     * @access private
2012
     * @return bool
2013
     */
2014
    function Connected() {
2015
        if(!empty($this->smtp_conn)) {
2016
            $sock_status = socket_get_status($this->smtp_conn);
2017
            if($sock_status["eof"]) {
2018
                # hmm this is an odd situation... the socket is
2019
                # valid but we aren't connected anymore
2020
                if($this->do_debug >= 1) {
2021
                    echo "SMTP -> NOTICE:" . $this->CRLF .
2022
                         "EOF caught while checking if connected";
2023
                }
2024
                $this->Close();
2025
                return false;
2026
            }
2027
            return true; # everything looks good
2028
        }
2029
        return false;
2030
    }
2031

    
2032
    /**
2033
     * Closes the socket and cleans up the state of the class.
2034
     * It is not considered good to use this function without
2035
     * first trying to use QUIT.
2036
     * @access public
2037
     * @return void
2038
     */
2039
    function Close() {
2040
        $this->error = null; # so there is no confusion
2041
        $this->helo_rply = null;
2042
        if(!empty($this->smtp_conn)) {
2043
            # close the connection and cleanup
2044
            fclose($this->smtp_conn);
2045
            $this->smtp_conn = 0;
2046
        }
2047
    }
2048

    
2049

    
2050
    /***************************************************************
2051
     *                        SMTP COMMANDS                       *
2052
     *************************************************************/
2053

    
2054
    /**
2055
     * Issues a data command and sends the msg_data to the server
2056
     * finializing the mail transaction. $msg_data is the message
2057
     * that is to be send with the headers. Each header needs to be
2058
     * on a single line followed by a <CRLF> with the message headers
2059
     * and the message body being seperated by and additional <CRLF>.
2060
     *
2061
     * Implements rfc 821: DATA <CRLF>
2062
     *
2063
     * SMTP CODE INTERMEDIATE: 354
2064
     *     [data]
2065
     *     <CRLF>.<CRLF>
2066
     *     SMTP CODE SUCCESS: 250
2067
     *     SMTP CODE FAILURE: 552,554,451,452
2068
     * SMTP CODE FAILURE: 451,554
2069
     * SMTP CODE ERROR  : 500,501,503,421
2070
     * @access public
2071
     * @return bool
2072
     */
2073
    function Data($msg_data) {
2074
    	
2075
    
2076
        $this->error = null; # so no confusion is caused
2077

    
2078
        if(!$this->connected()) {
2079
            $this->error = array(
2080
                    "error" => "Called Data() without being connected");
2081
            return false;
2082
        }
2083

    
2084
        fputs($this->smtp_conn,"DATA" . $this->CRLF);
2085

    
2086
        $rply = $this->get_lines();
2087
        $code = substr($rply,0,3);
2088

    
2089
        if($this->do_debug >= 2) {
2090
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2091
        }
2092

    
2093
        if($code != 354) {
2094
            $this->error =
2095
                array("error" => "DATA command not accepted from server",
2096
                      "smtp_code" => $code,
2097
                      "smtp_msg" => substr($rply,4));
2098
            if($this->do_debug >= 1) {
2099
                echo "SMTP -> ERROR: " . $this->error["error"] .
2100
                         ": " . $rply . $this->CRLF;
2101
            }
2102
            return false;
2103
        }
2104

    
2105
        # the server is ready to accept data!
2106
        # according to rfc 821 we should not send more than 1000
2107
        # including the CRLF
2108
        # characters on a single line so we will break the data up
2109
        # into lines by \r and/or \n then if needed we will break
2110
        # each of those into smaller lines to fit within the limit.
2111
        # in addition we will be looking for lines that start with
2112
        # a period '.' and append and additional period '.' to that
2113
        # line. NOTE: this does not count towards are limit.
2114

    
2115
        # normalize the line breaks so we know the explode works
2116
        $msg_data = str_replace("\r\n","\n",$msg_data);
2117
        $msg_data = str_replace("\r","\n",$msg_data);
2118
        $lines = explode("\n",$msg_data);
2119

    
2120
        # we need to find a good way to determine is headers are
2121
        # in the msg_data or if it is a straight msg body
2122
        # currently I'm assuming rfc 822 definitions of msg headers
2123
        # and if the first field of the first line (':' sperated)
2124
        # does not contain a space then it _should_ be a header
2125
        # and we can process all lines before a blank "" line as
2126
        # headers.
2127
        $field = substr($lines[0],0,strpos($lines[0],":"));
2128
        $in_headers = false;
2129
        if(!empty($field) && !strstr($field," ")) {
2130
            $in_headers = true;
2131
        }
2132

    
2133
        $max_line_length = 998; # used below; set here for ease in change
2134

    
2135
        while(list(,$line) = @each($lines)) {
2136
            $lines_out = null;
2137
            if($line == "" && $in_headers) {
2138
                $in_headers = false;
2139
            }
2140
            # ok we need to break this line up into several
2141
            # smaller lines
2142
            while(strlen($line) > $max_line_length) {
2143
                $pos = strrpos(substr($line,0,$max_line_length)," ");
2144

    
2145
                # Patch to fix DOS attack
2146
                if(!$pos) {
2147
                    $pos = $max_line_length - 1;
2148
                }
2149

    
2150
                $lines_out[] = substr($line,0,$pos);
2151
                $line = substr($line,$pos + 1);
2152
                # if we are processing headers we need to
2153
                # add a LWSP-char to the front of the new line
2154
                # rfc 822 on long msg headers
2155
                if($in_headers) {
2156
                    $line = "\t" . $line;
2157
                }
2158
            }
2159
            $lines_out[] = $line;
2160

    
2161
            # now send the lines to the server
2162
            while(list(,$line_out) = @each($lines_out)) {
2163
                if(strlen($line_out) > 0)
2164
                {
2165
                    if(substr($line_out, 0, 1) == ".") {
2166
                        $line_out = "." . $line_out;
2167
                    }
2168
                }
2169
                fputs($this->smtp_conn,$line_out . $this->CRLF);
2170
                if($this->do_debug >= 2) {
2171
            		echo "sending line:" . $line_out . $this->CRLF;
2172
        		} 
2173
            }
2174
            
2175
        }
2176

    
2177
        # ok all the message data has been sent so lets get this
2178
        # over with aleady
2179
        fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
2180

    
2181
        $rply = $this->get_lines();
2182
        $code = substr($rply,0,3);
2183

    
2184
        if($this->do_debug >= 2) {
2185
            echo "SMTP -> FROM SERVER(after sending data):" . $this->CRLF . $rply;
2186
        }
2187

    
2188
        if($code != 250) {
2189
            $this->error =
2190
                array("error" => "DATA not accepted from server",
2191
                      "smtp_code" => $code,
2192
                      "smtp_msg" => substr($rply,4));
2193
            if($this->do_debug >= 1) {
2194
                echo "SMTP -> ERROR: " . $this->error["error"] .
2195
                         ": " . $rply . $this->CRLF;
2196
            }
2197
            return false;
2198
        }
2199
        return true;
2200
    }
2201

    
2202
    /**
2203
     * Expand takes the name and asks the server to list all the
2204
     * people who are members of the _list_. Expand will return
2205
     * back and array of the result or false if an error occurs.
2206
     * Each value in the array returned has the format of:
2207
     *     [ <full-name> <sp> ] <path>
2208
     * The definition of <path> is defined in rfc 821
2209
     *
2210
     * Implements rfc 821: EXPN <SP> <string> <CRLF>
2211
     *
2212
     * SMTP CODE SUCCESS: 250
2213
     * SMTP CODE FAILURE: 550
2214
     * SMTP CODE ERROR  : 500,501,502,504,421
2215
     * @access public
2216
     * @return string array
2217
     */
2218
    function Expand($name) {
2219
        $this->error = null; # so no confusion is caused
2220

    
2221
        if(!$this->connected()) {
2222
            $this->error = array(
2223
                    "error" => "Called Expand() without being connected");
2224
            return false;
2225
        }
2226

    
2227
        fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
2228

    
2229
        $rply = $this->get_lines();
2230
        $code = substr($rply,0,3);
2231

    
2232
        if($this->do_debug >= 2) {
2233
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2234
        }
2235

    
2236
        if($code != 250) {
2237
            $this->error =
2238
                array("error" => "EXPN not accepted from server",
2239
                      "smtp_code" => $code,
2240
                      "smtp_msg" => substr($rply,4));
2241
            if($this->do_debug >= 1) {
2242
                echo "SMTP -> ERROR: " . $this->error["error"] .
2243
                         ": " . $rply . $this->CRLF;
2244
            }
2245
            return false;
2246
        }
2247

    
2248
        # parse the reply and place in our array to return to user
2249
        $entries = explode($this->CRLF,$rply);
2250
        while(list(,$l) = @each($entries)) {
2251
            $list[] = substr($l,4);
2252
        }
2253

    
2254
        return $list;
2255
    }
2256

    
2257
    /**
2258
     * Sends the HELO command to the smtp server.
2259
     * This makes sure that we and the server are in
2260
     * the same known state.
2261
     *
2262
     * Implements from rfc 821: HELO <SP> <domain> <CRLF>
2263
     *
2264
     * SMTP CODE SUCCESS: 250
2265
     * SMTP CODE ERROR  : 500, 501, 504, 421
2266
     * @access public
2267
     * @return bool
2268
     */
2269
    function Hello($host="") {
2270
        $this->error = null; # so no confusion is caused
2271

    
2272
        if(!$this->connected()) {
2273
            $this->error = array(
2274
                    "error" => "Called Hello() without being connected");
2275
            return false;
2276
        }
2277

    
2278
        # if a hostname for the HELO wasn't specified determine
2279
        # a suitable one to send
2280
        if(empty($host)) {
2281
            # we need to determine some sort of appopiate default
2282
            # to send to the server
2283
            $host = "localhost";
2284
        }
2285

    
2286
        // Send extended hello first (RFC 2821)
2287
        if(!$this->SendHello("EHLO", $host))
2288
        {
2289
            if(!$this->SendHello("HELO", $host))
2290
                return false;
2291
        }
2292

    
2293
        return true;
2294
    }
2295

    
2296
    /**
2297
     * Sends a HELO/EHLO command.
2298
     * @access private
2299
     * @return bool
2300
     */
2301
    function SendHello($hello, $host) {
2302
        fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
2303

    
2304
        $rply = $this->get_lines();
2305
        $code = substr($rply,0,3);
2306

    
2307
        if($this->do_debug >= 2) {
2308
            echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply;
2309
        }
2310

    
2311
        if($code != 250) {
2312
            $this->error =
2313
                array("error" => $hello . " not accepted from server",
2314
                      "smtp_code" => $code,
2315
                      "smtp_msg" => substr($rply,4));
2316
            if($this->do_debug >= 1) {
2317
                echo "SMTP -> ERROR: " . $this->error["error"] .
2318
                         ": " . $rply . $this->CRLF;
2319
            }
2320
            return false;
2321
        }
2322

    
2323
        $this->helo_rply = $rply;
2324
        
2325
        return true;
2326
    }
2327

    
2328
    /**
2329
     * Gets help information on the keyword specified. If the keyword
2330
     * is not specified then returns generic help, ussually contianing
2331
     * A list of keywords that help is available on. This function
2332
     * returns the results back to the user. It is up to the user to
2333
     * handle the returned data. If an error occurs then false is
2334
     * returned with $this->error set appropiately.
2335
     *
2336
     * Implements rfc 821: HELP [ <SP> <string> ] <CRLF>
2337
     *
2338
     * SMTP CODE SUCCESS: 211,214
2339
     * SMTP CODE ERROR  : 500,501,502,504,421
2340
     * @access public
2341
     * @return string
2342
     */
2343
    function Help($keyword="") {
2344
        $this->error = null; # to avoid confusion
2345

    
2346
        if(!$this->connected()) {
2347
            $this->error = array(
2348
                    "error" => "Called Help() without being connected");
2349
            return false;
2350
        }
2351

    
2352
        $extra = "";
2353
        if(!empty($keyword)) {
2354
            $extra = " " . $keyword;
2355
        }
2356

    
2357
        fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
2358

    
2359
        $rply = $this->get_lines();
2360
        $code = substr($rply,0,3);
2361

    
2362
        if($this->do_debug >= 2) {
2363
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2364
        }
2365

    
2366
        if($code != 211 && $code != 214) {
2367
            $this->error =
2368
                array("error" => "HELP not accepted from server",
2369
                      "smtp_code" => $code,
2370
                      "smtp_msg" => substr($rply,4));
2371
            if($this->do_debug >= 1) {
2372
                echo "SMTP -> ERROR: " . $this->error["error"] .
2373
                         ": " . $rply . $this->CRLF;
2374
            }
2375
            return false;
2376
        }
2377

    
2378
        return $rply;
2379
    }
2380

    
2381
    /**
2382
     * Starts a mail transaction from the email address specified in
2383
     * $from. Returns true if successful or false otherwise. If True
2384
     * the mail transaction is started and then one or more Recipient
2385
     * commands may be called followed by a Data command.
2386
     *
2387
     * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
2388
     *
2389
     * SMTP CODE SUCCESS: 250
2390
     * SMTP CODE SUCCESS: 552,451,452
2391
     * SMTP CODE SUCCESS: 500,501,421
2392
     * @access public
2393
     * @return bool
2394
     */
2395
    function Mail($from) {
2396
        $this->error = null; # so no confusion is caused
2397

    
2398
        if(!$this->connected()) {
2399
            $this->error = array(
2400
                    "error" => "Called Mail() without being connected");
2401
            return false;
2402
        }
2403

    
2404
        fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $this->CRLF);
2405

    
2406
        $rply = $this->get_lines();
2407
        $code = substr($rply,0,3);
2408

    
2409
        if($this->do_debug >= 2) {
2410
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2411
        }
2412

    
2413
        if($code != 250) {
2414
            $this->error =
2415
                array("error" => "MAIL not accepted from server",
2416
                      "smtp_code" => $code,
2417
                      "smtp_msg" => substr($rply,4));
2418
            if($this->do_debug >= 1) {
2419
                echo "SMTP -> ERROR: " . $this->error["error"] .
2420
                         ": " . $rply . $this->CRLF;
2421
            }
2422
            return false;
2423
        }
2424
        return true;
2425
    }
2426

    
2427
    /**
2428
     * Sends the command NOOP to the SMTP server.
2429
     *
2430
     * Implements from rfc 821: NOOP <CRLF>
2431
     *
2432
     * SMTP CODE SUCCESS: 250
2433
     * SMTP CODE ERROR  : 500, 421
2434
     * @access public
2435
     * @return bool
2436
     */
2437
    function Noop() {
2438
        $this->error = null; # so no confusion is caused
2439

    
2440
        if(!$this->connected()) {
2441
            $this->error = array(
2442
                    "error" => "Called Noop() without being connected");
2443
            return false;
2444
        }
2445

    
2446
        fputs($this->smtp_conn,"NOOP" . $this->CRLF);
2447

    
2448
        $rply = $this->get_lines();
2449
        $code = substr($rply,0,3);
2450

    
2451
        if($this->do_debug >= 2) {
2452
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2453
        }
2454

    
2455
        if($code != 250) {
2456
            $this->error =
2457
                array("error" => "NOOP not accepted from server",
2458
                      "smtp_code" => $code,
2459
                      "smtp_msg" => substr($rply,4));
2460
            if($this->do_debug >= 1) {
2461
                echo "SMTP -> ERROR: " . $this->error["error"] .
2462
                         ": " . $rply . $this->CRLF;
2463
            }
2464
            return false;
2465
        }
2466
        return true;
2467
    }
2468

    
2469
    /**
2470
     * Sends the quit command to the server and then closes the socket
2471
     * if there is no error or the $close_on_error argument is true.
2472
     *
2473
     * Implements from rfc 821: QUIT <CRLF>
2474
     *
2475
     * SMTP CODE SUCCESS: 221
2476
     * SMTP CODE ERROR  : 500
2477
     * @access public
2478
     * @return bool
2479
     */
2480
    function Quit($close_on_error=true) {
2481
        $this->error = null; # so there is no confusion
2482

    
2483
        if(!$this->connected()) {
2484
            $this->error = array(
2485
                    "error" => "Called Quit() without being connected");
2486
            return false;
2487
        }
2488

    
2489
        # send the quit command to the server
2490
        fputs($this->smtp_conn,"quit" . $this->CRLF);
2491

    
2492
        # get any good-bye messages
2493
        $byemsg = $this->get_lines();
2494

    
2495
        if($this->do_debug >= 2) {
2496
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;
2497
        }
2498

    
2499
        $rval = true;
2500
        $e = null;
2501

    
2502
        $code = substr($byemsg,0,3);
2503
        if($code != 221) {
2504
            # use e as a tmp var cause Close will overwrite $this->error
2505
            $e = array("error" => "SMTP server rejected quit command",
2506
                       "smtp_code" => $code,
2507
                       "smtp_rply" => substr($byemsg,4));
2508
            $rval = false;
2509
            if($this->do_debug >= 1) {
2510
                echo "SMTP -> ERROR: " . $e["error"] . ": " .
2511
                         $byemsg . $this->CRLF;
2512
            }
2513
        }
2514

    
2515
        if(empty($e) || $close_on_error) {
2516
            $this->Close();
2517
        }
2518

    
2519
        return $rval;
2520
    }
2521

    
2522
    /**
2523
     * Sends the command RCPT to the SMTP server with the TO: argument of $to.
2524
     * Returns true if the recipient was accepted false if it was rejected.
2525
     *
2526
     * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
2527
     *
2528
     * SMTP CODE SUCCESS: 250,251
2529
     * SMTP CODE FAILURE: 550,551,552,553,450,451,452
2530
     * SMTP CODE ERROR  : 500,501,503,421
2531
     * @access public
2532
     * @return bool
2533
     */
2534
    function Recipient($to) {
2535
        $this->error = null; # so no confusion is caused
2536

    
2537
        if(!$this->connected()) {
2538
            $this->error = array(
2539
                    "error" => "Called Recipient() without being connected");
2540
            return false;
2541
        }
2542

    
2543
        fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
2544

    
2545
        $rply = $this->get_lines();
2546
        $code = substr($rply,0,3);
2547

    
2548
        if($this->do_debug >= 2) {
2549
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2550
        }
2551

    
2552
        if($code != 250 && $code != 251) {
2553
            $this->error =
2554
                array("error" => "RCPT not accepted from server",
2555
                      "smtp_code" => $code,
2556
                      "smtp_msg" => substr($rply,4));
2557
            if($this->do_debug >= 1) {
2558
                echo "SMTP -> ERROR: " . $this->error["error"] .
2559
                         ": " . $rply . $this->CRLF;
2560
            }
2561
            return false;
2562
        }
2563
        return true;
2564
    }
2565

    
2566
    /**
2567
     * Sends the RSET command to abort and transaction that is
2568
     * currently in progress. Returns true if successful false
2569
     * otherwise.
2570
     *
2571
     * Implements rfc 821: RSET <CRLF>
2572
     *
2573
     * SMTP CODE SUCCESS: 250
2574
     * SMTP CODE ERROR  : 500,501,504,421
2575
     * @access public
2576
     * @return bool
2577
     */
2578
    function Reset() {
2579
        $this->error = null; # so no confusion is caused
2580

    
2581
        if(!$this->connected()) {
2582
            $this->error = array(
2583
                    "error" => "Called Reset() without being connected");
2584
            return false;
2585
        }
2586

    
2587
        fputs($this->smtp_conn,"RSET" . $this->CRLF);
2588

    
2589
        $rply = $this->get_lines();
2590
        $code = substr($rply,0,3);
2591

    
2592
        if($this->do_debug >= 2) {
2593
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2594
        }
2595

    
2596
        if($code != 250) {
2597
            $this->error =
2598
                array("error" => "RSET failed",
2599
                      "smtp_code" => $code,
2600
                      "smtp_msg" => substr($rply,4));
2601
            if($this->do_debug >= 1) {
2602
                echo "SMTP -> ERROR: " . $this->error["error"] .
2603
                         ": " . $rply . $this->CRLF;
2604
            }
2605
            return false;
2606
        }
2607

    
2608
        return true;
2609
    }
2610

    
2611
    /**
2612
     * Starts a mail transaction from the email address specified in
2613
     * $from. Returns true if successful or false otherwise. If True
2614
     * the mail transaction is started and then one or more Recipient
2615
     * commands may be called followed by a Data command. This command
2616
     * will send the message to the users terminal if they are logged
2617
     * in.
2618
     *
2619
     * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF>
2620
     *
2621
     * SMTP CODE SUCCESS: 250
2622
     * SMTP CODE SUCCESS: 552,451,452
2623
     * SMTP CODE SUCCESS: 500,501,502,421
2624
     * @access public
2625
     * @return bool
2626
     */
2627
    function Send($from) {
2628
        $this->error = null; # so no confusion is caused
2629

    
2630
        if(!$this->connected()) {
2631
            $this->error = array(
2632
                    "error" => "Called Send() without being connected");
2633
            return false;
2634
        }
2635

    
2636
        fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
2637

    
2638
        $rply = $this->get_lines();
2639
        $code = substr($rply,0,3);
2640

    
2641
        if($this->do_debug >= 2) {
2642
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2643
        }
2644

    
2645
        if($code != 250) {
2646
            $this->error =
2647
                array("error" => "SEND not accepted from server",
2648
                      "smtp_code" => $code,
2649
                      "smtp_msg" => substr($rply,4));
2650
            if($this->do_debug >= 1) {
2651
                echo "SMTP -> ERROR: " . $this->error["error"] .
2652
                         ": " . $rply . $this->CRLF;
2653
            }
2654
            return false;
2655
        }
2656
        return true;
2657
    }
2658

    
2659
    /**
2660
     * Starts a mail transaction from the email address specified in
2661
     * $from. Returns true if successful or false otherwise. If True
2662
     * the mail transaction is started and then one or more Recipient
2663
     * commands may be called followed by a Data command. This command
2664
     * will send the message to the users terminal if they are logged
2665
     * in and send them an email.
2666
     *
2667
     * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
2668
     *
2669
     * SMTP CODE SUCCESS: 250
2670
     * SMTP CODE SUCCESS: 552,451,452
2671
     * SMTP CODE SUCCESS: 500,501,502,421
2672
     * @access public
2673
     * @return bool
2674
     */
2675
    function SendAndMail($from) {
2676
        $this->error = null; # so no confusion is caused
2677

    
2678
        if(!$this->connected()) {
2679
            $this->error = array(
2680
                "error" => "Called SendAndMail() without being connected");
2681
            return false;
2682
        }
2683

    
2684
        fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
2685

    
2686
        $rply = $this->get_lines();
2687
        $code = substr($rply,0,3);
2688

    
2689
        if($this->do_debug >= 2) {
2690
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2691
        }
2692

    
2693
        if($code != 250) {
2694
            $this->error =
2695
                array("error" => "SAML not accepted from server",
2696
                      "smtp_code" => $code,
2697
                      "smtp_msg" => substr($rply,4));
2698
            if($this->do_debug >= 1) {
2699
                echo "SMTP -> ERROR: " . $this->error["error"] .
2700
                         ": " . $rply . $this->CRLF;
2701
            }
2702
            return false;
2703
        }
2704
        return true;
2705
    }
2706

    
2707
    /**
2708
     * Starts a mail transaction from the email address specified in
2709
     * $from. Returns true if successful or false otherwise. If True
2710
     * the mail transaction is started and then one or more Recipient
2711
     * commands may be called followed by a Data command. This command
2712
     * will send the message to the users terminal if they are logged
2713
     * in or mail it to them if they are not.
2714
     *
2715
     * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF>
2716
     *
2717
     * SMTP CODE SUCCESS: 250
2718
     * SMTP CODE SUCCESS: 552,451,452
2719
     * SMTP CODE SUCCESS: 500,501,502,421
2720
     * @access public
2721
     * @return bool
2722
     */
2723
    function SendOrMail($from) {
2724
        $this->error = null; # so no confusion is caused
2725

    
2726
        if(!$this->connected()) {
2727
            $this->error = array(
2728
                "error" => "Called SendOrMail() without being connected");
2729
            return false;
2730
        }
2731

    
2732
        fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
2733

    
2734
        $rply = $this->get_lines();
2735
        $code = substr($rply,0,3);
2736

    
2737
        if($this->do_debug >= 2) {
2738
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2739
        }
2740

    
2741
        if($code != 250) {
2742
            $this->error =
2743
                array("error" => "SOML not accepted from server",
2744
                      "smtp_code" => $code,
2745
                      "smtp_msg" => substr($rply,4));
2746
            if($this->do_debug >= 1) {
2747
                echo "SMTP -> ERROR: " . $this->error["error"] .
2748
                         ": " . $rply . $this->CRLF;
2749
            }
2750
            return false;
2751
        }
2752
        return true;
2753
    }
2754

    
2755
    /**
2756
     * This is an optional command for SMTP that this class does not
2757
     * support. This method is here to make the RFC821 Definition
2758
     * complete for this class and __may__ be implimented in the future
2759
     *
2760
     * Implements from rfc 821: TURN <CRLF>
2761
     *
2762
     * SMTP CODE SUCCESS: 250
2763
     * SMTP CODE FAILURE: 502
2764
     * SMTP CODE ERROR  : 500, 503
2765
     * @access public
2766
     * @return bool
2767
     */
2768
    function Turn() {
2769
        $this->error = array("error" => "This method, TURN, of the SMTP ".
2770
                                        "is not implemented");
2771
        if($this->do_debug >= 1) {
2772
            echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF;
2773
        }
2774
        return false;
2775
    }
2776

    
2777
    /**
2778
     * Verifies that the name is recognized by the server.
2779
     * Returns false if the name could not be verified otherwise
2780
     * the response from the server is returned.
2781
     *
2782
     * Implements rfc 821: VRFY <SP> <string> <CRLF>
2783
     *
2784
     * SMTP CODE SUCCESS: 250,251
2785
     * SMTP CODE FAILURE: 550,551,553
2786
     * SMTP CODE ERROR  : 500,501,502,421
2787
     * @access public
2788
     * @return int
2789
     */
2790
    function Verify($name) {
2791
        $this->error = null; # so no confusion is caused
2792

    
2793
        if(!$this->connected()) {
2794
            $this->error = array(
2795
                    "error" => "Called Verify() without being connected");
2796
            return false;
2797
        }
2798

    
2799
        fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF);
2800

    
2801
        $rply = $this->get_lines();
2802
        $code = substr($rply,0,3);
2803

    
2804
        if($this->do_debug >= 2) {
2805
            echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
2806
        }
2807

    
2808
        if($code != 250 && $code != 251) {
2809
            $this->error =
2810
                array("error" => "VRFY failed on name '$name'",
2811
                      "smtp_code" => $code,
2812
                      "smtp_msg" => substr($rply,4));
2813
            if($this->do_debug >= 1) {
2814
                echo "SMTP -> ERROR: " . $this->error["error"] .
2815
                         ": " . $rply . $this->CRLF;
2816
            }
2817
            return false;
2818
        }
2819
        return $rply;
2820
    }
2821

    
2822
    /*******************************************************************
2823
     *                       INTERNAL FUNCTIONS                       *
2824
     ******************************************************************/
2825

    
2826
    /**
2827
     * Read in as many lines as possible
2828
     * either before eof or socket timeout occurs on the operation.
2829
     * With SMTP we can tell if we have more lines to read if the
2830
     * 4th character is '-' symbol. If it is a space then we don't
2831
     * need to read anything else.
2832
     * @access private
2833
     * @return string
2834
     */
2835
    function get_lines() {
2836
        $data = "";
2837
        while($str = @fgets($this->smtp_conn,515)) {
2838
            if($this->do_debug >= 4) {
2839
                echo "SMTP -> get_lines(): \$data was \"$data\"" .
2840
                         $this->CRLF;
2841
                echo "SMTP -> get_lines(): \$str is \"$str\"" .
2842
                         $this->CRLF;
2843
            }
2844
            $data .= $str;
2845
            if($this->do_debug >= 4) {
2846
                echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF;
2847
            }
2848
            # if the 4th character is a space then we are done reading
2849
            # so just break the loop
2850
            if(substr($str,3,1) == " ") { break; }
2851
        }
2852
        return $data;
2853
    }
2854

    
2855
}
2856

    
(5-5/5)