* @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 = new addressbook_bo(); $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."); } } }