/** * Initial startup function * to register session, create database and imap connections * * @todo Remove global vars $DB, $USER */ private function startup() { $config_all = $this->config->all(); // initialize syslog if ($this->config->get('log_driver') == 'syslog') { $syslog_id = $this->config->get('syslog_id', 'roundcube'); $syslog_facility = $this->config->get('syslog_facility', LOG_USER); openlog($syslog_id, LOG_ODELAY, $syslog_facility); } // set task and action properties $this->set_task(strip_quotes(get_input_value('_task', RCUBE_INPUT_GPC))); $this->action = asciiwords(get_input_value('_action', RCUBE_INPUT_GPC)); // connect to database $GLOBALS['DB'] = $this->get_dbh(); // use database for storing session data include_once 'include/session.inc'; // set session domain if (!empty($config_all['session_domain'])) { ini_set('session.cookie_domain', $config_all['session_domain']); } // set session garbage collecting time according to session_lifetime if (!empty($config_all['session_lifetime'])) { ini_set('session.gc_maxlifetime', $config_all['session_lifetime'] * 120); } // start PHP session (if not in CLI mode) if ($_SERVER['REMOTE_ADDR']) { session_start(); } // set initial session vars if (!isset($_SESSION['auth_time'])) { $_SESSION['auth_time'] = time(); $_SESSION['temp'] = true; } // create user object $this->set_user(new rcube_user($_SESSION['user_id'])); // reset some session parameters when changing task if ($_SESSION['task'] != $this->task) { unset($_SESSION['page']); } // set current task to session $_SESSION['task'] = $this->task; // create IMAP object if ($this->task == 'mail') { $this->imap_init(); } }
/** * Register this plugin to be responsible for a specific task * * @param string $task Task name (only characters [a-z0-9_-] are allowed) * @param string $owner Plugin name that registers this action */ public function register_task($task, $owner) { // tasks are irrelevant in framework mode if (!class_exists('rcmail', false)) { return true; } if ($task != asciiwords($task, true)) { rcube::raise_error(array('code' => 526, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid task name: {$task}." . " Only characters [a-z0-9_.-] are allowed"), true, false); } else { if (in_array($task, rcmail::$main_tasks)) { rcube::raise_error(array('code' => 526, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Cannot register taks {$task};" . " already taken by another plugin or the application itself"), true, false); } else { $this->tasks[$task] = $owner; rcmail::$main_tasks[] = $task; return true; } } return false; }
/** * Setter for application task * * @param string Task to set */ public function set_task($task) { $task = asciiwords($task, true); if ($this->user && $this->user->ID) { $task = !$task ? 'mail' : $task; } else { if (php_sapi_name() == 'cli') { $task = 'cli'; } else { $task = 'login'; } } $this->task = $task; $this->comm_path = $this->url(array('task' => $this->task)); if (!empty($_REQUEST['_framed'])) { $this->comm_path .= '&_framed=1'; } if ($this->output) { $this->output->set_env('task', $this->task); $this->output->set_env('comm_path', $this->comm_path); } }
/** * Validate the given input and save to local properties * @access private */ private function _set_sort_order($sort_field, $sort_order) { if ($sort_field != null) { $this->sort_field = asciiwords($sort_field); } if ($sort_order != null) { $this->sort_order = strtoupper($sort_order) == 'DESC' ? 'DESC' : 'ASC'; } }
/** * Handler for the 'message_compose' plugin hook. This will check for * a compose parameter 'calendar_event' and create an attachment with the * referenced event in iCal format */ public function mail_message_compose($args) { // set the submitted event ID as attachment if (!empty($args['param']['calendar_event'])) { $this->load_driver(); list($cal, $id) = explode(':', $args['param']['calendar_event'], 2); if ($event = $this->driver->get_event(array('id' => $id, 'calendar' => $cal))) { $filename = asciiwords($event['title']); if (empty($filename)) { $filename = 'event'; } // save ics to a temp file and register as attachment $tmp_path = tempnam($this->rc->config->get('temp_dir'), 'rcmAttmntCal'); file_put_contents($tmp_path, $this->get_ical()->export(array($event), '', false, array($this->driver, 'get_attachment_body'))); $args['attachments'][] = array('path' => $tmp_path, 'name' => $filename . '.ics', 'mimetype' => 'text/calendar'); $args['param']['subject'] = $event['title']; } } return $args; }
/** * Setter for application task * * @param string Task to set */ public function set_task($task) { $task = asciiwords($task); if ($this->user && $this->user->ID) { $task = !$task ? 'mail' : $task; } else { $task = 'login'; } $this->task = $task; $this->comm_path = $this->url(array('task' => $this->task)); if ($this->output) { $this->output->set_env('task', $this->task); } }
/** * Helper method to build a calendar list item (HTML content and js data) */ public function calendar_list_item($id, $prop, &$jsenv, $activeonly = false) { // enrich calendar properties with settings from the driver if (!$prop['virtual']) { unset($prop['user_id']); $prop['alarms'] = $this->cal->driver->alarms; $prop['attendees'] = $this->cal->driver->attendees; $prop['freebusy'] = $this->cal->driver->freebusy; $prop['attachments'] = $this->cal->driver->attachments; $prop['undelete'] = $this->cal->driver->undelete; $prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed')); $jsenv[$id] = $prop; } $classes = array('calendar', 'cal-' . asciiwords($id, true)); $title = $prop['title'] ?: ($prop['name'] != $prop['listname'] || strlen($prop['name']) > 25 ? html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : ''); if ($prop['virtual']) { $classes[] = 'virtual'; } else { if ($prop['readonly']) { $classes[] = 'readonly'; } } if ($prop['subscribed']) { $classes[] = 'subscribed'; } if ($prop['subscribed'] === 2) { $classes[] = 'partial'; } if ($prop['class']) { $classes[] = $prop['class']; } $content = ''; if (!$activeonly || $prop['active']) { $label_id = 'cl:' . $id; $content = html::div(join(' ', $classes), html::span(array('class' => 'calname', 'id' => $label_id, 'title' => $title), $prop['editname'] ? Q($prop['editname']) : $prop['listname']) . ($prop['virtual'] ? '' : html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'], 'aria-labelledby' => $label_id), '') . html::span('actions', ($prop['removable'] ? html::a(array('href' => '#', 'class' => 'remove', 'title' => $this->cal->gettext('removelist')), ' ') : '') . html::a(array('href' => '#', 'class' => 'quickview', 'title' => $this->cal->gettext('quickview'), 'role' => 'checkbox', 'aria-checked' => 'false'), '') . (isset($prop['subscribed']) ? html::a(array('href' => '#', 'class' => 'subscribed', 'title' => $this->cal->gettext('calendarsubscribe'), 'role' => 'checkbox', 'aria-checked' => $prop['subscribed'] ? 'true' : 'false'), ' ') : '')) . html::span(array('class' => 'handle', 'style' => "background-color: #" . ($prop['color'] ?: 'f00')), ' '))); } return $content; }
*/ // suppress php notices @ini_set('error_reporting', E_ALL & ~E_NOTICE); // include the converter class file require_once 'vcard_convert.php'; require_once 'utils.php'; if (!empty($_FILES['_vcards'])) { // instantiate a parser object $conv = new vcard_convert(array('mailonly' => !empty($_POST['_mailonly']), 'phoneonly' => !empty($_POST['_phoneonly']), 'accesscode' => preg_replace('/[^1-9]/', '', $_POST['_accesscode']))); // check for errors if ($err = $_FILES['_vcards']['error']) { $GLOBALS['error_msg'] = $err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE ? "The uploaded file was too big! Maximum file size allowed: " . show_bytes(parse_bytes(ini_get('upload_max_filesize'))) : "Upload failed, please try again"; } else { if ($conv->fromFile($_FILES['_vcards']['tmp_name'])) { $ext = $_POST['_format'] == 'gmail' ? 'csv' : ($_POST['_format'] == 'img' ? 'zip' : $_POST['_format']); $fname = asciiwords(preg_replace('/\\.[a-z]+$/i', '', $_FILES['_vcards']['name'])); header(sprintf('Content-Type: text/%s', $ext)); header(sprintf('Content-Disposition: attachment; filename="%s.%s"', $fname, $ext)); if ($_POST['_format'] == 'ldif') { print $conv->toLdif(); exit; } else { if ($_POST['_format'] == 'ldap') { // Clean the input dn modifier from dangerous chars $dnID = substr(preg_replace('/[^\\da-z=,_ -]/i', '', $_POST['_dn']), 0, 255); print $conv->toLdif($dnID ? $dnID : "", null, $_POST['_encoding']); exit; } else { if ($_POST['_format'] == 'gmail') { print $conv->toGmail(); exit;
/** * */ function tasklists($attrib = array()) { $lists = $this->plugin->driver->get_lists(); $li = ''; foreach ((array) $lists as $id => $prop) { if ($attrib['activeonly'] && !$prop['active']) { continue; } unset($prop['user_id']); $prop['alarms'] = $this->plugin->driver->alarms; $prop['undelete'] = $this->plugin->driver->undelete; $prop['sortable'] = $this->plugin->driver->sortable; $prop['attachments'] = $this->plugin->driver->attachments; $jsenv[$id] = $prop; $html_id = html_identifier($id); $class = 'tasks-' . asciiwords($id, true); if (!$prop['editable']) { $class .= ' readonly'; } if ($prop['class_name']) { $class .= ' ' . $prop['class_name']; } $li .= html::tag('li', array('id' => 'rcmlitasklist' . $html_id, 'class' => $class), html::tag('input', array('type' => 'checkbox', 'name' => '_list[]', 'value' => $id, 'checked' => $prop['active'])) . html::span('handle', ' ') . html::span('listname', $prop['name'])); } $this->rc->output->set_env('tasklists', $jsenv); $this->rc->output->add_gui_object('folderlist', $attrib['id']); return html::tag('ul', $attrib, $li, html::$common_attrib); }
/** * */ function calendar_list($attrib = array()) { $li = ''; foreach ($this->cal->get_calendars() as $id => $prop) { $driver = $this->cal->get_driver_by_cal($id); if ($attrib['activeonly'] && !$prop['active']) { continue; } unset($prop['user_id']); $prop['alarms'] = $driver->alarms; $prop['attendees'] = $driver->attendees; $prop['freebusy'] = $driver->freebusy; $prop['attachments'] = $driver->attachments; $prop['undelete'] = $driver->undelete; $prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed')); if (!$prop['virtual']) { $jsenv[$id] = $prop; } $html_id = html_identifier($id); $class = 'cal-' . asciiwords($id, true); $title = $prop['name'] != $prop['listname'] ? html_entity_decode($prop['name'], ENT_COMPAT, RCMAIL_CHARSET) : ''; if ($prop['virtual']) { $class .= ' virtual'; } else { if ($prop['readonly']) { $class .= ' readonly'; } } if ($prop['class_name']) { $class .= ' ' . $prop['class_name']; } $disabled = array(); if (!$prop['unsubscribe']) { $disabled = array('disabled' => 'disabled'); } $li .= html::tag('li', array('id' => 'rcmlical' . $html_id, 'class' => $class), ($prop['virtual'] ? '' : html::tag('input', array_merge($disabled, array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active'])), '') . html::span('handle', ' ')) . html::span(array('class' => 'calname', 'title' => $title), $prop['listname'])); } $this->rc->output->set_env('calendars', $jsenv); $this->rc->output->add_gui_object('folderlist', $attrib['id']); return html::tag('ul', $attrib, $li, html::$common_attrib); }
/** * Add UI element to copy event invitations or updates to the calendar */ public function mail_messagebody_html($p) { // load iCalendar functions (if necessary) if (!empty($this->ics_parts)) { $this->get_ical(); } $html = ''; foreach ($this->ics_parts as $mime_id) { $part = $this->message->mime_parts[$mime_id]; $charset = $part->ctype_parameters['charset'] ? $part->ctype_parameters['charset'] : RCMAIL_CHARSET; $events = $this->ical->import($this->message->get_part_content($mime_id), $charset); $title = $this->gettext('title'); $date = rcube_utils::anytodatetime($this->message->headers->date); // successfully parsed events? if (empty($events)) { continue; } // show a box for every event in the file foreach ($events as $idx => $event) { // Begin mod by Rosali (Google sends the ics inline and attached -> avoid duplicates with same UID - https://issues.kolab.org/show_bug.cgi?id=3585) $uid = $event['uid'] ? $event['uid'] : md5(serialize($event)); if (isset($this->ics_parts_filtered[$uid])) { continue; } $this->ics_parts_filtered[$uid] = 1; // End mod by Rosali if ($event['_type'] != 'event' && $event['_type'] != 'task') { // skip non-event objects (#2928) // Mod by Rosali (don't skip tasks) continue; } // define buttons according to method if ($this->ical->method == 'REPLY') { $driver = $this->get_default_driver(); $existing = $driver->get_event($event['uid']); $calendar_saveto = new html_hiddenfield(array('class' => 'calendar-saveto', 'value' => $existing['calendar'])); // Mod by Rosali (always pass calendar to GUI) if ($calendar_saveto) { $title = $this->gettext('itipreply'); $buttons = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_calendar.add_event_from_mail('" . JQ($mime_id . ':' . $idx) . "', this)", 'value' => $this->gettext('updateattendeestatus'))) . $calendar_saveto->show(); } } else { if ($this->ical->method == 'REQUEST') { $emails = $this->get_user_emails(); $title = $event['sequence'] > 0 ? $this->gettext('itipupdate') : $this->gettext('itipinvitation'); // add (hidden) buttons and activate them from asyncronous request foreach (array('accepted', 'tentative', 'declined') as $method) { $rsvp_buttons .= html::tag('input', array('type' => 'button', 'class' => "button {$method}", 'onclick' => "rcube_calendar.add_event_from_mail('" . JQ($mime_id . ':' . $idx) . "', this, '{$method}')", 'value' => $this->gettext('itip' . $method))); } $import_button = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_calendar.add_event_from_mail('" . JQ($mime_id . ':' . $idx) . "', this)", 'value' => $this->gettext('importtocalendar'))); // check my status $status = 'unknown'; foreach ($event['attendees'] as $attendee) { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { $status = !empty($attendee['status']) ? strtoupper($attendee['status']) : 'NEEDS-ACTION'; break; } } $dom_id = asciiwords($event['uid'], true); $buttons = html::div(array('id' => 'rsvp-' . $dom_id, 'style' => 'display:none'), $rsvp_buttons); $buttons .= html::div(array('id' => 'import-' . $dom_id, 'style' => 'display:none'), $import_button); $buttons_pre = html::div(array('id' => 'loading-' . $dom_id, 'class' => 'rsvp-status loading'), $this->gettext('loading')); $changed = is_object($event['changed']) ? $event['changed'] : $date; $script = json_serialize(array('uid' => $event['uid'], 'changed' => $changed ? $changed->format('U') : 0, 'sequence' => intval($event['sequence']), 'fallback' => $status)); $this->rc->output->add_script("rcube_calendar.fetch_event_rsvp_status({$script})", 'docready'); } else { if ($this->ical->method == 'CANCEL') { $title = $this->gettext('itipcancellation'); // create buttons to be activated from async request checking existence of this event in local calendars $button_import = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_calendar.add_event_from_mail('" . JQ($mime_id . ':' . $idx) . "', this)", 'value' => $this->gettext('importtocalendar'))); $button_remove = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_calendar.remove_event_from_mail('" . JQ($event['uid']) . "', '" . JQ($event['title']) . "')", 'value' => $this->gettext('removefromcalendar'))); $dom_id = asciiwords($event['uid'], true); $buttons = html::div(array('id' => 'rsvp-' . $dom_id, 'style' => 'display:none'), $button_remove); $buttons .= html::div(array('id' => 'import-' . $dom_id, 'style' => 'display:none'), $button_import); $buttons_pre = html::div(array('id' => 'loading-' . $dom_id, 'class' => 'rsvp-status loading'), $this->gettext('loading')); $changed = is_object($event['changed']) ? $event['changed'] : $date; $script = json_serialize(array('uid' => $event['uid'], 'changed' => $changed ? $changed->format('U') : 0, 'sequence' => intval($event['sequence']), 'fallback' => 'CANCELLED')); $this->rc->output->add_script("rcube_calendar.fetch_event_rsvp_status({$script})", 'docready'); } else { // get a list of writeable calendars // Begin mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/33) $driver = $this->get_default_driver(); $calendars = $driver->list_calendars(false, true); $calendar_select = new html_select(array('name' => 'calendar', 'class' => 'calendar-saveto', 'is_escaped' => true)); // Mod by Rosali (calendar selector can exist multiple times - can't be referenced by ID) $numcals = 0; foreach ($calendars as $calendar) { $driver = $this->get_driver_by_cal($calendar['calendar_id']); if ($driver->readonly !== true) { $calendar_select->add($calendar['name'], $calendar['id']); $numcals++; } } } } } if ($numcals > 0) { $buttons = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_calendar.add_event_from_mail('" . JQ($mime_id . ':' . $idx) . "', this)", 'value' => $this->gettext('importtocalendar'))) . $calendar_select->show($this->rc->config->get('calendar_default_calendar')); } // show event details with buttons if ($buttons) { $html .= html::div('calendar-invitebox', $this->ui->event_details_table($event, $title) . $buttons_pre . html::div('rsvp-buttons', $buttons)); } // Emd mod by Rosli // limit listing if ($idx >= 3) { break; } } } // prepend event boxes to message body if ($html) { $this->ui->init(); $p['content'] = $html . $p['content']; $this->rc->output->add_label('calendar.savingdata', 'calendar.deleteventconfirm', 'calendar.declinedeleteconfirm'); } return $p; }
/** * Build inline UI elements for iTip messages */ public function mail_itip_inline_ui($event, $method, $mime_id, $task, $message_date = null, $preview_url = null) { $buttons = array(); $dom_id = asciiwords($event['uid'], true); $rsvp_status = 'unknown'; // pass some metadata about the event and trigger the asynchronous status check $changed = is_object($event['changed']) ? $event['changed'] : $message_date; $metadata = array('uid' => $event['uid'], '_instance' => $event['_instance'], 'changed' => $changed ? $changed->format('U') : 0, 'sequence' => intval($event['sequence']), 'method' => $method, 'task' => $task); // create buttons to be activated from async request checking existence of this event in local calendars $buttons[] = html::div(array('id' => 'loading-' . $dom_id, 'class' => 'rsvp-status loading'), $this->gettext('loading')); // on iTip REPLY we have two options: if ($method == 'REPLY') { $title = $this->gettext('itipreply'); foreach ($event['attendees'] as $attendee) { if (!empty($attendee['email']) && $attendee['role'] != 'ORGANIZER' && (empty($event['_sender']) || ($attendee['email'] == $event['_sender'] || $attendee['email'] == $event['_sender_utf']))) { $metadata['attendee'] = $attendee['email']; $rsvp_status = strtoupper($attendee['status']); if ($attendee['delegated-to']) { $metadata['delegated-to'] = $attendee['delegated-to']; } break; } } // 1. update the attendee status on our copy $update_button = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . rcube::JQ($mime_id) . "', '{$task}')", 'value' => $this->gettext('updateattendeestatus'))); // 2. accept or decline a new or delegate attendee $accept_buttons = html::tag('input', array('type' => 'button', 'class' => "button accept", 'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . rcube::JQ($mime_id) . "', '{$task}')", 'value' => $this->gettext('acceptattendee'))); $accept_buttons .= html::tag('input', array('type' => 'button', 'class' => "button decline", 'onclick' => "rcube_libcalendaring.decline_attendee_reply('" . rcube::JQ($mime_id) . "', '{$task}')", 'value' => $this->gettext('declineattendee'))); $buttons[] = html::div(array('id' => 'update-' . $dom_id, 'style' => 'display:none'), $update_button); $buttons[] = html::div(array('id' => 'accept-' . $dom_id, 'style' => 'display:none'), $accept_buttons); } else { if ($method == 'REQUEST') { $emails = $this->lib->get_user_emails(); $title = $event['sequence'] > 0 ? $this->gettext('itipupdate') : $this->gettext('itipinvitation'); $metadata['rsvp'] = true; $metadata['sensitivity'] = $event['sensitivity']; if (is_object($event['start'])) { $metadata['date'] = $event['start']->format('U'); } // check for X-KOLAB-INVITATIONTYPE property and only show accept/decline buttons if (self::get_custom_property($event, 'X-KOLAB-INVITATIONTYPE') == 'CONFIRMATION') { $this->rsvp_actions = array('accepted', 'declined'); $metadata['nosave'] = true; } // 1. display RSVP buttons (if the user was invited) foreach ($this->rsvp_actions as $method) { $rsvp_buttons .= html::tag('input', array('type' => 'button', 'class' => "button {$method}", 'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . rcube::JQ($mime_id) . "', '{$task}', '{$method}', '{$dom_id}')", 'value' => $this->gettext('itip' . $method))); } // add button to open calendar/preview if (!empty($preview_url)) { $msgref = $this->lib->ical_message->folder . '/' . $this->lib->ical_message->uid . '#' . $mime_id; $rsvp_buttons .= html::tag('input', array('type' => 'button', 'class' => "button preview", 'onclick' => "rcube_libcalendaring.open_itip_preview('" . rcube::JQ($preview_url) . "', '" . rcube::JQ($msgref) . "')", 'value' => $this->gettext('openpreview'))); } // 2. update the local copy with minor changes $update_button = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . rcube::JQ($mime_id) . "', '{$task}')", 'value' => $this->gettext('updatemycopy'))); // 3. Simply import the event without replying $import_button = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . rcube::JQ($mime_id) . "', '{$task}')", 'value' => $this->gettext('importtocalendar'))); // check my status foreach ($event['attendees'] as $attendee) { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { $metadata['attendee'] = $attendee['email']; $metadata['rsvp'] = $attendee['rsvp'] || $attendee['role'] != 'NON-PARTICIPANT'; $rsvp_status = !empty($attendee['status']) ? strtoupper($attendee['status']) : 'NEEDS-ACTION'; break; } } // add itip reply message controls $rsvp_buttons .= html::div('itip-reply-controls', $this->itip_rsvp_options_ui($dom_id, $metadata['nosave'])); $buttons[] = html::div(array('id' => 'rsvp-' . $dom_id, 'class' => 'rsvp-buttons', 'style' => 'display:none'), $rsvp_buttons); $buttons[] = html::div(array('id' => 'update-' . $dom_id, 'style' => 'display:none'), $update_button); // prepare autocompletion for delegation dialog if (in_array('delegated', $this->rsvp_actions)) { $this->rc->autocomplete_init(); } } else { if ($method == 'CANCEL') { $title = $this->gettext('itipcancellation'); $event_prop = array_filter(array('uid' => $event['uid'], '_instance' => $event['_instance'], '_savemode' => $event['_savemode'])); // 1. remove the event from our calendar $button_remove = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_libcalendaring.remove_from_itip(" . rcube_output::json_serialize($event_prop) . ", '{$task}', '" . rcube::JQ($event['title']) . "')", 'value' => $this->gettext('removefromcalendar'))); // 2. update our copy with status=cancelled $button_update = html::tag('input', array('type' => 'button', 'class' => 'button', 'onclick' => "rcube_libcalendaring.add_from_itip_mail('" . rcube::JQ($mime_id) . "', '{$task}')", 'value' => $this->gettext('updatemycopy'))); $buttons[] = html::div(array('id' => 'rsvp-' . $dom_id, 'style' => 'display:none'), $button_remove . $button_update); $rsvp_status = 'CANCELLED'; $metadata['rsvp'] = true; } } } // append generic import button if ($import_button) { $buttons[] = html::div(array('id' => 'import-' . $dom_id, 'style' => 'display:none'), $import_button); } // pass some metadata about the event and trigger the asynchronous status check $metadata['fallback'] = $rsvp_status; $metadata['rsvp'] = intval($metadata['rsvp']); $this->rc->output->add_script("rcube_libcalendaring.fetch_itip_object_status(" . rcube_output::json_serialize($metadata) . ")", 'docready'); // get localized texts from the right domain foreach (array('savingdata', 'deleteobjectconfirm', 'declinedeleteconfirm', 'declineattendee', 'cancel', 'itipdelegated', 'declineattendeeconfirm', 'itipcomment', 'delegateinvitation', 'delegateto', 'delegatersvpme', 'delegateinvalidaddress') as $label) { $this->rc->output->command('add_label', "itip.{$label}", $this->gettext($label)); } // show event details with buttons return $this->itip_object_details_table($event, $title) . html::div(array('class' => 'itip-buttons', 'id' => 'itip-buttons-' . asciiwords($metadata['uid'], true)), join('', $buttons)); }
/** * Setter for application task * * @param string Task to set */ public function set_task($task) { $task = asciiwords($task); $this->task = $task ? $task : 'mail'; $this->comm_path = $this->url(array('task' => $this->task)); if ($this->output) { $this->output->set_env('task', $this->task); } }
private function _gen_folder_list($arrFolders, $command, $nestLevel = 0, &$folderTotal = 0) { $rcmail = rcmail::get_instance(); $maxlength = 35; $realnames = false; $out = ''; foreach ($arrFolders as $key => $folder) { $title = null; if (($folder_class = rcmail_folder_classname($folder['id'])) && !$realnames) { $foldername = rcube_label($folder_class); } else { $foldername = $folder['name']; // shorten the folder name to a given length if ($maxlength && $maxlength > 1) { $fname = abbreviate_string($foldername, $maxlength); if ($fname != $foldername) { $title = $foldername; } $foldername = $fname; } } // make folder name safe for ids and class names $folder_id = asciiwords($folder['id'], true, '_'); $classes = array(); // set special class for Sent, Drafts, Trash and Junk if ($folder['id'] == $rcmail->config->get('sent_mbox')) { $classes[] = 'sent'; } else { if ($folder['id'] == $rcmail->config->get('drafts_mbox')) { $classes[] = 'drafts'; } else { if ($folder['id'] == $rcmail->config->get('trash_mbox')) { $classes[] = 'trash'; } else { if ($folder['id'] == $rcmail->config->get('junk_mbox')) { $classes[] = 'junk'; } else { if ($folder['id'] == 'INBOX') { $classes[] = 'inbox'; } else { $classes[] = '_' . asciiwords($folder_class ? $folder_class : strtolower($folder['id']), true); } } } } } if ($folder['virtual']) { $classes[] = 'virtual'; } $out .= html::tag('li', array('class' => join(' ', $classes)), html::a(array('href' => $command, 'onclick' => "rcm_set_dest_folder('" . JQ($folder['id']) . "')", 'class' => 'active', 'title' => $title), str_repeat(' ', $nestLevel) . Q($foldername))); if (!empty($folder['folders'])) { $out .= $this->_gen_folder_list($folder['folders'], $command, $nestLevel + 1, $folderTotal); } $folderTotal++; } if ($nestLevel == 0) { if ($folderTotal > 5) { $out = html::tag('ul', array('class' => 'toolbarmenu folders scrollable'), $out); $out = html::tag('div', array('class' => 'scroll_up_pas'), '') . $out . html::tag('div', array('class' => 'scroll_down_act'), ''); $out = html::tag('div', array('class' => 'popupmenu'), $out); } else { $out = html::tag('ul', array('class' => 'popupmenu toolbarmenu folders'), $out); } } return $out; }
/** * Object constructor * * @param array $p LDAP connection properties * @param boolean $debug Enables debug mode * @param string $mail_domain Current user mail domain name */ function __construct($p, $debug = false, $mail_domain = null) { $this->prop = $p; $fetch_attributes = array('objectClass'); // check if groups are configured if (is_array($p['groups']) && count($p['groups'])) { $this->groups = true; // set member field if (!empty($p['groups']['member_attr'])) { $this->prop['member_attr'] = strtolower($p['groups']['member_attr']); } else { if (empty($p['member_attr'])) { $this->prop['member_attr'] = 'member'; } } // set default name attribute to cn if (empty($this->prop['groups']['name_attr'])) { $this->prop['groups']['name_attr'] = 'cn'; } if (empty($this->prop['groups']['scope'])) { $this->prop['groups']['scope'] = 'sub'; } // extend group objectclass => member attribute mapping if (!empty($this->prop['groups']['class_member_attr'])) { $this->group_types = array_merge($this->group_types, $this->prop['groups']['class_member_attr']); } // add group name attrib to the list of attributes to be fetched $fetch_attributes[] = $this->prop['groups']['name_attr']; } if (is_array($p['group_filters'])) { $this->groups = $this->groups || count($p['group_filters']); foreach ($p['group_filters'] as $k => $group_filter) { // set default name attribute to cn if (empty($group_filter['name_attr']) && empty($this->prop['groups']['name_attr'])) { $this->prop['group_filters'][$k]['name_attr'] = $group_filter['name_attr'] = 'cn'; } if ($group_filter['name_attr']) { $fetch_attributes[] = $group_filter['name_attr']; } } } // fieldmap property is given if (is_array($p['fieldmap'])) { foreach ($p['fieldmap'] as $rf => $lf) { $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf)); } } else { if (!empty($p)) { // read deprecated *_field properties to remain backwards compatible foreach ($p as $prop => $value) { if (preg_match('/^(.+)_field$/', $prop, $matches)) { $this->fieldmap[$matches[1]] = $this->_attr_name(strtolower($value)); } } } } // use fieldmap to advertise supported coltypes to the application foreach ($this->fieldmap as $colv => $lfv) { list($col, $type) = explode(':', $colv); list($lf, $limit, $delim) = explode(':', $lfv); if ($limit == '*') { $limit = null; } else { $limit = max(1, intval($limit)); } if (!is_array($this->coltypes[$col])) { $subtypes = $type ? array($type) : null; $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes, 'attributes' => array($lf)); } elseif ($type) { $this->coltypes[$col]['subtypes'][] = $type; $this->coltypes[$col]['attributes'][] = $lf; $this->coltypes[$col]['limit'] += $limit; } if ($delim) { $this->coltypes[$col]['serialized'][$type] = $delim; } $this->fieldmap[$colv] = $lf; } // support for composite address if ($this->coltypes['street'] && $this->coltypes['locality']) { $this->coltypes['address'] = array('limit' => max(1, $this->coltypes['locality']['limit'] + $this->coltypes['address']['limit']), 'subtypes' => array_merge((array) $this->coltypes['address']['subtypes'], (array) $this->coltypes['locality']['subtypes']), 'childs' => array()) + (array) $this->coltypes['address']; foreach (array('street', 'locality', 'zipcode', 'region', 'country') as $childcol) { if ($this->coltypes[$childcol]) { $this->coltypes['address']['childs'][$childcol] = array('type' => 'text'); unset($this->coltypes[$childcol]); // remove address child col from global coltypes list } } // at least one address type must be specified if (empty($this->coltypes['address']['subtypes'])) { $this->coltypes['address']['subtypes'] = array('home'); } } else { if ($this->coltypes['address']) { $this->coltypes['address'] += array('type' => 'textarea', 'childs' => null, 'size' => 40); // 'serialized' means the UI has to present a composite address field if ($this->coltypes['address']['serialized']) { $childprop = array('type' => 'text'); $this->coltypes['address']['type'] = 'composite'; $this->coltypes['address']['childs'] = array('street' => $childprop, 'locality' => $childprop, 'zipcode' => $childprop, 'country' => $childprop); } } } // make sure 'required_fields' is an array if (!is_array($this->prop['required_fields'])) { $this->prop['required_fields'] = (array) $this->prop['required_fields']; } // make sure LDAP_rdn field is required if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields']) && !in_array($this->prop['LDAP_rdn'], array_keys((array) $this->prop['autovalues']))) { $this->prop['required_fields'][] = $this->prop['LDAP_rdn']; } foreach ($this->prop['required_fields'] as $key => $val) { $this->prop['required_fields'][$key] = $this->_attr_name(strtolower($val)); } // Build sub_fields filter if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { $this->sub_filter = ''; foreach ($this->prop['sub_fields'] as $class) { if (!empty($class)) { $class = is_array($class) ? array_pop($class) : $class; $this->sub_filter .= '(objectClass=' . $class . ')'; } } if (count($this->prop['sub_fields']) > 1) { $this->sub_filter = '(|' . $this->sub_filter . ')'; } } $this->sort_col = is_array($p['sort']) ? $p['sort'][0] : $p['sort']; $this->debug = $debug; $this->mail_domain = $mail_domain; // initialize cache $rcube = rcube::get_instance(); if ($cache_type = $rcube->config->get('ldap_cache', 'db')) { $cache_ttl = $rcube->config->get('ldap_cache_ttl', '10m'); $cache_name = 'LDAP.' . asciiwords($this->prop['name']); $this->cache = $rcube->get_cache($cache_name, $cache_type, $cache_ttl); } // determine which attributes to fetch $this->prop['list_attributes'] = array_unique($fetch_attributes); $this->prop['attributes'] = array_merge(array_values($this->fieldmap), $fetch_attributes); foreach ($rcube->config->get('contactlist_fields') as $col) { $this->prop['list_attributes'] = array_merge($this->prop['list_attributes'], $this->_map_field($col)); } // initialize ldap wrapper object $this->ldap = new rcube_ldap_generic($this->prop); $this->ldap->config_set(array('cache' => $this->cache, 'debug' => $this->debug)); $this->_connect(); }
/** * Object constructor * * @param array LDAP connection properties * @param boolean Enables debug mode * @param string Current user mail domain name * @param integer User-ID */ function __construct($p, $debug = false, $mail_domain = NULL) { $this->prop = $p; if (isset($p['searchonly'])) { $this->searchonly = $p['searchonly']; } // check if groups are configured if (is_array($p['groups']) && count($p['groups'])) { $this->groups = true; // set member field if (!empty($p['groups']['member_attr'])) { $this->prop['member_attr'] = strtolower($p['groups']['member_attr']); } else { if (empty($p['member_attr'])) { $this->prop['member_attr'] = 'member'; } } // set default name attribute to cn if (empty($this->prop['groups']['name_attr'])) { $this->prop['groups']['name_attr'] = 'cn'; } if (empty($this->prop['groups']['scope'])) { $this->prop['groups']['scope'] = 'sub'; } } // fieldmap property is given if (is_array($p['fieldmap'])) { foreach ($p['fieldmap'] as $rf => $lf) { $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf)); } } else { if (!empty($p)) { // read deprecated *_field properties to remain backwards compatible foreach ($p as $prop => $value) { if (preg_match('/^(.+)_field$/', $prop, $matches)) { $this->fieldmap[$matches[1]] = $this->_attr_name(strtolower($value)); } } } } // use fieldmap to advertise supported coltypes to the application foreach ($this->fieldmap as $colv => $lfv) { list($col, $type) = explode(':', $colv); list($lf, $limit, $delim) = explode(':', $lfv); if ($limit == '*') { $limit = null; } else { $limit = max(1, intval($limit)); } if (!is_array($this->coltypes[$col])) { $subtypes = $type ? array($type) : null; $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes); } elseif ($type) { $this->coltypes[$col]['subtypes'][] = $type; $this->coltypes[$col]['limit'] += $limit; } if ($delim) { $this->coltypes[$col]['serialized'][$type] = $delim; } if ($type && !$this->fieldmap[$col]) { $this->fieldmap[$col] = $lf; } $this->fieldmap[$colv] = $lf; } // support for composite address if ($this->fieldmap['street'] && $this->fieldmap['locality']) { $this->coltypes['address'] = array('limit' => max(1, $this->coltypes['locality']['limit'] + $this->coltypes['address']['limit']), 'subtypes' => array_merge((array) $this->coltypes['address']['subtypes'], (array) $this->coltypes['locality']['subtypes']), 'childs' => array()) + (array) $this->coltypes['address']; foreach (array('street', 'locality', 'zipcode', 'region', 'country') as $childcol) { if ($this->fieldmap[$childcol]) { $this->coltypes['address']['childs'][$childcol] = array('type' => 'text'); unset($this->coltypes[$childcol]); // remove address child col from global coltypes list } } // at least one address type must be specified if (empty($this->coltypes['address']['subtypes'])) { $this->coltypes['address']['subtypes'] = array('home'); } } else { if ($this->coltypes['address']) { $this->coltypes['address'] += array('type' => 'textarea', 'childs' => null, 'size' => 40); // 'serialized' means the UI has to present a composite address field if ($this->coltypes['address']['serialized']) { $childprop = array('type' => 'text'); $this->coltypes['address']['type'] = 'composite'; $this->coltypes['address']['childs'] = array('street' => $childprop, 'locality' => $childprop, 'zipcode' => $childprop, 'country' => $childprop); } } } // make sure 'required_fields' is an array if (!is_array($this->prop['required_fields'])) { $this->prop['required_fields'] = (array) $this->prop['required_fields']; } // make sure LDAP_rdn field is required if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields'])) { $this->prop['required_fields'][] = $this->prop['LDAP_rdn']; } foreach ($this->prop['required_fields'] as $key => $val) { $this->prop['required_fields'][$key] = $this->_attr_name(strtolower($val)); } // Build sub_fields filter if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { $this->sub_filter = ''; foreach ($this->prop['sub_fields'] as $attr => $class) { if (!empty($class)) { $class = is_array($class) ? array_pop($class) : $class; $this->sub_filter .= '(objectClass=' . $class . ')'; } } if (count($this->prop['sub_fields']) > 1) { $this->sub_filter = '(|' . $this->sub_filter . ')'; } } $this->sort_col = is_array($p['sort']) ? $p['sort'][0] : $p['sort']; $this->debug = $debug; $this->mail_domain = $mail_domain; // initialize cache $rcmail = rcmail::get_instance(); $this->cache = $rcmail->get_cache('LDAP.' . asciiwords($this->prop['name']), 'db', 600); $this->_connect(); }
/** * Convert the given string into a valid HTML identifier * Same functionality as done in app.js with rcube_webmail.html_identifier() */ public static function html_identifier($str, $encode = false) { if ($encode) { return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); } else { return asciiwords($str, true, '_'); } }
/** * Register this plugin to be responsible for a specific task * * @param string Task name (only characters [a-z0-9_.-] are allowed) */ public function register_task($task) { if ($task != asciiwords($task)) { raise_error(array('code' => 526, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid task name: {$task}. Only characters [a-z0-9_.-] are allowed"), true, false); } else { if (in_array(rcmail::$main_tasks, $task)) { raise_error(array('code' => 526, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Cannot register taks {$task}; already taken by another plugin or the application itself"), true, false); } else { rcmail::$main_tasks[] = $task; } } }