<?php
/**************************************************************************
* This file is part of the WebIssues Server program
* Copyright (C) 2006 Michał Męciński
* Copyright (C) 2007-2009 WebIssues Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
**************************************************************************/

function wi_mail_send( $from, $to, $subject, $body, $content_type )
{
    global $smtp;

    if ( !wi_mail_smtp_connect() )
        return false;

    if ( !$smtp->Mail( $from ) ) {
        $smtp->Reset();
        return false;
    }

    if ( !$smtp->Recipient( $to ) ) {
        $smtp->Reset();
        return false;
    }

    $headers = array();
    $headers[ 'Date' ] = date( 'r' );
    $headers[ 'Message-Id' ] = '<' . md5( uniqid( time() ) ) . strstr( $from, '@' ) . '>';
    $headers[ 'From' ] = $from;
    $headers[ 'Reply-To' ] = $from;
    $headers[ 'Sender' ] = $from;
    $headers[ 'Return-Path' ] = $from;
    $headers[ 'Errors-To' ] = $from;
    $headers[ 'To' ] = $to;
    $headers[ 'Subject' ] = $subject;
    $headers[ 'X-Mailer' ] = 'WebIssues Server';
    $headers[ 'MIME-Version' ] = '1.0';
    $headers[ 'Content-Type' ] = $content_type . '; charset=UTF-8';
    $headers[ 'Content-Transfer-Encoding' ] = '8Bit';

    $headers = wi_format_headers( $headers );

    if ( !$smtp->Data( $headers . "\n\n" . $body ) ) {
        $smtp->Reset();
        return false;
    }

    $smtp->Reset();
    return true;
}

function wi_mail_smtp_connect()
{
    global $config;
    global $smtp;

    if ( !empty( $smtp ) )
        return $smtp->Connected();

    $smtp = new SMTP();

    $host = $config[ 'smtp_host' ];
    if ( !empty( $config[ 'smtp_secure' ] ) )
        $host = $config[ 'smtp_secure' ] . '://' . $host;

    if ( !$smtp->Connect( $host, $config[ 'smtp_port' ] ) )
        return false;

    $smtp->Hello( $_SERVER[ 'SERVER_NAME' ] );

    if ( !empty( $config[ 'smtp_user' ] ) ) {
        if ( !$smtp->Authenticate( $config[ 'smtp_user' ], $config[ 'smtp_password' ] ) ) {
            wi_mail_smtp_close();
            return false;
        }
    }

    register_shutdown_function( 'wi_mail_smtp_close' );

    return true;
}

function wi_mail_smtp_close()
{
    global $smtp;

    if ( !empty( $smtp ) && $smtp->Connected() ) {
        $smtp->Quit();
        $smtp->Close();
    }
}

/*
* Code below is based on PHPMailer version 2.0.2
* http://phpmailer.sourceforge.net
* Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved.
* Copyright (c) 2001-2003, Brent R. Matzelle
* Distributed under the Lesser General Public License (LGPL)
*/

class SMTP
{
    var $CRLF = "\r\n";

    var $smtp_conn;

    function SMTP()
    {
        $this->smtp_conn = 0;
    }

    function Connect( $host, $port, $tval = 30 )
    {
        if ( $this->Connected() )
            return false;

        $this->smtp_conn = fsockopen( $host, $port, $errno, $errstr, $tval );

        if ( empty( $this->smtp_conn ) )
            return false;

        if ( substr( PHP_OS, 0, 3 ) != 'WIN' )
            socket_set_timeout( $this->smtp_conn, $tval, 0 );

        $announce = $this->get_lines();

        return true;
    }

    function Authenticate( $username, $password )
    {
        fputs( $this->smtp_conn, 'AUTH LOGIN' . $this->CRLF );

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

        if ( $code != 334 )
            return false;

        fputs( $this->smtp_conn, base64_encode( $username ) . $this->CRLF );

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

        if ( $code != 334 )
            return false;

        fputs( $this->smtp_conn, base64_encode( $password ) . $this->CRLF );

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

        if ( $code != 235 )
            return false;

        return true;
    }

    function Connected()
    {
        if ( !empty( $this->smtp_conn ) ) {
            $sock_status = socket_get_status( $this->smtp_conn );
            if ( $sock_status[ 'eof' ] ) {
                $this->Close();
                return false;
            }
            return true;
        }
        return false;
    }

    function Close()
    {
        if ( !empty( $this->smtp_conn ) ) {
            fclose( $this->smtp_conn );
            $this->smtp_conn = 0;
        }
    }

    function Data( $msg_data )
    {
        if ( !$this->Connected() )
            return false;

        fputs( $this->smtp_conn, 'DATA' . $this->CRLF );

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

        if ( $code != 354 )
            return false;

        $msg_data = str_replace( "\r\n", "\n", $msg_data );
        $msg_data = str_replace( "\r", "\n", $msg_data );
        $lines = explode( "\n", $msg_data );

        $field = substr( $lines[ 0 ], 0, strpos( $lines[ 0 ], ':' ) );
        $in_headers = false;
        if ( !empty( $field ) && !strstr( $field, ' ' ) )
            $in_headers = true;

        $max_line_length = 998;

        while ( list( , $line ) = @each( $lines ) ) {
            $lines_out = null;
            if ( $line == '' && $in_headers )
                $in_headers = false;

            while ( strlen( $line ) > $max_line_length ) {
                $pos = strrpos( substr( $line, 0, $max_line_length ), ' ' );

                if ( !$pos )
                    $pos = $max_line_length - 1;

                $lines_out[] = substr( $line, 0, $pos );
                $line = substr( $line, $pos + 1 );

                if ( $in_headers )
                    $line = "\t" . $line;
            }
            $lines_out[] = $line;

            while ( list( , $line_out ) = @each( $lines_out ) ) {
                if ( strlen( $line_out ) > 0 ) {
                    if ( substr( $line_out, 0, 1 ) == '.' )
                        $line_out = '.' . $line_out;
                }
                fputs( $this->smtp_conn, $line_out . $this->CRLF );
            }
        }

        fputs( $this->smtp_conn, $this->CRLF . '.' . $this->CRLF );

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

        if ( $code != 250 )
            return false;

        return true;
    }

    function Hello( $host )
    {
        if ( !$this->Connected() )
            return false;

        fputs( $this->smtp_conn, 'HELO ' . $host . $this->CRLF );

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

        if ( $code != 250 )
            return false;

        return true;
    }

    function Mail( $from )
    {
        if ( !$this->Connected() )
            return false;

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

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

        if ( $code != 250 )
            return false;

        return true;
    }

    function Quit()
    {
        if ( !$this->Connected() )
            return false;

        fputs( $this->smtp_conn, 'quit' . $this->CRLF );

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

        if ( $code != 221 )
            return false;

        return true;
    }

    function Recipient( $to )
    {
        if ( !$this->Connected() )
            return false;

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

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

        if ( $code != 250 && $code != 251 )
            return false;

        return true;
    }

    function Reset()
    {
        if ( !$this->Connected() )
            return false;

        fputs( $this->smtp_conn, 'RSET' . $this->CRLF );

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

        if ( $code != 250 )
            return false;

        return true;
    }

    function get_lines()
    {
        $data = '';
        while ( $str = @fgets( $this->smtp_conn, 515 ) ) {
            $data .= $str;
            if ( substr( $str, 3, 1 ) == ' ' )
                break;
        }
        return $data;
    }
}
