#!/usr/bin/php -q
<?php
/**
 * Copyright (c) 2002-2006 Aurélien Maille
 * 
 * This file is part of Wanewsletter.
 * 
 * Wanewsletter 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.
 * 
 * Wanewsletter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Wanewsletter; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * 
 * @package Wanewsletter
 * @author  Bobe <wascripts@phpcodeur.net>
 * @link    http://phpcodeur.net/wascripts/wanewsletter/
 * @license http://www.gnu.org/copyleft/gpl.html  GNU General Public License
 * 
 * @status experimental
 * 
 * Ce module est marqué comme expérimental car son intégration dans Wanewsletter
 * n'est pas considérée comme étant satisfaisante, cependant, tous les tests
 * effectués ont été satisfaisant et la partie permettant les envois d'emails
 * notamment est considérée comme étant utilisable en "production".
 */

define('IN_NEWSLETTER',  true);
define('IN_COMMANDLINE', true);
define('ANSI_TERMINAL',  true);
define('WA_ROOTDIR',     dirname(dirname(__FILE__)));

//
// PHP CLI ne change pas le répertoire courant pour celui du script
//
if( php_sapi_name() != 'cli' )
{
	//
	// PHP en mode CGI ne rend pas disponible directement les variables
	// $argv et $argc si register_globals est sur Off
	//
	$argv = $_SERVER['argv'];
	$argc = $_SERVER['argc'];
}

if( preg_match('/\.UTF-?8/i', getenv('LANG')) ) // Au cas où le terminal utilise l'encodage utf-8
{
	function convert_output($data)
	{
		return wan_utf8_encode($data);
	}
	
	ob_start('convert_output', 1);
}

require WA_ROOTDIR . '/start.php';

load_settings();

$argv[0]  = basename($argv[0]);
$version  = WA_VERSION;
$emails   = array();
$format   = FORMAT_TEXTE;
$liste_id = null;
$message  = null;
$process_send = $process_subscribe = $import_mail = false;
$send_packet  = 400;
$send_delay   = 10;

if( $argc == 1 ) // Aucun argument fourni
{
	echo "Usage: $argv[0] [OPTION]...\n";
	echo "Pour en savoir davantage, faites: « $argv[0] --help ».\n";
	exit(0);
}

//
// En mode un email par abonné, on envoit tous les emails par défaut (avec une pause
// à intervalle régulier (voir plus haut)).
//
if( $nl_config['engine_send'] == ENGINE_UNIQ )
{
	$nl_config['emails_sended'] = 0;
}

for( $i = 1; $i < $argc; $i++ )
{
	//
	// Version du script et de PHP et SAPI utilisé
	//
	if( $argv[$i] == '--version' || $argv[$i] == '-v' )
	{
		echo "Wanewsletter $version with PHP " . phpversion() . " (" . php_sapi_name() . ")\n";
		exit(0);
	}
	
	//
	// Licence de Wanewsletter
	//
	else if( $argv[$i] == '--license' )
	{
		echo "Wanewsletter $version\n";
		echo "Copyright (c) 2002-2006 Aurélien Maille\n";
		echo "\n";
		
		if( preg_match('/^fr[_-]/', getenv('LANG')) )
		{
			echo <<<WANSHELL
Wanewsletter est un logiciel libre; vous pouvez le redistribuer ou le
modifier selon les termes de la License Publique Générale de GNU, publiée
par la Free Software Foundation; soit la version 2 de la Licence ou,
soit (selon vos préférences) toute version ultérieure.

Wanewsletter est distribué dans l'espoir qu'il soit utile,
mais AUCUNE garantie n'est donnée tant pour des raisons COMMERCIALES que
pour RÉPONDRE À UN BESOIN PARTICULIER.  Consultez la Licence
Publique Générale de GNU pour plus de détails.

Vous devriez avoir reçu copie de la Licence Publique Générale de GNU
avec Wanewsletter; sinon, écrivez à la Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


WANSHELL;
		}
		else
		{
			echo <<<WANSHELL
Wanewsletter 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.

Wanewsletter is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Wanewsletter; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


WANSHELL;
		}
		
		exit(0);
	}
	
	//
	// Aide succinte d'utilisation en ligne de commande
	//
	else if( $argv[$i] == '--help' || $argv[$i] == '-h' )
	{
		echo <<<WANSHELL
Usage: $argv[0] [options]

Envois:
  -pNUM, --process-send=NUM  Lance un envoi avec NUM un id de liste
  -lNUM, --limit=NUM   Limite à NUM le nombre d'emails envoyés
  -kNUM, --packet=NUM  Nombre d'envois maximum par flot (par défaut, 400)
  -dNUM, --delay=NUM   Durée en secondes entre les flots d'envois
                       (par défaut, 10).

Divers:
  --process-subscribe=NUM  Validation des inscriptions par email
  --import-mail=NUM        Importation d'emails avec NUM un id de liste
  --format=FORMAT          FORMAT peut prendre la valeur 'plain' ou 'html'
                           'text' et 'texte' sont acceptés comme
                           alternative à 'plain'.

Informations:
  -h, --help     Affiche la présente aide
  -v, --version  Affiche les informations de version
      --license  Affiche les informations de licence

Exemple d'importation d'emails :
  $argv[0] --import-mail=1 -- address1@domain.tld address2@domain.tld
  
La liste d'adresses peut également être fournie en entrée, les adresses
dans le fichier étant séparées par des caractères blancs (espace, tabulation
ou saut de ligne) :
  $argv[0] --import-mail=1 < /path/to/address_list


WANSHELL;
		exit(0);
	}
	
	//
	// Lancement d'un flôt d'envoi
	//
	else if( preg_match('/^-(?:-process-send=|p)(\d+)$/', $argv[$i], $match) )
	{
		$process_send = true;
		$liste_id = $match[1];
	}
	
	//
	// Validation des inscriptions par email
	//
	else if( preg_match('/^--process-subscribe=(\d+)$/', $argv[$i], $match) )
	{
		$process_subscribe = true;
		$liste_id = $match[1];
	}
	
	//
	// Limitation du nombre d'envois
	//
	else if( preg_match('/^-(?:-limit=|l)(\d+)$/', $argv[$i], $match) )
	{
		$nl_config['emails_sended'] = $match[1];
	}
	
	//
	// Nombre d'envois maximum à effectuer lors d'un flot d'envois
	//
	else if( preg_match('/^-(?:-packet=|k)(\d+)$/', $argv[$i], $match) )
	{
		$send_packet = $match[1];
	}
	
	//
	// Nombre d'envois maximum à effectuer lors d'un flot d'envois
	//
	else if( preg_match('/^-(?:-delay=|d)(\d+)$/', $argv[$i], $match) )
	{
		$send_delay = $match[1];
	}
	
	else if( preg_match('/^--import-mail=(\d+)$/', $argv[$i], $match) )
	{
		$import_mail = true;
		$liste_id = $match[1];
	}
	
	//
	// Format choisi pour les comptes des adresses emails importées
	//
	else if( preg_match('/^--format=/', $argv[$i], $match) )
	{
		$format = substr($argv[$i], 9);
		
		if( in_array($format, array('plain', 'text', 'texte')) )
		{
			$format = FORMAT_TEXTE;
		}
		else if( $format == 'html' )
		{
			$format = FORMAT_HTML;
		}
		else
		{
			trigger_error("Bad format. Possible values are 'plain', 'text', 'texte' or 'html'", CRITICAL_ERROR);
		}
	}
	
	//
	// Récupération des adresses email passées dans la ligne de commande
	//
	else if( $argv[$i] == '--' )
	{
		if( isset($argv[++$i]) )
		{
			$emails = array_slice($argv, $i);
		}
	}
}

if( !is_null($liste_id) )
{
	$sql = 'SELECT liste_id, liste_format, sender_email, liste_alias, limitevalidate,
			liste_name, form_url, return_email, liste_sig, use_cron, confirm_subscribe,
			pop_host, pop_port, pop_user, pop_pass
		FROM ' . LISTE_TABLE . ' 
		WHERE liste_id = ' . $liste_id;
	if( !($result = $db->query($sql)) )
	{
		trigger_error('Impossible de récupérer les informations sur cette liste', CRITICAL_ERROR);
	}
	
	if( !($listdata = $result->fetch()) )
	{
		trigger_error('Unknown_list', CRITICAL_ERROR);
	}
}

if( $process_send == true )
{
	define('SEND_PACKET', $send_packet);
	define('SEND_DELAY',  $send_delay);
	
	require WA_ROOTDIR . '/includes/engine_send.php';
	
	$sql = "SELECT log_id, log_subject, log_body_text, log_body_html, log_status
		FROM " . LOG_TABLE . "
		WHERE liste_id = $listdata[liste_id]
			AND log_status = " . STATUS_STANDBY . "
		LIMIT 1 OFFSET 0";
	if( !($result = $db->query($sql)) ) // on récupère le dernier log en statut d'envoi
	{
		trigger_error('Impossible d\'obtenir les données sur ce log', CRITICAL_ERROR);
	}
	
	if( !($logdata = $result->fetch()) )
	{
		echo $lang['Message']['No_log_to_send'] . "\n";
		exit(0);
	}
	
	$sql = "SELECT jf.file_id, jf.file_real_name, jf.file_physical_name, jf.file_size, jf.file_mimetype
		FROM " . JOINED_FILES_TABLE . " AS jf
			INNER JOIN " . LOG_FILES_TABLE . " AS lf ON lf.file_id = jf.file_id
			INNER JOIN " . LOG_TABLE . " AS l ON l.log_id = lf.log_id
				AND l.liste_id = $listdata[liste_id]
				AND l.log_id   = $logdata[log_id]
		ORDER BY jf.file_real_name ASC";
	if( !($result = $db->query($sql)) )
	{
		trigger_error('Impossible d\'obtenir la liste des fichiers joints', CRITICAL_ERROR);
	}
	
	$logdata['joined_files'] = $result->fetchAll();
	
	//
	// On lance l'envoi
	//
	$message = launch_sending($listdata, $logdata);
	
	echo "\n";
}
else if( $process_subscribe )
{
	require WAMAILER_DIR . '/class.mailer.php';
	require WAMAILER_DIR . '/class.pop.php';
	require WA_ROOTDIR . '/includes/class.form.php';
	require WA_ROOTDIR . '/includes/functions.validate.php';
	include WA_ROOTDIR . '/includes/functions.stats.php';
	
	//
	// Initialisation de la classe mailer
	//
	$mailer = new Mailer(WA_ROOTDIR . '/language/email_' . $nl_config['language'] . '/');
	
	if( $nl_config['use_smtp'] )
	{
		$mailer->smtp_path = WAMAILER_DIR . '/';
		$mailer->use_smtp(
			$nl_config['smtp_host'],
			$nl_config['smtp_port'],
			$nl_config['smtp_user'],
			$nl_config['smtp_pass']
		);
	}
	
	$mailer->set_charset($lang['CHARSET']);
	$mailer->set_format(FORMAT_TEXTE);
	$mailer->set_from($listdata['sender_email'], wan_html_entity_decode($listdata['liste_name']));
	
	if( $listdata['return_email'] != '' )
	{
		$mailer->set_return_path($listdata['return_email']);
	}
	
	$wan = new Wanewsletter($listdata);
	$pop = new Pop();
	$pop->connect($listdata['pop_host'], $listdata['pop_port'], $listdata['pop_user'], $listdata['pop_pass']);
	
	$total    = $pop->stat_box();
	$mail_box = $pop->list_mail();
	
	foreach( $mail_box as $mail_id => $mail_size )
	{
		$headers = $pop->parse_headers($mail_id);
		
		if( !isset($headers['from']) || !preg_match('/^(?:"?([^"]*?)"?)?[ ]*(?:<)?([^> ]+)(?:>)?$/i', $headers['from'], $match) )
		{
			continue;
		}
		
		$pseudo = ( isset($match[1]) ) ? strip_tags(trim($match[1])) : '';
		$email  = trim($match[2]);
		
		if( !isset($headers['to']) || !stristr($headers['to'], $wan->liste_email) )
		{
			continue;
		}
		
		if( !isset($headers['subject']) )
		{
			continue;
		}
		
		$action = strtolower(trim($headers['subject']));
		
		switch( $action )
		{
			case 'desinscription':
			case 'désinscription':
			case 'unsubscribe':
				$action = 'desinscription';
				break;
			
			case 'inscription':
			case 'subscribe':
				$action = 'inscription';
				break;
			
			case 'confirmation':
			case 'setformat':
				break;
			
			default:
				$pop->delete_mail($mail_id);
				continue 2;
				break;
		}
		
		$code = $pop->contents[$mail_id]['message'];
		if( strlen($code) == 32 ) // Compatibilité avec versions < 2.3
		{
			$code = substr($code, 0, 20);
		}
		
		if( $action == 'inscription' || $action == 'setformat' || ($action == 'desinscription' && empty($code)) )
		{
			$wan->do_action($action, $email);
		}
		else
		{
			if( empty($headers['date']) || intval($time = strtotime($headers['date'])) > 0 )
			{
				$time = time();
			}
			
			$wan->check_code($code, $time);
		}
		
		//
		// On supprime l'email maintenant devenu inutile
		//
		$pop->delete_mail($mail_id);
	}//end for
	
	$pop->quit();
	
	$message = $lang['Message']['Success_operation'];
}
else if( $import_mail == true )
{
	require WAMAILER_DIR . '/class.mailer.php';
	
	if( count($emails) == 0 )
	{
		$emails = '';
		while( !feof(STDIN) )
		{
			$emails .= fgets(STDIN);
		}
		
		$emails = preg_split('/\s+/', trim($emails));
	}
	
	if( count($emails) == 0 )
	{
		
	}
	
	$emails = array_unique($emails);
	$current_time = time();
	$emails_ok    = array();
	
	if( $listdata['liste_format'] != FORMAT_MULTIPLE )
	{
		$format = $listdata['liste_format'];
	}
	
	//
	// Vérification syntaxique des emails
	//
	$emails = array_filter($emails, create_function('$email',
		'global $lang;
		
		if( Mailer::validate_email($email) ) {
			return true;
		} else {
			printf("%s : %s\n", $email, $lang[\'Message\'][\'Invalid_email2\']);
			return false;
		}'
	));
	
	if( count($emails) > 0 )
	{
		$counter = 0;
		$sql_emails = array_map(create_function('$email',
			'return $GLOBALS["db"]->escape(strtolower($email));'), $emails);
		
		$sql = "SELECT a.abo_id, a.abo_email, a.abo_status, al.confirmed
			FROM " . ABONNES_TABLE . " AS a
				LEFT JOIN " . ABO_LISTE_TABLE . " AS al ON al.abo_id = a.abo_id
					AND al.liste_id = $listdata[liste_id]
			WHERE LOWER(a.abo_email) IN('" . implode("', '", $sql_emails) . "')";
		if( !($result = $db->query($sql)) )
		{
			trigger_error('Impossible de tester les tables d\'inscriptions', CRITICAL_ERROR);
		}
		
		//
		// Traitement des adresses email déjà présentes dans la base de données
		//
		while( $abodata = $result->fetch() )
		{
			if( !isset($abodata['confirmed']) ) // N'est pas inscrit à cette liste
			{
				$sql_data = array();
				$sql_data['abo_id']        = $abodata['abo_id'];
				$sql_data['liste_id']      = $listdata['liste_id'];
				$sql_data['format']        = $format;
				$sql_data['register_key']  = generate_key(20, false);
				$sql_data['register_date'] = $current_time;
				$sql_data['confirmed']     = ($abodata['abo_status'] == ABO_ACTIF) ? SUBSCRIBE_CONFIRMED : SUBSCRIBE_NOT_CONFIRMED;
				
				if( !$db->build(SQL_INSERT, ABO_LISTE_TABLE, $sql_data) )
				{
					trigger_error('Impossible d\'insérer une nouvelle entrée dans la table abo_liste', CRITICAL_ERROR);
				}
				
				$counter++;
			}
			else
			{
				printf("%s : %s\n", $abodata['abo_email'], $lang['Message']['Allready_reg']);
			}
			
			array_push($emails_ok, $abodata['abo_email']);
		}
		
		//
		// Traitement des adresses email inconnues
		//
		@include 'PHP/Compat/Function/array_udiff.php';// partie du module PEAR PHP_Compat
		
		if( function_exists('array_udiff') )
		{
			$emails = array_udiff($emails, $emails_ok, 'strcasecmp');
		}
		else
		{
			$emails = array_diff($emails, $emails_ok);
		}
		
		foreach( $emails as $email )
		{
			$db->beginTransaction();
			
			$sql_data = array();
			$sql_data['abo_email']  = $email;
			$sql_data['abo_status'] = ABO_ACTIF;
			
			if( !$db->build(SQL_INSERT, ABONNES_TABLE, $sql_data) )
			{
				printf("%s : SQL error (#%d: %s)\n", $email, $db->errno, $db->error);
				$db->rollBack();
				continue;
			}
			
			$sql_data = array();
			$sql_data['abo_id']        = $db->lastInsertId();
			$sql_data['liste_id']      = $listdata['liste_id'];
			$sql_data['format']        = $format;
			$sql_data['register_key']  = generate_key(20, false);
			$sql_data['register_date'] = $current_time;
			$sql_data['confirmed']     = SUBSCRIBE_CONFIRMED;
			
			if( !$db->build(SQL_INSERT, ABO_LISTE_TABLE, $sql_data) )
			{
				trigger_error('Impossible d\'insérer une nouvelle entrée dans la table abo_liste', CRITICAL_ERROR);
			}
			
			$counter++;
			$db->commit();
		}
		
		if( $counter > 1 )
		{
			$message = sprintf($lang['Message']['Success_import4_n'], $counter);
		}
		else if( $counter == 1 )
		{
			$message = sprintf($lang['Message']['Success_import4_1'], $counter);
		}
		else
		{
			$message = $lang['Message']['Success_import4_0'];
		}
	}
}

if( !is_null($message) )
{
	echo strip_tags($message), "\n";
}

exit(0);


