public function create_identity($p) { $rcmail = rcmail::get_instance(); // prefs are set in create_user() if ($this->prefs) { if ($this->prefs['full_name']) { $p['record']['name'] = $this->prefs['full_name']; } if (($this->identities_level == 0 || $this->identities_level == 2) && $this->prefs['email_address']) { $p['record']['email'] = $this->prefs['email_address']; } if ($this->prefs['___signature___']) { $p['record']['signature'] = $this->prefs['___signature___']; } if ($this->prefs['reply_to']) { $p['record']['reply-to'] = $this->prefs['reply_to']; } if (($this->identities_level == 0 || $this->identities_level == 1) && isset($this->prefs['identities']) && $this->prefs['identities'] > 1) { for ($i = 1; $i < $this->prefs['identities']; $i++) { unset($ident_data); $ident_data = array('name' => '', 'email' => ''); // required data if ($this->prefs['full_name' . $i]) { $ident_data['name'] = $this->prefs['full_name' . $i]; } if ($this->identities_level == 0 && $this->prefs['email_address' . $i]) { $ident_data['email'] = $this->prefs['email_address' . $i]; } else { $ident_data['email'] = $p['record']['email']; } if ($this->prefs['reply_to' . $i]) { $ident_data['reply-to'] = $this->prefs['reply_to' . $i]; } if ($this->prefs['___sig' . $i . '___']) { $ident_data['signature'] = $this->prefs['___sig' . $i . '___']; } // insert identity $identid = $rcmail->user->insert_identity($ident_data); } } // copy address book $contacts = $rcmail->get_address_book(null, true); if ($contacts && count($this->abook)) { foreach ($this->abook as $rec) { // #1487096 handle multi-address and/or too long items $rec['email'] = array_shift(explode(';', $rec['email'])); if (check_email(rcube_idn_to_ascii($rec['email']))) { $rec['email'] = rcube_idn_to_utf8($rec['email']); $contacts->insert($rec, true); } } } // mark identity as complete for following hooks $p['complete'] = true; } return $p; }
/** * Callback function when HTML page is rendered * We'll add an overlay box here. */ function render_page($p) { if ($_SESSION['plugin.newuserdialog'] && $p['template'] == 'mail') { $this->add_texts('localization'); $rcmail = rcmail::get_instance(); $identity = $rcmail->user->get_identity(); $identities_level = intval($rcmail->config->get('identities_level', 0)); // compose user-identity dialog $table = new html_table(array('cols' => 2)); $table->add('title', $this->gettext('name')); $table->add(null, html::tag('input', array('type' => 'text', 'name' => '_name', 'value' => $identity['name']))); $table->add('title', $this->gettext('email')); $table->add(null, html::tag('input', array('type' => 'text', 'name' => '_email', 'value' => rcube_idn_to_utf8($identity['email']), 'disabled' => $identities_level == 1 || $identities_level == 3))); $table->add('title', $this->gettext('organization')); $table->add(null, html::tag('input', array('type' => 'text', 'name' => '_organization', 'value' => $identity['organization']))); $table->add('title', $this->gettext('signature')); $table->add(null, html::tag('textarea', array('name' => '_signature', 'rows' => '3'), $identity['signature'])); // add overlay input box to html page $rcmail->output->add_footer(html::div(array('id' => 'newuseroverlay'), html::tag('form', array('action' => $rcmail->url('plugin.newusersave'), 'method' => 'post'), html::tag('h3', null, Q($this->gettext('identitydialogtitle'))) . html::p('hint', Q($this->gettext('identitydialoghint'))) . $table->show() . html::p(array('class' => 'formbuttons'), html::tag('input', array('type' => 'submit', 'class' => 'button mainaction', 'value' => $this->gettext('save'))))))); // disable keyboard events for messages list (#1486726) $rcmail->output->add_script("rcmail.message_list.key_press = function(){};\n rcmail.message_list.key_down = function(){};\n \$('input[name=_name]').focus();\n ", 'docready'); $this->include_stylesheet('newuserdialog.css'); } }
function save($curpass, $passwd) { $rcmail = rcmail::get_instance(); if (!($sql = $rcmail->config->get('password_query'))) { $sql = 'SELECT update_passwd(%c, %u)'; } if ($dsn = $rcmail->config->get('password_db_dsn')) { // #1486067: enable new_link option if (is_array($dsn) && empty($dsn['new_link'])) { $dsn['new_link'] = true; } else { if (!is_array($dsn) && !preg_match('/\\?new_link=true/', $dsn)) { $dsn .= '?new_link=true'; } } $db = rcube_db::factory($dsn, '', false); $db->set_debug((bool) $rcmail->config->get('sql_debug')); $db->db_connect('w'); } else { $db = $rcmail->get_dbh(); } if ($err = $db->is_error()) { return PASSWORD_ERROR; } // crypted password if (strpos($sql, '%c') !== FALSE) { $salt = ''; if (!($crypt_hash = $rcmail->config->get('password_crypt_hash'))) { if (CRYPT_MD5) { $crypt_hash = 'md5'; } else { if (CRYPT_STD_DES) { $crypt_hash = 'des'; } } } switch ($crypt_hash) { case 'md5': $len = 8; $salt_hashindicator = '$1$'; break; case 'des': $len = 2; break; case 'blowfish': $len = 22; $salt_hashindicator = '$2a$'; break; case 'sha256': $len = 16; $salt_hashindicator = '$5$'; break; case 'sha512': $len = 16; $salt_hashindicator = '$6$'; break; default: return PASSWORD_CRYPT_ERROR; } //Restrict the character set used as salt (#1488136) $seedchars = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; for ($i = 0; $i < $len; $i++) { $salt .= $seedchars[rand(0, 63)]; } $sql = str_replace('%c', $db->quote(crypt($passwd, $salt_hashindicator ? $salt_hashindicator . $salt . '$' : $salt)), $sql); } // dovecotpw if (strpos($sql, '%D') !== FALSE) { if (!($dovecotpw = $rcmail->config->get('password_dovecotpw'))) { $dovecotpw = 'dovecotpw'; } if (!($method = $rcmail->config->get('password_dovecotpw_method'))) { $method = 'CRAM-MD5'; } // use common temp dir $tmp_dir = $rcmail->config->get('temp_dir'); $tmpfile = tempnam($tmp_dir, 'roundcube-'); $pipe = popen("{$dovecotpw} -s '{$method}' > '{$tmpfile}'", "w"); if (!$pipe) { unlink($tmpfile); return PASSWORD_CRYPT_ERROR; } else { fwrite($pipe, $passwd . "\n", 1 + strlen($passwd)); usleep(1000); fwrite($pipe, $passwd . "\n", 1 + strlen($passwd)); pclose($pipe); $newpass = trim(file_get_contents($tmpfile), "\n"); if (!preg_match('/^\\{' . $method . '\\}/', $newpass)) { return PASSWORD_CRYPT_ERROR; } if (!$rcmail->config->get('password_dovecotpw_with_method')) { $newpass = trim(str_replace('{' . $method . '}', '', $newpass)); } unlink($tmpfile); } $sql = str_replace('%D', $db->quote($newpass), $sql); } // hashed passwords if (preg_match('/%[n|q]/', $sql)) { if (!extension_loaded('hash')) { raise_error(array('code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Password plugin: 'hash' extension not loaded!"), true, false); return PASSWORD_ERROR; } if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) { $hash_algo = 'sha1'; } $hash_passwd = hash($hash_algo, $passwd); $hash_curpass = hash($hash_algo, $curpass); if ($rcmail->config->get('password_hash_base64')) { $hash_passwd = base64_encode(pack('H*', $hash_passwd)); $hash_curpass = base64_encode(pack('H*', $hash_curpass)); } $sql = str_replace('%n', $db->quote($hash_passwd, 'text'), $sql); $sql = str_replace('%q', $db->quote($hash_curpass, 'text'), $sql); } // Handle clear text passwords securely (#1487034) $sql_vars = array(); if (preg_match_all('/%[p|o]/', $sql, $m)) { foreach ($m[0] as $var) { if ($var == '%p') { $sql = preg_replace('/%p/', '?', $sql, 1); $sql_vars[] = (string) $passwd; } else { // %o $sql = preg_replace('/%o/', '?', $sql, 1); $sql_vars[] = (string) $curpass; } } } $local_part = $rcmail->user->get_username('local'); $domain_part = $rcmail->user->get_username('domain'); $username = $_SESSION['username']; $host = $_SESSION['imap_host']; // convert domains to/from punnycode if ($rcmail->config->get('password_idn_ascii')) { $domain_part = rcube_idn_to_ascii($domain_part); $username = rcube_idn_to_ascii($username); $host = rcube_idn_to_ascii($host); } else { $domain_part = rcube_idn_to_utf8($domain_part); $username = rcube_idn_to_utf8($username); $host = rcube_idn_to_utf8($host); } // at least we should always have the local part $sql = str_replace('%l', $db->quote($local_part, 'text'), $sql); $sql = str_replace('%d', $db->quote($domain_part, 'text'), $sql); $sql = str_replace('%u', $db->quote($username, 'text'), $sql); $sql = str_replace('%h', $db->quote($host, 'text'), $sql); $res = $db->query($sql, $sql_vars); if (!$db->is_error()) { if (strtolower(substr(trim($sql), 0, 6)) == 'select') { if ($result = $db->fetch_array($res)) { return PASSWORD_SUCCESS; } } else { // This is the good case: 1 row updated if ($db->affected_rows($res) == 1) { return PASSWORD_SUCCESS; } // @TODO: Some queries don't affect any rows // Should we assume a success if there was no error? } } return PASSWORD_ERROR; }
/** * GUI object 'username' * Showing IMAP username of the current session * * @param array Named tag parameters (currently not used) * @return string HTML code for the gui object */ public function current_username($attrib) { static $username; // alread fetched if (!empty($username)) { return $username; } // Current username is an e-mail address if (strpos($_SESSION['username'], '@')) { $username = $_SESSION['username']; } else { if ($sql_arr = $this->app->user->get_identity()) { $username = $sql_arr['email']; } else { $username = $this->app->user->get_username(); } } return rcube_idn_to_utf8($username); }
/** * Handler for POST request to import an event attached to a mail message */ public function mail_import_event() { $uid = get_input_value('_uid', RCUBE_INPUT_POST); $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); $mime_id = get_input_value('_part', RCUBE_INPUT_POST); $status = get_input_value('_status', RCUBE_INPUT_POST); $delete = intval(get_input_value('_del', RCUBE_INPUT_POST)); $charset = RCMAIL_CHARSET; // establish imap connection $imap = $this->rc->get_storage(); $imap->set_mailbox($mbox); if ($uid && $mime_id) { list($mime_id, $index) = explode(':', $mime_id); $part = $imap->get_message_part($uid, $mime_id); if ($part->ctype_parameters['charset']) { $charset = $part->ctype_parameters['charset']; } $headers = $imap->get_message_headers($uid); } $events = $this->get_ical()->import($part, $charset); $error_msg = $this->gettext('errorimportingevent'); $success = false; // successfully parsed events? if (!empty($events) && ($event = $events[$index])) { // find writeable calendar to store event $cal_id = !empty($_REQUEST['_calendar']) ? get_input_value('_calendar', RCUBE_INPUT_POST) : null; $calendar = null; if (!$cal_id) { $calendar = $this->get_default_calendar(true); $cal_id = $calendar['id']; } if ($cal_id < 0) { foreach ($this->get_calendars() as $cal_id => $calendar) { $cal_id = $calendar['id']; $driver = $this->get_driver_by_cal($cal_id); $old_event = $driver->get_event($events[0]['uid']); if (is_array($old_event)) { $cal_id = $old_event['calendar']; break; } } } // Begin mod by Rosali (try to find the corresponding calendar) if (is_numeric($cal_id)) { $driver = $this->get_driver_by_cal($cal_id); } else { $error_msg = $this->gettext('nowritecalendarfound'); $this->rc->output->command('display_message', $error_msg, 'error'); $this->rc->output->send(); return false; } // End mod by Rosali // Begin mod by Rosali (handle tasks) $create_method = 'new_event'; $edit_method = 'edit_event'; $get_method = 'get_event'; // End mod by Rosali if (!$calendar) { $calendars = $driver->list_calendars(false, true); $calendar = $calendars[$cal_id] ?: $this->get_default_calendar(true); } // Begin mod by Rosali (handle tasks) if ($event['_type'] == 'task') { //database or caldav? $class_name = get_class($driver); $create_method = 'create_task'; $edit_method = 'edit_task'; $get_method = 'get_task'; require_once INSTALL_PATH . 'plugins/libgpl/tasklist/drivers/tasklist_driver.php'; if ($class_name == 'database_driver') { require_once INSTALL_PATH . 'plugins/libgpl/tasklist/drivers/database/tasklist_database_driver.php'; $driver = new tasklist_database_driver($this); } else { if ($class_name == 'caldav_driver') { require_once INSTALL_PATH . 'plugins/libgpl/tasklist/drivers/caldav/tasklist_caldav_driver.php'; $driver = new tasklist_caldav_driver($this); } else { $error_msg = $this->gettext('errorimportingtask'); $this->rc->output->command('display_message', $error_msg, 'error'); $this->rc->output->send(); } } } // update my attendee status according to submitted method if (!empty($status) && $event['_type'] == 'event') { // End by Rosali (no iTip support for tasks yet) $organizer = null; $emails = $this->get_user_emails(); foreach ($event['attendees'] as $i => $attendee) { if ($attendee['role'] == 'ORGANIZER') { $organizer = $attendee; } else { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { $event['attendees'][$i]['status'] = strtoupper($status); $reply_sender = $attendee['email']; } } } } // save to calendar if ($calendar && !$calendar['readonly']) { $event['calendar'] = $calendar['id']; // check for existing event with the same UID $existing = $driver->{$get_method}($event['uid'], true, false, true); // Begin mod by Rosali (no iTip support for tasks yet) if ($event['_type'] == 'task') { if ($existing) { $event['id'] = $existing['id']; $event['list'] = $event['calendar']; $existing['list'] = $event['calendar']; $existing_modified = $existing['changed']->format('U'); $event_modified = $event['changed']->format('U'); if ($existing_modified >= $event_modified) { $message = 'newerversionexists'; $msgtype = 'error'; } else { if ($event['start']) { $event['startdate'] = $event['start']->format('Y-m-d'); $event['starttime'] = $event['start']->format('H:i:s'); } if ($event['due']) { $event['date'] = $event['due']->format('Y-m-d'); $event['time'] = $event['due']->format('H:i:s'); } if ($success = $driver->{$edit_method}($event, $existing)) { $message = 'importedsuccessfully'; $msgtype = 'confirmation'; } else { $message = $error_msg; $msgtype = 'error'; } } } else { $event['list'] = $event['calendar']; if ($event['start']) { $event['startdate'] = $event['start']->format('Y-m-d'); $event['starttime'] = $event['start']->format('H:i:s'); } if ($event['due']) { $event['date'] = $event['due']->format('Y-m-d'); $event['time'] = $event['due']->format('H:i:s'); } if ($success = $driver->{$create_method}($event)) { $message = 'importedsuccessfully'; $msgtype = 'confirmation'; } else { $message = $error_msg; $msgtype = 'error'; } } $this->rc->output->command('display_message', $this->gettext(array('name' => $message, 'vars' => array('calendar' => $calendar['name']))), $msgtype); $this->rc->output->send(); } // End mod by Rosali if ($existing) { // Mod by Rosali (no iTip support for tasks yet) // only update attendee status if ($this->ical->method == 'REPLY') { // try to identify the attendee using the email sender address $sender = preg_match('/([a-z0-9][a-z0-9\\-\\.\\+\\_]*@[^&@"\'.][^@&"\']*\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,}))/', $headers->from, $m) ? $m[1] : ''; $sender_utf = rcube_idn_to_utf8($sender); $existing_attendee = -1; foreach ($existing['attendees'] as $i => $attendee) { if ($sender && ($attendee['email'] == $sender || $attendee['email'] == $sender_utf)) { $existing_attendee = $i; break; } } $event_attendee = null; foreach ($event['attendees'] as $attendee) { if ($sender && ($attendee['email'] == $sender || $attendee['email'] == $sender_utf)) { $event_attendee = $attendee; break; } } // found matching attendee entry in both existing and new events if ($existing_attendee >= 0 && $event_attendee) { $existing['attendees'][$existing_attendee] = $event_attendee; $success = $driver->edit_event($existing); } else { if ($event['changed'] >= $existing['changed'] && $event['attendees']) { $existing['attendees'] = $event['attendees']; $success = $driver->edit_event($existing); } else { $error_msg = $this->gettext('newerversionexists'); } } } else { if ($status == 'declined' && $delete) { $deleted = $driver->remove_event($existing, true); $success = true; } else { if ($event['sequence'] >= $existing['sequence'] || $event['changed'] >= $existing['changed']) { $event['id'] = $existing['id']; $event['calendar'] = $existing['calendar']; if ($status == 'declined') { // show me as free when declined (#1670) $event['free_busy'] = 'free'; } $success = $driver->edit_event($event); } else { if (!empty($status)) { $existing['attendees'] = $event['attendees']; if ($status == 'declined') { // show me as free when declined (#1670) $existing['free_busy'] = 'free'; } $success = $driver->edit_event($existing); } else { $error_msg = $this->gettext('newerversionexists'); } } } } } else { if (!$existing && $status != 'declined') { $success = $driver->{$create_method}($event); } else { if ($status == 'declined') { $error_msg = null; } } } } else { if ($status == 'declined') { $error_msg = null; } else { $error_msg = $this->gettext('nowritecalendarfound'); } } } if ($success) { $message = $this->ical->method == 'REPLY' ? 'attendeupdateesuccess' : ($deleted ? 'successremoval' : 'importedsuccessfully'); $this->rc->output->command('display_message', $this->gettext(array('name' => $message, 'vars' => array('calendar' => $calendar['name']))), 'confirmation'); $this->rc->output->command('plugin.fetch_event_rsvp_status', array('uid' => $event['uid'], 'changed' => is_object($event['changed']) ? $event['changed']->format('U') : 0, 'sequence' => intval($event['sequence']), 'fallback' => strtoupper($status))); $error_msg = null; } else { if ($error_msg) { $this->rc->output->command('display_message', $error_msg, 'error'); } } // Begin mod by Rosali (make the event accessible by GUI) $this->rc->output->command('plugin.event_callback', array('task' => $this->rc->task, 'action' => $this->rc->action, 'evt' => $this->_client_event($event))); // End mod by Rosali // send iTip reply if ($this->ical->method == 'REQUEST' && $organizer && !in_array(strtolower($organizer['email']), $emails) && !$error_msg) { $itip = $this->load_itip(); $itip->set_sender_email($reply_sender); if ($itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status)) { $this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation'); } else { $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); } } $this->rc->output->send(); }
/** * Handler for request action */ function save_vcard() { $this->add_texts('localization', true); $uid = get_input_value('_uid', RCUBE_INPUT_POST); $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); $mime_id = get_input_value('_part', RCUBE_INPUT_POST); $rcmail = rcmail::get_instance(); $storage = $rcmail->get_storage(); $storage->set_folder($mbox); if ($uid && $mime_id) { list($mime_id, $index) = explode(':', $mime_id); $part = $storage->get_message_part($uid, $mime_id, null, null, null, true); } $error_msg = $this->gettext('vcardsavefailed'); if ($part && ($vcards = rcube_vcard::import($part)) && ($vcard = $vcards[$index]) && $vcard->displayname && $vcard->email) { $CONTACTS = $this->get_address_book(); $email = $vcard->email[0]; $contact = $vcard->get_assoc(); $valid = true; // skip entries without an e-mail address or invalid if (empty($email) || !$CONTACTS->validate($contact, true)) { $valid = false; } else { // We're using UTF8 internally $email = rcube_idn_to_utf8($email); // compare e-mail address $existing = $CONTACTS->search('email', $email, 1, false); // compare display name if (!$existing->count && $vcard->displayname) { $existing = $CONTACTS->search('name', $vcard->displayname, 1, false); } if ($existing->count) { $rcmail->output->command('display_message', $this->gettext('contactexists'), 'warning'); $valid = false; } } if ($valid) { $plugin = $rcmail->plugins->exec_hook('contact_create', array('record' => $contact, 'source' => null)); $contact = $plugin['record']; if (!$plugin['abort'] && $CONTACTS->insert($contact)) { $rcmail->output->command('display_message', $this->gettext('addedsuccessfully'), 'confirmation'); } else { $rcmail->output->command('display_message', $error_msg, 'error'); } } } else { $rcmail->output->command('display_message', $error_msg, 'error'); } $rcmail->output->send(); }
/** * Helper function to build a Mail_mime object to send an iTip message * * @param array Event object to send * @param string iTip method (REQUEST|REPLY|CANCEL) * @return object Mail_mime object with message data */ public function compose_itip_message($event, $method) { $from = rcube_idn_to_ascii($this->sender['email']); $from_utf = rcube_idn_to_utf8($from); $sender = format_email_recipient($from, $this->sender['name']); // truncate list attendees down to the recipient of the iTip Reply. // constraints for a METHOD:REPLY according to RFC 5546 if ($method == 'REPLY') { $replying_attendee = null; $reply_attendees = array(); foreach ($event['attendees'] as $attendee) { if ($attendee['role'] == 'ORGANIZER') { $reply_attendees[] = $attendee; } else { if (strcasecmp($attedee['email'], $from) == 0 || strcasecmp($attendee['email'], $from_utf) == 0) { $replying_attendee = $attendee; } } } if ($replying_attendee) { $reply_attendees[] = $replying_attendee; $event['attendees'] = $reply_attendees; } } // compose multipart message using PEAR:Mail_Mime $message = new Mail_mime("\r\n"); $message->setParam('text_encoding', 'quoted-printable'); $message->setParam('head_encoding', 'quoted-printable'); $message->setParam('head_charset', RCMAIL_CHARSET); $message->setParam('text_charset', RCMAIL_CHARSET . ";\r\n format=flowed"); $message->setContentType('multipart/alternative'); // compose common headers array $headers = array('From' => $sender, 'Date' => $this->rc->user_date(), 'Message-ID' => $this->rc->gen_message_id(), 'X-Sender' => $from); if ($agent = $this->rc->config->get('useragent')) { $headers['User-Agent'] = $agent; } $message->headers($headers); // attach ics file for this event $ical = $this->cal->get_ical(); $ics = $ical->export(array($event), $method, false, $method == 'REQUEST' ? array($this->cal->driver, 'get_attachment_body') : false); $message->addAttachment($ics, 'text/calendar', 'event.ics', false, '8bit', '', RCMAIL_CHARSET . "; method=" . $method); return $message; }