From 9e615429e9255185769f347197164a9269b5440a Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 21 Apr 2008 17:23:18 +0000 Subject: [PATCH] sms notifications from aleksander.adamowski(at)olo.org.pl --- notifications/inc/class.notifications.inc.php | 12 +- .../inc/class.notifications_sms.inc.php | 186 ++++++++++++++++++ notifications/templates/default/config.tpl | 2 - 3 files changed, 192 insertions(+), 8 deletions(-) create mode 100644 notifications/inc/class.notifications_sms.inc.php diff --git a/notifications/inc/class.notifications.inc.php b/notifications/inc/class.notifications.inc.php index ac4cb51efa..050c7b90ca 100644 --- a/notifications/inc/class.notifications.inc.php +++ b/notifications/inc/class.notifications.inc.php @@ -40,7 +40,7 @@ final class notifications { * registered backends * @var array */ - private $backends = array('popup', 'winpopup', 'email'); + private $backends = array('popup', 'winpopup', 'email', 'sms'); /** * pre-defined notificaton chains @@ -60,14 +60,14 @@ final class notifications { 'all' => false, // will be created by $this->get_available_chains 'popup_only' => array('popup' => 'stop'), 'popup_or_email' => array('popup' => 'fail', 'email' => 'stop'), - //'popup_or_sms' => array('popup' => 'fail', 'sms' => 'stop'), + 'popup_or_sms' => array('popup' => 'fail', 'sms' => 'stop'), 'popup_and_email' => array('popup' => 'continue', 'email' => 'stop'), 'popup_and_winpopup' => array('popup' => 'continue', 'winpopup' => 'stop'), 'winpopup_only' => array('winpopup' => 'stop'), 'winpopup_or_email' => array('winpopup' => 'fail', 'email' => 'stop'), //'winpopup_or_sms' => array('winpopup' => 'fail', 'sms' => 'stop'), 'winpopup_and_email' => array('winpopup' => 'continue', 'email' => 'stop'), - //'sms_only' => array('sms' => 'stop'), + 'sms_only' => array('sms' => 'stop'), ); /** @@ -80,14 +80,14 @@ final class notifications { 'all' => 'all possible notification backends', 'popup_only' => 'eGroupWare-Popup only', 'popup_or_email' => 'eGroupWare-Popup first, if that fails notify me by E-Mail', - //'popup_or_sms' => 'eGroupware-Popup first, if that fails notify me by SMS', + 'popup_or_sms' => 'eGroupware-Popup first, if that fails notify me by SMS', 'popup_and_email' => 'eGroupWare-Popup and E-Mail', 'popup_and_winpopup' => 'eGroupWare-Popup and Windows-Popup', 'winpopup_only' => 'Windows-Popup only', 'winpopup_or_email' => 'Windows-Popup first, if that fails notify me by E-Mail', //'winpopup_or_sms' => 'Windows-Popup first, if that fails notify me by SMS', 'winpopup_and_email' => 'Windows-Popup and E-Mail', - //'sms_only' => 'SMS only', + 'sms_only' => 'SMS only', ); /** @@ -590,4 +590,4 @@ final class notifications { return false; } -} \ No newline at end of file +} diff --git a/notifications/inc/class.notifications_sms.inc.php b/notifications/inc/class.notifications_sms.inc.php new file mode 100644 index 0000000000..2b456250b2 --- /dev/null +++ b/notifications/inc/class.notifications_sms.inc.php @@ -0,0 +1,186 @@ + + * @version $Id$ + */ + +/** + * User notification via winpopup. + */ +class notifications_sms implements notifications_iface { + + /** + * Appname + */ + const _appname = 'notifications'; + + /** + * Login table in SQL database + */ + const _login_table = 'egw_access_log'; + + /** + * holds account object for user who sends the message + * + * @var object + */ + private $sender; + + /** + * holds account object for user to notify + * + * @var object + */ + private $recipient; + + /** + * holds config object (sitewide application config) + * + * @var object + */ + private $config; + + /** + * holds preferences object of user to notify + * + * @var object + */ + private $preferences; + + /** + * holds the sms sending command. the script should accept two arguments: mobile number and + * SMS body in ASCII. + * + * @abstract + * Example: /usr/bin/sendsms + * (sendsms is from smstools) + * + * @var string + */ + private $sendsms_command = '/usr/sbin/sendsms'; + + /** + * constructor of notification_sms + * + * @param object $_sender + * @param object $_recipient + * @param object $_config + * @param object $_preferences + */ + public function __construct($_sender, $_recipient, $_config = null, $_preferences = null) { + if(!is_object($_sender)) { throw new Exception("no sender given."); } + if(!is_object($_recipient)) { throw new Exception("no recipient given."); } + $this->sender = $_sender; + $this->recipient = $_recipient; + $this->config = $_config; + $this->preferences = $_preferences; + } + + /** + * sends notification + * + * @param string $_subject + * @param array $_messages + * @param array $_attachments + */ + public function send(array $_messages, $_subject = false, $_links = false, $_attachments = false) { + if(!$this->sendsms_command) { + throw new Exception( 'SMS plugin not configured yet. Skipped sending notification message. '. + 'Please check var "sms_command" in SMS backend '. + '('.EGW_INCLUDE_ROOT. SEP. self::_appname. SEP. 'inc'. SEP. 'class.notification_sms.inc.php).'); + } + //error_log('_messages: '.var_export($_messages, TRUE)."\n"); + $this->send_sms( $_subject.$_messages['plain']); + return true; + } + + /** + * Try to guess a locale supported by the server, with fallback to 'en_EN' and 'C' + * borrowed from projectmanager/inc/class.ganttchart.inc.php + * + * @return string + */ + function guess_locale() { + $fullprefs = new preferences($this->recipient->account_id); + $fullpreferences = $fullprefs->read(); + $lang = $fullpreferences['common']['lang']; + $country = $fullpreferences['common']['country']; + + if (strlen($lang) == 2) { + $country_from_lang = strtoupper($lang); + } else { + list($lang,$country_from_lang) = explode('-',$lang); + $country_from_lang = strtoupper($country_from_lang); + } + $old_locale = setlocale(LC_CTYPE, '0'); + if (setlocale(LC_CTYPE,$locale=$lang.'_'.$country)) return $old_locale; + if (setlocale(LC_CTYPE,$locale=$lang.'_'.$country_from_lang)) return $old_locale; + if (setlocale(LC_CTYPE,$locale=$lang)) return $old_locale; + if (setlocale(LC_CTYPE,$locale='en_EN')) return $old_locale; + return $old_locale; + } + + /** + * sends the sms message via command line script specified above + * + * @param string $_message + * @param array $_user_sessions + */ + private function send_sms( $_message) { + $account_id = $this->recipient->account_id; + // Theoretically one could send unicode text SMS by using UCS-2 encoding for the message. + // My modem, however, rejected UCS-2 encoded text so I convert to plain ASCII: + if (function_exists('iconv')) { + $funcToUse = 'iconv'; + } else if (function_exists('mb_convert_encoding')) { + $funcToUse = 'mb_convert_encoding'; + } + $old_locale = $this->guess_locale(); + //error_log("New LC_CTYPE locale: ".setlocale(LC_CTYPE, '0')); + $source_charset = $GLOBALS['egw']->translation->charset(); + if ($funcToUse == 'iconv') { + $converted_message = iconv($source_charset, 'ASCII//TRANSLIT', $_message); + } else if ($funcToUse == 'mb_convert_encoding') { + $converted_message = mb_convert_encoding($_message, 'ASCII', $source_charset); + } + setlocale(LC_CTYPE, $old_locale); + //error_log("Restored old LC_CTYPE locale: ".setlocale(LC_CTYPE, '0')); + + $addressbook =& CreateObject('addressbook.bocontacts'); + $contact = $addressbook->read('account:'.$account_id); + $cell = $contact['tel_cell']; + // remove all characters that are non-digit and not a plus sign: + $cell = preg_replace('/[^0-9]/', '', $cell); + if (!preg_match('/48[^0][0-9]{8}/', $cell)) { + error_log('Invalid cell number: '.$cell); + throw new Exception("Failed sending notification message via sms. Invalid mobile number: ".$cell); + } + + $command = $this->sendsms_command; + // just in case to be sure of safeness: + $escaped_cell = escapeshellarg($cell); + $command .= ' '.$cell; + + // The first four rows of alarm message contain redundant text + // that's unneeded in SMS notifications, and space is precious, + // so we remove them: + // Or maybe not: + //$converted_message = preg_replace("/^([^\n]*\r?\n){4}/", "", $converted_message); + // SMS length limit of max. 3 SMS concatenated: + $converted_message = substr($converted_message, 0, 160*3); + // escape any dangerous content from the message: + $escaped_message = escapeshellarg($converted_message); + $command .= ' '.$escaped_message; + //error_log('SMS command: '.$command."\n"); + exec($command,$output,$returncode); + if($returncode != 0) { + throw new Exception("Failed sending notification message via sms. Error while executing the specified command."); + } + } + +} diff --git a/notifications/templates/default/config.tpl b/notifications/templates/default/config.tpl index fae52fd0d5..0728f68e7d 100644 --- a/notifications/templates/default/config.tpl +++ b/notifications/templates/default/config.tpl @@ -34,7 +34,6 @@ -