Copying plugins into 0.6 release branch
New file |
| | |
| | | /** |
| | | * ACL plugin script |
| | | * |
| | | * @version 0.5 |
| | | * @author Aleksander Machniak <alec@alec.pl> |
| | | */ |
| | | |
| | | if (window.rcmail) { |
| | | rcmail.addEventListener('init', function() { |
| | | if (rcmail.gui_objects.acltable) { |
| | | rcmail.acl_list_init(); |
| | | // enable autocomplete on user input |
| | | if (rcmail.env.acl_users_source) { |
| | | rcmail.init_address_input_events($('#acluser'), {action:'plugin.acl-autocomplete'}); |
| | | // fix inserted value |
| | | rcmail.addEventListener('autocomplete_insert', function(e) { |
| | | if (e.field.id != 'acluser') |
| | | return; |
| | | |
| | | var value = e.insert; |
| | | // get UID from the entry value |
| | | if (value.match(/\s*\(([^)]+)\)[, ]*$/)) |
| | | value = RegExp.$1; |
| | | e.field.value = value; |
| | | }); |
| | | } |
| | | } |
| | | |
| | | rcmail.enable_command('acl-create', 'acl-save', 'acl-cancel', 'acl-mode-switch', true); |
| | | rcmail.enable_command('acl-delete', 'acl-edit', false); |
| | | }); |
| | | } |
| | | |
| | | // Display new-entry form |
| | | rcube_webmail.prototype.acl_create = function() |
| | | { |
| | | this.acl_init_form(); |
| | | } |
| | | |
| | | // Display ACL edit form |
| | | rcube_webmail.prototype.acl_edit = function() |
| | | { |
| | | // @TODO: multi-row edition |
| | | var id = this.acl_list.get_single_selection(); |
| | | if (id) |
| | | this.acl_init_form(id); |
| | | } |
| | | |
| | | // ACL entry delete |
| | | rcube_webmail.prototype.acl_delete = function() |
| | | { |
| | | var users = this.acl_get_usernames(); |
| | | |
| | | if (users && users.length && confirm(this.get_label('acl.deleteconfirm'))) { |
| | | this.http_request('plugin.acl', '_act=delete&_user='+urlencode(users.join(',')) |
| | | + '&_mbox='+urlencode(this.env.mailbox), |
| | | this.set_busy(true, 'acl.deleting')); |
| | | } |
| | | } |
| | | |
| | | // Save ACL data |
| | | rcube_webmail.prototype.acl_save = function() |
| | | { |
| | | var user = $('#acluser').val(), rights = '', type; |
| | | |
| | | $(':checkbox', this.env.acl_advanced ? $('#advancedrights') : sim_ul = $('#simplerights')).map(function() { |
| | | if (this.checked) |
| | | rights += this.value; |
| | | }); |
| | | |
| | | if (type = $('input:checked[name=usertype]').val()) { |
| | | if (type != 'user') |
| | | user = type; |
| | | } |
| | | |
| | | if (!user) { |
| | | alert(this.get_label('acl.nouser')); |
| | | return; |
| | | } |
| | | if (!rights) { |
| | | alert(this.get_label('acl.norights')); |
| | | return; |
| | | } |
| | | |
| | | this.http_request('plugin.acl', '_act=save' |
| | | + '&_user='+urlencode(user) |
| | | + '&_acl=' +rights |
| | | + '&_mbox='+urlencode(this.env.mailbox) |
| | | + (this.acl_id ? '&_old='+this.acl_id : ''), |
| | | this.set_busy(true, 'acl.saving')); |
| | | } |
| | | |
| | | // Cancel/Hide form |
| | | rcube_webmail.prototype.acl_cancel = function() |
| | | { |
| | | this.ksearch_blur(); |
| | | this.acl_form.hide(); |
| | | } |
| | | |
| | | // Update data after save (and hide form) |
| | | rcube_webmail.prototype.acl_update = function(o) |
| | | { |
| | | // delete old row |
| | | if (o.old) |
| | | this.acl_remove_row(o.old); |
| | | // make sure the same ID doesn't exist |
| | | else if (this.env.acl[o.id]) |
| | | this.acl_remove_row(o.id); |
| | | |
| | | // add new row |
| | | this.acl_add_row(o, true); |
| | | // hide autocomplete popup |
| | | this.ksearch_blur(); |
| | | // hide form |
| | | this.acl_form.hide(); |
| | | } |
| | | |
| | | // Switch table display mode |
| | | rcube_webmail.prototype.acl_mode_switch = function(elem) |
| | | { |
| | | this.env.acl_advanced = !this.env.acl_advanced; |
| | | this.enable_command('acl-delete', 'acl-edit', false); |
| | | this.http_request('plugin.acl', '_act=list' |
| | | + '&_mode='+(this.env.acl_advanced ? 'advanced' : 'simple') |
| | | + '&_mbox='+urlencode(this.env.mailbox), |
| | | this.set_busy(true, 'loading')); |
| | | } |
| | | |
| | | // ACL table initialization |
| | | rcube_webmail.prototype.acl_list_init = function() |
| | | { |
| | | this.acl_list = new rcube_list_widget(this.gui_objects.acltable, |
| | | {multiselect:true, draggable:false, keyboard:true, toggleselect:true}); |
| | | this.acl_list.addEventListener('select', function(o) { rcmail.acl_list_select(o); }); |
| | | this.acl_list.addEventListener('dblclick', function(o) { rcmail.acl_list_dblclick(o); }); |
| | | this.acl_list.addEventListener('keypress', function(o) { rcmail.acl_list_keypress(o); }); |
| | | this.acl_list.init(); |
| | | } |
| | | |
| | | // ACL table row selection handler |
| | | rcube_webmail.prototype.acl_list_select = function(list) |
| | | { |
| | | rcmail.enable_command('acl-delete', list.selection.length > 0); |
| | | rcmail.enable_command('acl-edit', list.selection.length == 1); |
| | | list.focus(); |
| | | } |
| | | |
| | | // ACL table double-click handler |
| | | rcube_webmail.prototype.acl_list_dblclick = function(list) |
| | | { |
| | | this.acl_edit(); |
| | | } |
| | | |
| | | // ACL table keypress handler |
| | | rcube_webmail.prototype.acl_list_keypress = function(list) |
| | | { |
| | | if (list.key_pressed == list.ENTER_KEY) |
| | | this.command('acl-edit'); |
| | | else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY) |
| | | if (!this.acl_form || !this.acl_form.is(':visible')) |
| | | this.command('acl-delete'); |
| | | } |
| | | |
| | | // Reloads ACL table |
| | | rcube_webmail.prototype.acl_list_update = function(html) |
| | | { |
| | | $(this.gui_objects.acltable).html(html); |
| | | this.acl_list_init(); |
| | | } |
| | | |
| | | // Returns names of users in selected rows |
| | | rcube_webmail.prototype.acl_get_usernames = function() |
| | | { |
| | | var users = [], n, len, cell, row, |
| | | list = this.acl_list, |
| | | selection = list.get_selection(); |
| | | |
| | | for (n=0, len=selection.length; n<len; n++) { |
| | | if (this.env.acl_specials.length && $.inArray(selection[n], this.env.acl_specials) >= 0) { |
| | | users.push(selection[n]); |
| | | } |
| | | else { |
| | | row = list.rows[selection[n]].obj; |
| | | cell = $('td.user', row); |
| | | if (cell.length == 1) |
| | | users.push(cell.text()); |
| | | } |
| | | } |
| | | |
| | | return users; |
| | | } |
| | | |
| | | // Removes ACL table row |
| | | rcube_webmail.prototype.acl_remove_row = function(id) |
| | | { |
| | | this.acl_list.remove_row(id); |
| | | // we don't need it anymore (remove id conflict) |
| | | $('#rcmrow'+id).remove(); |
| | | this.env.acl[id] = null; |
| | | } |
| | | |
| | | // Adds ACL table row |
| | | rcube_webmail.prototype.acl_add_row = function(o, sel) |
| | | { |
| | | var n, len, ids = [], spec = [], id = o.id, list = this.acl_list, |
| | | items = this.env.acl_advanced ? [] : this.env.acl_items, |
| | | table = this.gui_objects.acltable, |
| | | row = $('thead > tr', table).clone(); |
| | | |
| | | // Update new row |
| | | $('td', row).map(function() { |
| | | var r, cl = this.className.replace(/^acl/, ''); |
| | | |
| | | if (items && items[cl]) |
| | | cl = items[cl]; |
| | | |
| | | if (cl == 'user') |
| | | $(this).text(o.username); |
| | | else |
| | | $(this).addClass(rcmail.acl_class(o.acl, cl)).text(''); |
| | | }); |
| | | |
| | | row.attr('id', 'rcmrow'+id); |
| | | row = row.get(0); |
| | | |
| | | this.env.acl[id] = o.acl; |
| | | |
| | | // sorting... (create an array of user identifiers, then sort it) |
| | | for (n in this.env.acl) { |
| | | if (this.env.acl[n]) { |
| | | if (this.env.acl_specials.length && $.inArray(n, this.env.acl_specials) >= 0) |
| | | spec.push(n); |
| | | else |
| | | ids.push(n); |
| | | } |
| | | } |
| | | ids.sort(); |
| | | // specials on the top |
| | | ids = spec.concat(ids); |
| | | |
| | | // find current id |
| | | for (n=0, len=ids.length; n<len; n++) |
| | | if (ids[n] == id) |
| | | break; |
| | | |
| | | // add row |
| | | if (n && n < len) { |
| | | $('#rcmrow'+ids[n-1]).after(row); |
| | | list.init_row(row); |
| | | list.rowcount++; |
| | | } |
| | | else |
| | | list.insert_row(row); |
| | | |
| | | if (sel) |
| | | list.select_row(o.id); |
| | | } |
| | | |
| | | // Initializes and shows ACL create/edit form |
| | | rcube_webmail.prototype.acl_init_form = function(id) |
| | | { |
| | | var ul, row, val = '', type = 'user', li_elements, body = $('body'), |
| | | adv_ul = $('#advancedrights'), sim_ul = $('#simplerights'), |
| | | name_input = $('#acluser'); |
| | | |
| | | if (!this.acl_form) { |
| | | var fn = function () { $('input[value=user]').prop('checked', true); }; |
| | | name_input.click(fn).keypress(fn); |
| | | } |
| | | |
| | | this.acl_form = $('#aclform'); |
| | | |
| | | // Hide unused items |
| | | if (this.env.acl_advanced) { |
| | | adv_ul.show(); |
| | | sim_ul.hide(); |
| | | ul = adv_ul; |
| | | } |
| | | else { |
| | | sim_ul.show(); |
| | | adv_ul.hide(); |
| | | ul = sim_ul; |
| | | } |
| | | |
| | | // initialize form fields |
| | | li_elements = $(':checkbox', ul); |
| | | li_elements.attr('checked', false); |
| | | |
| | | if (id) { |
| | | row = this.acl_list.rows[id].obj; |
| | | li_elements.map(function() { |
| | | var val = this.value, td = $('td.'+this.id, row); |
| | | if (td && td.hasClass('enabled')) |
| | | this.checked = true; |
| | | }); |
| | | |
| | | if (!this.env.acl_specials.length || $.inArray(id, this.env.acl_specials) < 0) |
| | | val = $('td.user', row).text(); |
| | | else |
| | | type = id; |
| | | } |
| | | |
| | | name_input.val(val); |
| | | $('input[value='+type+']').prop('checked', true); |
| | | |
| | | this.acl_id = id; |
| | | |
| | | // position the form horizontally |
| | | var bw = body.width(), mw = this.acl_form.width(); |
| | | |
| | | if (bw >= mw) |
| | | this.acl_form.css({left: parseInt((bw - mw)/2)+'px'}); |
| | | |
| | | // display it |
| | | this.acl_form.show(); |
| | | if (type == 'user') |
| | | name_input.focus(); |
| | | } |
| | | |
| | | // Returns class name according to ACL comparision result |
| | | rcube_webmail.prototype.acl_class = function(acl1, acl2) |
| | | { |
| | | var i, len, found = 0; |
| | | |
| | | acl1 = String(acl1); |
| | | acl2 = String(acl2); |
| | | |
| | | for (i=0, len=acl2.length; i<len; i++) |
| | | if (acl1.indexOf(acl2[i]) > -1) |
| | | found++; |
| | | |
| | | if (found == len) |
| | | return 'enabled'; |
| | | else if (found) |
| | | return 'partial'; |
| | | |
| | | return 'disabled'; |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Folders Access Control Lists Management (RFC4314, RFC2086) |
| | | * |
| | | * @version 0.5 |
| | | * @author Aleksander Machniak <alec@alec.pl> |
| | | * |
| | | * |
| | | * Copyright (C) 2011, Kolab Systems AG |
| | | * |
| | | * This program is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU General Public License version 2 |
| | | * as published by the Free Software Foundation. |
| | | * |
| | | * This program 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 this program; if not, write to the Free Software Foundation, Inc., |
| | | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| | | */ |
| | | |
| | | class acl extends rcube_plugin |
| | | { |
| | | public $task = 'settings|addressbook'; |
| | | |
| | | private $rc; |
| | | private $supported = null; |
| | | private $mbox; |
| | | private $ldap; |
| | | private $specials = array('anyone', 'anonymous'); |
| | | |
| | | /** |
| | | * Plugin initialization |
| | | */ |
| | | function init() |
| | | { |
| | | $this->rc = rcmail::get_instance(); |
| | | |
| | | // Register hooks |
| | | $this->add_hook('folder_form', array($this, 'folder_form')); |
| | | // kolab_addressbook plugin |
| | | $this->add_hook('addressbook_form', array($this, 'folder_form')); |
| | | // Plugin actions |
| | | $this->register_action('plugin.acl', array($this, 'acl_actions')); |
| | | $this->register_action('plugin.acl-autocomplete', array($this, 'acl_autocomplete')); |
| | | } |
| | | |
| | | /** |
| | | * Handler for plugin actions (AJAX) |
| | | */ |
| | | function acl_actions() |
| | | { |
| | | $action = trim(get_input_value('_act', RCUBE_INPUT_GPC)); |
| | | |
| | | // Connect to IMAP |
| | | $this->rc->imap_init(); |
| | | $this->rc->imap_connect(); |
| | | |
| | | // Load localization and configuration |
| | | $this->add_texts('localization/'); |
| | | $this->load_config(); |
| | | |
| | | if ($action == 'save') { |
| | | $this->action_save(); |
| | | } |
| | | else if ($action == 'delete') { |
| | | $this->action_delete(); |
| | | } |
| | | else if ($action == 'list') { |
| | | $this->action_list(); |
| | | } |
| | | |
| | | // Only AJAX actions |
| | | $this->rc->output->send(); |
| | | } |
| | | |
| | | /** |
| | | * Handler for user login autocomplete request |
| | | */ |
| | | function acl_autocomplete() |
| | | { |
| | | $this->load_config(); |
| | | |
| | | $search = get_input_value('_search', RCUBE_INPUT_GPC, true); |
| | | $users = array(); |
| | | |
| | | if ($this->init_ldap()) { |
| | | $this->ldap->set_pagesize(15); |
| | | $result = $this->ldap->search('*', $search); |
| | | |
| | | foreach ($result->records as $record) { |
| | | $user = $record['uid']; |
| | | |
| | | if (is_array($user)) { |
| | | $user = array_filter($user); |
| | | $user = $user[0]; |
| | | } |
| | | |
| | | if ($user) { |
| | | if ($record['name']) |
| | | $user = $record['name'] . ' (' . $user . ')'; |
| | | |
| | | $users[] = $user; |
| | | } |
| | | } |
| | | } |
| | | |
| | | sort($users, SORT_LOCALE_STRING); |
| | | |
| | | $this->rc->output->command('ksearch_query_results', $users, $search); |
| | | $this->rc->output->send(); |
| | | } |
| | | |
| | | /** |
| | | * Handler for 'folder_form' hook |
| | | * |
| | | * @param array $args Hook arguments array (form data) |
| | | * |
| | | * @return array Hook arguments array |
| | | */ |
| | | function folder_form($args) |
| | | { |
| | | // Edited folder name (empty in create-folder mode) |
| | | $mbox_imap = $args['options']['name']; |
| | | if (!strlen($mbox_imap)) { |
| | | return $args; |
| | | } |
| | | /* |
| | | // Do nothing on protected folders (?) |
| | | if ($args['options']['protected']) { |
| | | return $args; |
| | | } |
| | | */ |
| | | // Namespace root |
| | | if ($args['options']['is_root']) { |
| | | return $args; |
| | | } |
| | | |
| | | // Get MYRIGHTS |
| | | if (!($myrights = $args['options']['rights'])) { |
| | | return $args; |
| | | } |
| | | |
| | | // Do nothing if no ACL support |
| | | if (!$this->rc->imap->get_capability('ACL')) { |
| | | return $args; |
| | | } |
| | | |
| | | // Load localization and include scripts |
| | | $this->load_config(); |
| | | $this->add_texts('localization/', array('deleteconfirm', 'norights', |
| | | 'nouser', 'deleting', 'saving')); |
| | | $this->include_script('acl.js'); |
| | | $this->rc->output->include_script('list.js'); |
| | | $this->include_stylesheet($this->local_skin_path().'/acl.css'); |
| | | |
| | | // add Info fieldset if it doesn't exist |
| | | if (!isset($args['form']['props']['fieldsets']['info'])) |
| | | $args['form']['props']['fieldsets']['info'] = array( |
| | | 'name' => rcube_label('info'), |
| | | 'content' => array()); |
| | | |
| | | // Display folder rights to 'Info' fieldset |
| | | $args['form']['props']['fieldsets']['info']['content']['myrights'] = array( |
| | | 'label' => Q($this->gettext('myrights')), |
| | | 'value' => $this->acl2text($myrights) |
| | | ); |
| | | |
| | | // Return if not folder admin |
| | | if (!in_array('a', $myrights)) { |
| | | return $args; |
| | | } |
| | | |
| | | // The 'Sharing' tab |
| | | $this->mbox = $mbox_imap; |
| | | $this->rc->output->set_env('acl_users_source', (bool) $this->rc->config->get('acl_users_source')); |
| | | $this->rc->output->set_env('mailbox', $mbox_imap); |
| | | $this->rc->output->add_handlers(array( |
| | | 'acltable' => array($this, 'templ_table'), |
| | | 'acluser' => array($this, 'templ_user'), |
| | | 'aclrights' => array($this, 'templ_rights'), |
| | | )); |
| | | |
| | | $args['form']['sharing'] = array( |
| | | 'name' => Q($this->gettext('sharing')), |
| | | 'content' => $this->rc->output->parse('acl.table', false, false), |
| | | ); |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Creates ACL rights table |
| | | * |
| | | * @param array $attrib Template object attributes |
| | | * |
| | | * @return string HTML Content |
| | | */ |
| | | function templ_table($attrib) |
| | | { |
| | | if (empty($attrib['id'])) |
| | | $attrib['id'] = 'acl-table'; |
| | | |
| | | $out = $this->list_rights($attrib); |
| | | |
| | | $this->rc->output->add_gui_object('acltable', $attrib['id']); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Creates ACL rights form (rights list part) |
| | | * |
| | | * @param array $attrib Template object attributes |
| | | * |
| | | * @return string HTML Content |
| | | */ |
| | | function templ_rights($attrib) |
| | | { |
| | | // Get supported rights |
| | | $supported = $this->rights_supported(); |
| | | |
| | | // depending on server capability either use 'te' or 'd' for deleting msgs |
| | | $deleteright = implode(array_intersect(str_split('ted'), $supported)); |
| | | |
| | | $out = ''; |
| | | $ul = ''; |
| | | $input = new html_checkbox(); |
| | | |
| | | // Advanced rights |
| | | $attrib['id'] = 'advancedrights'; |
| | | foreach ($supported as $val) { |
| | | $id = "acl$val"; |
| | | $ul .= html::tag('li', null, |
| | | $input->show('', array( |
| | | 'name' => "acl[$val]", 'value' => $val, 'id' => $id)) |
| | | . html::label(array('for' => $id, 'title' => $this->gettext('longacl'.$val)), |
| | | $this->gettext('acl'.$val))); |
| | | } |
| | | |
| | | $out = html::tag('ul', $attrib, $ul, html::$common_attrib); |
| | | |
| | | // Simple rights |
| | | $ul = ''; |
| | | $attrib['id'] = 'simplerights'; |
| | | $items = array( |
| | | 'read' => 'lrs', |
| | | 'write' => 'wi', |
| | | 'delete' => $deleteright, |
| | | 'other' => preg_replace('/[lrswi'.$deleteright.']/', '', implode($supported)), |
| | | ); |
| | | |
| | | foreach ($items as $key => $val) { |
| | | $id = "acl$key"; |
| | | $ul .= html::tag('li', null, |
| | | $input->show('', array( |
| | | 'name' => "acl[$val]", 'value' => $val, 'id' => $id)) |
| | | . html::label(array('for' => $id, 'title' => $this->gettext('longacl'.$key)), |
| | | $this->gettext('acl'.$key))); |
| | | } |
| | | |
| | | $out .= "\n" . html::tag('ul', $attrib, $ul, html::$common_attrib); |
| | | |
| | | $this->rc->output->set_env('acl_items', $items); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Creates ACL rights form (user part) |
| | | * |
| | | * @param array $attrib Template object attributes |
| | | * |
| | | * @return string HTML Content |
| | | */ |
| | | function templ_user($attrib) |
| | | { |
| | | // Create username input |
| | | $attrib['name'] = 'acluser'; |
| | | |
| | | $textfield = new html_inputfield($attrib); |
| | | |
| | | $fields['user'] = html::label(array('for' => 'iduser'), $this->gettext('username')) |
| | | . ' ' . $textfield->show(); |
| | | |
| | | // Add special entries |
| | | if (!empty($this->specials)) { |
| | | foreach ($this->specials as $key) { |
| | | $fields[$key] = html::label(array('for' => 'id'.$key), $this->gettext($key)); |
| | | } |
| | | } |
| | | |
| | | $this->rc->output->set_env('acl_specials', $this->specials); |
| | | |
| | | // Create list with radio buttons |
| | | if (count($fields) > 1) { |
| | | $ul = ''; |
| | | $radio = new html_radiobutton(array('name' => 'usertype')); |
| | | foreach ($fields as $key => $val) { |
| | | $ul .= html::tag('li', null, $radio->show($key == 'user' ? 'user' : '', |
| | | array('value' => $key, 'id' => 'id'.$key)) |
| | | . $val); |
| | | } |
| | | |
| | | $out = html::tag('ul', array('id' => 'usertype'), $ul, html::$common_attrib); |
| | | } |
| | | // Display text input alone |
| | | else { |
| | | $out = $fields['user']; |
| | | } |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Creates ACL rights table |
| | | * |
| | | * @param array $attrib Template object attributes |
| | | * |
| | | * @return string HTML Content |
| | | */ |
| | | private function list_rights($attrib=array()) |
| | | { |
| | | // Get ACL for the folder |
| | | $acl = $this->rc->imap->get_acl($this->mbox); |
| | | |
| | | if (!is_array($acl)) { |
| | | $acl = array(); |
| | | } |
| | | |
| | | // Keep special entries (anyone/anonymous) on top of the list |
| | | if (!empty($this->specials) && !empty($acl)) { |
| | | foreach ($this->specials as $key) { |
| | | if (isset($acl[$key])) { |
| | | $acl_special[$key] = $acl[$key]; |
| | | unset($acl[$key]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Sort the list by username |
| | | uksort($acl, 'strnatcasecmp'); |
| | | |
| | | if (!empty($acl_special)) { |
| | | $acl = array_merge($acl_special, $acl); |
| | | } |
| | | |
| | | // Get supported rights and build column names |
| | | $supported = $this->rights_supported(); |
| | | |
| | | // depending on server capability either use 'te' or 'd' for deleting msgs |
| | | $deleteright = implode(array_intersect(str_split('ted'), $supported)); |
| | | |
| | | // Use advanced or simple (grouped) rights |
| | | $advanced = $this->rc->config->get('acl_advanced_mode'); |
| | | |
| | | if ($advanced) { |
| | | $items = array(); |
| | | foreach ($supported as $sup) { |
| | | $items[$sup] = $sup; |
| | | } |
| | | } |
| | | else { |
| | | $items = array( |
| | | 'read' => 'lrs', |
| | | 'write' => 'wi', |
| | | 'delete' => $deleteright, |
| | | 'other' => preg_replace('/[lrswi'.$deleteright.']/', '', implode($supported)), |
| | | ); |
| | | } |
| | | |
| | | // Create the table |
| | | $attrib['noheader'] = true; |
| | | $table = new html_table($attrib); |
| | | |
| | | // Create table header |
| | | $table->add_header('user', $this->gettext('identifier')); |
| | | foreach (array_keys($items) as $key) { |
| | | $table->add_header('acl'.$key, $this->gettext('shortacl'.$key)); |
| | | } |
| | | |
| | | $i = 1; |
| | | $js_table = array(); |
| | | foreach ($acl as $user => $rights) { |
| | | if ($this->rc->imap->conn->user == $user) { |
| | | continue; |
| | | } |
| | | |
| | | // filter out virtual rights (c or d) the server may return |
| | | $userrights = array_intersect($rights, $supported); |
| | | $userid = html_identifier($user); |
| | | |
| | | if (!empty($this->specials) && in_array($user, $this->specials)) { |
| | | $user = $this->gettext($user); |
| | | } |
| | | |
| | | $table->add_row(array('id' => 'rcmrow'.$userid)); |
| | | $table->add('user', Q($user)); |
| | | |
| | | foreach ($items as $key => $right) { |
| | | $in = $this->acl_compare($userrights, $right); |
| | | switch ($in) { |
| | | case 2: $class = 'enabled'; break; |
| | | case 1: $class = 'partial'; break; |
| | | default: $class = 'disabled'; break; |
| | | } |
| | | $table->add('acl' . $key . ' ' . $class, ''); |
| | | } |
| | | |
| | | $js_table[$userid] = implode($userrights); |
| | | } |
| | | |
| | | $this->rc->output->set_env('acl', $js_table); |
| | | $this->rc->output->set_env('acl_advanced', $advanced); |
| | | |
| | | $out = $table->show(); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Handler for ACL update/create action |
| | | */ |
| | | private function action_save() |
| | | { |
| | | $mbox = trim(get_input_value('_mbox', RCUBE_INPUT_GPC, true, 'UTF7-IMAP')); |
| | | $user = trim(get_input_value('_user', RCUBE_INPUT_GPC)); |
| | | $acl = trim(get_input_value('_acl', RCUBE_INPUT_GPC)); |
| | | $oldid = trim(get_input_value('_old', RCUBE_INPUT_GPC)); |
| | | |
| | | $acl = array_intersect(str_split($acl), $this->rights_supported()); |
| | | |
| | | if (!empty($this->specials) && in_array($user, $this->specials)) { |
| | | $username = $this->gettext($user); |
| | | } |
| | | else { |
| | | if (!strpos($user, '@') && ($realm = $this->get_realm())) { |
| | | $user .= '@' . rcube_idn_to_ascii(preg_replace('/^@/', '', $realm)); |
| | | } |
| | | $username = $user; |
| | | } |
| | | |
| | | if ($acl && $user && $user != $_SESSION['username'] && strlen($mbox)) { |
| | | $result = $this->rc->imap->set_acl($mbox, $user, $acl); |
| | | } |
| | | |
| | | if ($result) { |
| | | $ret = array('id' => html_identifier($user), |
| | | 'username' => $username, 'acl' => implode($acl), 'old' => $oldid); |
| | | $this->rc->output->command('acl_update', $ret); |
| | | $this->rc->output->show_message($oldid ? 'acl.updatesuccess' : 'acl.createsuccess', 'confirmation'); |
| | | } |
| | | else { |
| | | $this->rc->output->show_message($oldid ? 'acl.updateerror' : 'acl.createerror', 'error'); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for ACL delete action |
| | | */ |
| | | private function action_delete() |
| | | { |
| | | $mbox = trim(get_input_value('_mbox', RCUBE_INPUT_GPC, true, 'UTF7-IMAP')); |
| | | $user = trim(get_input_value('_user', RCUBE_INPUT_GPC)); |
| | | |
| | | $user = explode(',', $user); |
| | | |
| | | foreach ($user as $u) { |
| | | if ($this->rc->imap->delete_acl($mbox, $u)) { |
| | | $this->rc->output->command('acl_remove_row', html_identifier($u)); |
| | | } |
| | | else { |
| | | $error = true; |
| | | } |
| | | } |
| | | |
| | | if (!$error) { |
| | | $this->rc->output->show_message('acl.deletesuccess', 'confirmation'); |
| | | } |
| | | else { |
| | | $this->rc->output->show_message('acl.deleteerror', 'error'); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for ACL list update action (with display mode change) |
| | | */ |
| | | private function action_list() |
| | | { |
| | | if (in_array('acl_advanced_mode', (array)$this->rc->config->get('dont_override'))) { |
| | | return; |
| | | } |
| | | |
| | | $this->mbox = trim(get_input_value('_mbox', RCUBE_INPUT_GPC, true, 'UTF7-IMAP')); |
| | | $advanced = trim(get_input_value('_mode', RCUBE_INPUT_GPC)); |
| | | $advanced = $advanced == 'advanced' ? true : false; |
| | | |
| | | // Save state in user preferences |
| | | $this->rc->user->save_prefs(array('acl_advanced_mode' => $advanced)); |
| | | |
| | | $out = $this->list_rights(); |
| | | |
| | | $out = preg_replace(array('/^<table[^>]+>/', '/<\/table>$/'), '', $out); |
| | | |
| | | $this->rc->output->command('acl_list_update', $out); |
| | | } |
| | | |
| | | /** |
| | | * Creates <UL> list with descriptive access rights |
| | | * |
| | | * @param array $rights MYRIGHTS result |
| | | * |
| | | * @return string HTML content |
| | | */ |
| | | function acl2text($rights) |
| | | { |
| | | if (empty($rights)) { |
| | | return ''; |
| | | } |
| | | |
| | | $supported = $this->rights_supported(); |
| | | $list = array(); |
| | | $attrib = array( |
| | | 'name' => 'rcmyrights', |
| | | 'style' => 'padding: 0 15px;', |
| | | ); |
| | | |
| | | foreach ($supported as $right) { |
| | | if (in_array($right, $rights)) { |
| | | $list[] = html::tag('li', null, Q($this->gettext('acl' . $right))); |
| | | } |
| | | } |
| | | |
| | | if (count($list) == count($supported)) |
| | | return Q($this->gettext('aclfull')); |
| | | |
| | | return html::tag('ul', $attrib, implode("\n", $list)); |
| | | } |
| | | |
| | | /** |
| | | * Compares two ACLs (according to supported rights) |
| | | * |
| | | * @param array $acl1 ACL rights array (or string) |
| | | * @param array $acl2 ACL rights array (or string) |
| | | * |
| | | * @param int Comparision result, 2 - full match, 1 - partial match, 0 - no match |
| | | */ |
| | | function acl_compare($acl1, $acl2) |
| | | { |
| | | if (!is_array($acl1)) $acl1 = str_split($acl1); |
| | | if (!is_array($acl2)) $acl2 = str_split($acl2); |
| | | |
| | | $rights = $this->rights_supported(); |
| | | |
| | | $acl1 = array_intersect($acl1, $rights); |
| | | $acl2 = array_intersect($acl2, $rights); |
| | | $res = array_intersect($acl1, $acl2); |
| | | |
| | | $cnt1 = count($res); |
| | | $cnt2 = count($acl2); |
| | | |
| | | if ($cnt1 == $cnt2) |
| | | return 2; |
| | | else if ($cnt1) |
| | | return 1; |
| | | else |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * Get list of supported access rights (according to RIGHTS capability) |
| | | * |
| | | * @return array List of supported access rights abbreviations |
| | | */ |
| | | function rights_supported() |
| | | { |
| | | if ($this->supported !== null) { |
| | | return $this->supported; |
| | | } |
| | | |
| | | $capa = $this->rc->imap->get_capability('RIGHTS'); |
| | | |
| | | if (is_array($capa)) { |
| | | $rights = strtolower($capa[0]); |
| | | } |
| | | else { |
| | | $rights = 'cd'; |
| | | } |
| | | |
| | | return $this->supported = str_split('lrswi' . $rights . 'pa'); |
| | | } |
| | | |
| | | /** |
| | | * Username realm detection. |
| | | * |
| | | * @return string Username realm (domain) |
| | | */ |
| | | private function get_realm() |
| | | { |
| | | // When user enters a username without domain part, realm |
| | | // alows to add it to the username (and display correct username in the table) |
| | | |
| | | if (isset($_SESSION['acl_username_realm'])) { |
| | | return $_SESSION['acl_username_realm']; |
| | | } |
| | | |
| | | // find realm in username of logged user (?) |
| | | list($name, $domain) = explode('@', $_SESSION['username']); |
| | | |
| | | // Use (always existent) ACL entry on the INBOX for the user to determine |
| | | // whether or not the user ID in ACL entries need to be qualified and how |
| | | // they would need to be qualified. |
| | | if (empty($domain)) { |
| | | $acl = $this->rc->imap->get_acl('INBOX'); |
| | | if (is_array($acl)) { |
| | | $regexp = '/^' . preg_quote($_SESSION['username'], '/') . '@(.*)$/'; |
| | | $regexp = '/^' . preg_quote('aleksander.machniak', '/') . '@(.*)$/'; |
| | | foreach (array_keys($acl) as $name) { |
| | | if (preg_match($regexp, $name, $matches)) { |
| | | $domain = $matches[1]; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $_SESSION['acl_username_realm'] = $domain; |
| | | } |
| | | |
| | | /** |
| | | * Initializes autocomplete LDAP backend |
| | | */ |
| | | private function init_ldap() |
| | | { |
| | | if ($this->ldap) |
| | | return $this->ldap->ready; |
| | | |
| | | // get LDAP config |
| | | $config = $this->rc->config->get('acl_users_source'); |
| | | |
| | | if (empty($config)) { |
| | | return false; |
| | | } |
| | | |
| | | // not an array, use configured ldap_public source |
| | | if (!is_array($config)) { |
| | | $ldap_config = (array) $this->rc->config->get('ldap_public'); |
| | | $config = $ldap_config[$config]; |
| | | } |
| | | |
| | | $uid_field = $this->rc->config->get('acl_users_field', 'mail'); |
| | | $filter = $this->rc->config->get('acl_users_filter'); |
| | | |
| | | if (empty($uid_field) || empty($config)) { |
| | | return false; |
| | | } |
| | | |
| | | // get name attribute |
| | | if (!empty($config['fieldmap'])) { |
| | | $name_field = $config['fieldmap']['name']; |
| | | } |
| | | // ... no fieldmap, use the old method |
| | | if (empty($name_field)) { |
| | | $name_field = $config['name_field']; |
| | | } |
| | | |
| | | // add UID field to fieldmap, so it will be returned in a record with name |
| | | $config['fieldmap'] = array( |
| | | 'name' => $name_field, |
| | | 'uid' => $uid_field, |
| | | ); |
| | | |
| | | // search in UID and name fields |
| | | $config['search_fields'] = array_values($config['fieldmap']); |
| | | $config['required_fields'] = array($uid_field); |
| | | |
| | | // set search filter |
| | | if ($filter) |
| | | $config['filter'] = $filter; |
| | | |
| | | // disable vlv |
| | | $config['vlv'] = false; |
| | | |
| | | // Initialize LDAP connection |
| | | $this->ldap = new rcube_ldap($config, |
| | | $this->rc->config->get('ldap_debug'), |
| | | $this->rc->config->mail_domain($_SESSION['imap_host'])); |
| | | |
| | | return $this->ldap->ready; |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | // Default look of access rights table |
| | | // In advanced mode all access rights are displayed separately |
| | | // In simple mode access rights are grouped into four groups: read, write, delete, full |
| | | $rcmail_config['acl_advanced_mode'] = false; |
| | | |
| | | // LDAP addressbook that would be searched for user names autocomplete. |
| | | // That should be an array refering to the $rcmail_config['ldap_public'] array key |
| | | // or complete addressbook configuration array. |
| | | $rcmail_config['acl_users_source'] = ''; |
| | | |
| | | // The LDAP attribute which will be used as ACL user identifier |
| | | $rcmail_config['acl_users_field'] = 'mail'; |
| | | |
| | | // The LDAP search filter will be &'d with search queries |
| | | $rcmail_config['acl_users_filter'] = ''; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels['sharing'] = 'Sharing'; |
| | | $labels['myrights'] = 'Access Rights'; |
| | | $labels['username'] = 'User:'; |
| | | $labels['advanced'] = 'advanced mode'; |
| | | $labels['newuser'] = 'Add entry'; |
| | | $labels['actions'] = 'Access right actions...'; |
| | | $labels['anyone'] = 'All users (anyone)'; |
| | | $labels['anonymous'] = 'Guests (anonymous)'; |
| | | $labels['identifier'] = 'Identifier'; |
| | | |
| | | $labels['acll'] = 'Lookup'; |
| | | $labels['aclr'] = 'Read messages'; |
| | | $labels['acls'] = 'Keep Seen state'; |
| | | $labels['aclw'] = 'Write flags'; |
| | | $labels['acli'] = 'Insert (Copy into)'; |
| | | $labels['aclp'] = 'Post'; |
| | | $labels['aclc'] = 'Create subfolders'; |
| | | $labels['aclk'] = 'Create subfolders'; |
| | | $labels['acld'] = 'Delete messages'; |
| | | $labels['aclt'] = 'Delete messages'; |
| | | $labels['acle'] = 'Expunge'; |
| | | $labels['aclx'] = 'Delete folder'; |
| | | $labels['acla'] = 'Administer'; |
| | | |
| | | $labels['aclfull'] = 'Full control'; |
| | | $labels['aclother'] = 'Other'; |
| | | $labels['aclread'] = 'Read'; |
| | | $labels['aclwrite'] = 'Write'; |
| | | $labels['acldelete'] = 'Delete'; |
| | | |
| | | $labels['shortacll'] = 'Lookup'; |
| | | $labels['shortaclr'] = 'Read'; |
| | | $labels['shortacls'] = 'Keep'; |
| | | $labels['shortaclw'] = 'Write'; |
| | | $labels['shortacli'] = 'Insert'; |
| | | $labels['shortaclp'] = 'Post'; |
| | | $labels['shortaclc'] = 'Create'; |
| | | $labels['shortaclk'] = 'Create'; |
| | | $labels['shortacld'] = 'Delete'; |
| | | $labels['shortaclt'] = 'Delete'; |
| | | $labels['shortacle'] = 'Expunge'; |
| | | $labels['shortaclx'] = 'Folder delete'; |
| | | $labels['shortacla'] = 'Administer'; |
| | | |
| | | $labels['shortaclother'] = 'Other'; |
| | | $labels['shortaclread'] = 'Read'; |
| | | $labels['shortaclwrite'] = 'Write'; |
| | | $labels['shortacldelete'] = 'Delete'; |
| | | |
| | | $labels['longacll'] = 'The folder is visible on lists and can be subscribed to'; |
| | | $labels['longaclr'] = 'The folder can be opened for reading'; |
| | | $labels['longacls'] = 'Messages Seen flag can be changed'; |
| | | $labels['longaclw'] = 'Messages flags and keywords can be changed, except Seen and Deleted'; |
| | | $labels['longacli'] = 'Messages can be written or copied to the folder'; |
| | | $labels['longaclp'] = 'Messages can be posted to this folder'; |
| | | $labels['longaclc'] = 'Folders can be created (or renamed) directly under this folder'; |
| | | $labels['longaclk'] = 'Folders can be created (or renamed) directly under this folder'; |
| | | $labels['longacld'] = 'Messages Delete flag can be changed'; |
| | | $labels['longaclt'] = 'Messages Delete flag can be changed'; |
| | | $labels['longacle'] = 'Messages can be expunged'; |
| | | $labels['longaclx'] = 'The folder can be deleted or renamed'; |
| | | $labels['longacla'] = 'The folder access rights can be changed'; |
| | | |
| | | $labels['longaclfull'] = 'Full control including folder administration'; |
| | | $labels['longaclread'] = 'The folder can be opened for reading'; |
| | | $labels['longaclwrite'] = 'Messages can be marked, written or copied to the folder'; |
| | | $labels['longacldelete'] = 'Messages can be deleted'; |
| | | |
| | | $messages['deleting'] = 'Deleting access rights...'; |
| | | $messages['saving'] = 'Saving access rights...'; |
| | | $messages['updatesuccess'] = 'Successfully changed access rights'; |
| | | $messages['deletesuccess'] = 'Successfully deleted access rights'; |
| | | $messages['createsuccess'] = 'Successfully added access rights'; |
| | | $messages['updateerror'] = 'Ubable to update access rights'; |
| | | $messages['deleteerror'] = 'Unable to delete access rights'; |
| | | $messages['createerror'] = 'Unable to add access rights'; |
| | | $messages['deleteconfirm'] = 'Are you sure, you want to remove access rights of selected user(s)?'; |
| | | $messages['norights'] = 'No rights has been specified!'; |
| | | $messages['nouser'] = 'No username has been specified!'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels['sharing'] = 'Udostępnianie'; |
| | | $labels['myrights'] = 'Prawa dostępu'; |
| | | $labels['username'] = 'Użytkownik:'; |
| | | $labels['advanced'] = 'tryb zaawansowany'; |
| | | $labels['newuser'] = 'Dodaj rekord'; |
| | | $labels['actions'] = 'Akcje na prawach...'; |
| | | $labels['anyone'] = 'Wszyscy (anyone)'; |
| | | $labels['anonymous'] = 'Goście (anonymous)'; |
| | | $labels['identifier'] = 'Identyfikator'; |
| | | |
| | | $labels['acll'] = 'Podgląd (Lookup)'; |
| | | $labels['aclr'] = 'Odczyt (Read)'; |
| | | $labels['acls'] = 'Zmiana stanu wiadomości (Keep)'; |
| | | $labels['aclw'] = 'Zmiana flag wiadomości (Write)'; |
| | | $labels['acli'] = 'Dodawanie/Kopiowanie do (Insert)'; |
| | | $labels['aclp'] = 'Wysyłanie (Post)'; |
| | | $labels['aclc'] = 'Tworzenie podfolderów (Create)'; |
| | | $labels['aclk'] = 'Tworzenie podfolderów (Create)'; |
| | | $labels['acld'] = 'Usuwanie wiadomości (Delete)'; |
| | | $labels['aclt'] = 'Usuwanie wiadomości (Delete)'; |
| | | $labels['acle'] = 'Porządkowanie folderu (Expunge)'; |
| | | $labels['aclx'] = 'Usuwanie folderu (Delete)'; |
| | | $labels['acla'] = 'Administracja (Administer)'; |
| | | |
| | | $labels['aclfull'] = 'Wszystkie'; |
| | | $labels['aclother'] = 'Inne'; |
| | | $labels['aclread'] = 'Odczyt'; |
| | | $labels['aclwrite'] = 'Zapis'; |
| | | $labels['acldelete'] = 'Usuwanie'; |
| | | |
| | | $labels['shortacll'] = 'Podgląd'; |
| | | $labels['shortaclr'] = 'Odczyt'; |
| | | $labels['shortacls'] = 'Zmiana'; |
| | | $labels['shortaclw'] = 'Zmiana flag'; |
| | | $labels['shortacli'] = 'Dodawanie'; |
| | | $labels['shortaclp'] = 'Wysyłanie'; |
| | | $labels['shortaclc'] = 'Tworzenie'; |
| | | $labels['shortaclk'] = 'Tworzenie'; |
| | | $labels['shortacld'] = 'Usuwanie'; |
| | | $labels['shortaclt'] = 'Usuwanie'; |
| | | $labels['shortacle'] = 'Porządkowanie'; |
| | | $labels['shortaclx'] = 'Usuwanie folderu'; |
| | | $labels['shortacla'] = 'Administracja'; |
| | | |
| | | $labels['shortaclother'] = 'Pozostałe'; |
| | | $labels['shortaclread'] = 'Odczyt'; |
| | | $labels['shortaclwrite'] = 'Zapis'; |
| | | $labels['shortacldelete'] = 'Usuwanie'; |
| | | |
| | | $labels['longacll'] = 'Pozwala na subskrybowanie folderu i powoduje, że jest on widoczny na liście'; |
| | | $labels['longaclr'] = 'Pozwala na otwarcie folderu w trybie do odczytu'; |
| | | $labels['longacls'] = 'Pozwala na zmienę stanu wiadomości'; |
| | | $labels['longaclw'] = 'Pozwala zmieniać wszystkie flagi wiadomości, oprócz "Przeczytano" i "Usunięto"'; |
| | | $labels['longacli'] = 'Pozwala zapisywać wiadomości i kopiować do folderu'; |
| | | $labels['longaclp'] = 'Pozwala wysyłać wiadomości do folderu'; |
| | | $labels['longaclc'] = 'Pozwala tworzyć (lub zmieniać nazwę) podfoldery'; |
| | | $labels['longaclk'] = 'Pozwala tworzyć (lub zmieniać nazwę) podfoldery'; |
| | | $labels['longacld'] = 'Pozwala zmianiać flagę "Usunięto" wiadomości'; |
| | | $labels['longaclt'] = 'Pozwala zmianiać flagę "Usunięto" wiadomości'; |
| | | $labels['longacle'] = 'Pozwala na usuwanie wiadomości oznaczonych do usunięcia'; |
| | | $labels['longaclx'] = 'Pozwala na zmianę nazwy lub usunięcie folderu'; |
| | | $labels['longacla'] = 'Pozwala na zmiane praw dostępu do folderu'; |
| | | |
| | | $labels['longaclfull'] = 'Pełna kontrola włącznie z administrowaniem folderem'; |
| | | $labels['longaclread'] = 'Folder może być otwarty w trybie do odczytu'; |
| | | $labels['longaclwrite'] = 'Wiadomości mogą być oznaczane, zapisywane i kopiowane do folderu'; |
| | | $labels['longacldelete'] = 'Wiadomości mogą być usuwane'; |
| | | |
| | | $messages['deleting'] = 'Usuwanie praw dostępu...'; |
| | | $messages['saving'] = 'Zapisywanie praw dostępu...'; |
| | | $messages['updatesuccess'] = 'Pomyślnie zmieniono prawa dostępu'; |
| | | $messages['deletesuccess'] = 'Pomyślnie usunięto prawa dostępu'; |
| | | $messages['createsuccess'] = 'Pomyślnie dodano prawa dostępu'; |
| | | $messages['updateerror'] = 'Nie udało się zmienić praw dostępu'; |
| | | $messages['deleteerror'] = 'Nie udało się usunąć praw dostępu'; |
| | | $messages['createerror'] = 'Nie udało się dodać praw dostępu'; |
| | | $messages['deleteconfirm'] = 'Czy na pewno chcesz usunąć prawa wybranym użytkownikom?'; |
| | | $messages['norights'] = 'Nie wybrano praw dostępu!'; |
| | | $messages['nouser'] = 'Nie podano nazwy użytkownika!'; |
| | | |
| | | ?> |
New file |
| | |
| | | #aclmanager |
| | | { |
| | | position: relative; |
| | | border: 1px solid #999; |
| | | min-height: 302px; |
| | | } |
| | | |
| | | #aclcontainer |
| | | { |
| | | overflow-x: auto; |
| | | } |
| | | |
| | | #acltable |
| | | { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | background-color: #F9F9F9; |
| | | } |
| | | |
| | | #acltable td |
| | | { |
| | | width: 1%; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | #acltable thead td |
| | | { |
| | | padding: 0 4px 0 2px; |
| | | } |
| | | |
| | | #acltable tbody td |
| | | { |
| | | text-align: center; |
| | | padding: 2px; |
| | | border-bottom: 1px solid #999999; |
| | | cursor: default; |
| | | } |
| | | |
| | | #acltable tbody td.user |
| | | { |
| | | width: 96%; |
| | | text-align: left; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | -o-text-overflow: ellipsis; |
| | | } |
| | | |
| | | #acltable tbody td.partial |
| | | { |
| | | background: url(images/partial.png) center no-repeat; |
| | | } |
| | | |
| | | #acltable tbody td.enabled |
| | | { |
| | | background: url(images/enabled.png) center no-repeat; |
| | | } |
| | | |
| | | #acltable tr.selected td |
| | | { |
| | | color: #FFFFFF; |
| | | background-color: #CC3333; |
| | | } |
| | | |
| | | #acladvswitch |
| | | { |
| | | position: absolute; |
| | | right: 4px; |
| | | text-align: right; |
| | | line-height: 22px; |
| | | } |
| | | |
| | | #acladvswitch input |
| | | { |
| | | vertical-align: middle; |
| | | } |
| | | |
| | | #acladvswitch span |
| | | { |
| | | display: block; |
| | | } |
| | | |
| | | #aclform |
| | | { |
| | | top: 100px; |
| | | width: 480px; |
| | | padding: 10px; |
| | | } |
| | | |
| | | #aclform div |
| | | { |
| | | padding: 0; |
| | | text-align: center; |
| | | clear: both; |
| | | } |
New file |
| | |
| | | <!--[if lte IE 6]> |
| | | <style type="text/css"> |
| | | #aclmanager { height: expression(Math.min(302, parseInt(document.documentElement.clientHeight))+'px'); } |
| | | </style> |
| | | <![endif]--> |
| | | |
| | | <div id="aclmanager"> |
| | | <div id="aclcontainer" class="boxlistcontent" style="top:0"> |
| | | <roundcube:object name="acltable" id="acltable" class="records-table" /> |
| | | </div> |
| | | <div class="boxfooter"> |
| | | <roundcube:button command="acl-create" id="aclcreatelink" type="link" title="acl.newuser" class="buttonPas addgroup" classAct="button addgroup" content=" " /> |
| | | <roundcube:button name="aclmenulink" id="aclmenulink" type="link" title="acl.actions" class="button groupactions" onclick="show_aclmenu(); return false" content=" " /> |
| | | <roundcube:if condition="!in_array('acl_advanced_mode', (array)config:dont_override)" /> |
| | | <div id="acladvswitch" class="pagenav"> |
| | | <span><label for="acl-switch"><roundcube:label name="acl.advanced" /></label> |
| | | <input type="checkbox" id="acl-switch" onclick="rcmail.command('acl-mode-switch')"<roundcube:exp expression="config:acl_advanced_mode == true ? ' checked=checked' : ''" /> /> |
| | | </span> |
| | | </div> |
| | | <roundcube:endif /> |
| | | </div> |
| | | </div> |
| | | |
| | | <div id="aclmenu" class="popupmenu"> |
| | | <ul> |
| | | <li><roundcube:button command="acl-edit" label="edit" classAct="active" /></li> |
| | | <li><roundcube:button command="acl-delete" label="delete" classAct="active" /></li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <div id="aclform" class="popupmenu"> |
| | | <fieldset class="thinbordered"><legend><roundcube:label name="acl.identifier" /></legend> |
| | | <roundcube:object name="acluser" class="toolbarmenu" id="acluser" size="35" /> |
| | | </fieldset> |
| | | <fieldset class="thinbordered"><legend><roundcube:label name="acl.myrights" /></legend> |
| | | <roundcube:object name="aclrights" class="toolbarmenu" /> |
| | | </fieldset> |
| | | <div> |
| | | <roundcube:button command="acl-cancel" type="input" class="button" label="cancel" /> |
| | | <roundcube:button command="acl-save" type="input" class="button mainaction" label="save" /> |
| | | </div> |
| | | </div> |
| | | |
| | | <script type="text/javascript"> |
| | | function show_aclmenu() |
| | | { |
| | | if (!rcmail_ui) { |
| | | rcube_init_mail_ui(); |
| | | rcmail_ui.popups.aclmenu = {id:'aclmenu', above:1, obj: $('#aclmenu')}; |
| | | } |
| | | |
| | | rcmail_ui.show_popup('aclmenu'); |
| | | } |
| | | </script> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Additional Message Headers |
| | | * |
| | | * Very simple plugin which will add additional headers |
| | | * to or remove them from outgoing messages. |
| | | * |
| | | * Enable the plugin in config/main.inc.php and add your desired headers: |
| | | * $rcmail_config['additional_message_headers'] = array('User-Agent'); |
| | | * |
| | | * @version @package_version@ |
| | | * @author Ziba Scott |
| | | * @website http://roundcube.net |
| | | */ |
| | | class additional_message_headers extends rcube_plugin |
| | | { |
| | | public $task = 'mail'; |
| | | |
| | | function init() |
| | | { |
| | | $this->add_hook('message_outgoing_headers', array($this, 'message_headers')); |
| | | } |
| | | |
| | | function message_headers($args) |
| | | { |
| | | $this->load_config(); |
| | | |
| | | // additional email headers |
| | | $additional_headers = rcmail::get_instance()->config->get('additional_message_headers',array()); |
| | | foreach($additional_headers as $header=>$value){ |
| | | if (null === $value) { |
| | | unset($args['headers'][$header]); |
| | | } else { |
| | | $args['headers'][$header] = $value; |
| | | } |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // $rcmail_config['additional_message_headers']['X-Remote-Browser'] = $_SERVER['HTTP_USER_AGENT']; |
| | | // $rcmail_config['additional_message_headers']['X-Originating-IP'] = $_SERVER['REMOTE_ADDR']; |
| | | // $rcmail_config['additional_message_headers']['X-RoundCube-Server'] = $_SERVER['SERVER_ADDR']; |
| | | |
| | | // if( isset( $_SERVER['MACHINE_NAME'] )) { |
| | | // $rcmail_config['additional_message_headers']['X-RoundCube-Server'] .= ' (' . $_SERVER['MACHINE_NAME'] . ')'; |
| | | // } |
| | | |
| | | // To remove (e.g. X-Sender) message header use null value |
| | | // $rcmail_config['additional_message_headers']['X-Sender'] = null; |
| | | |
| | | ?> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <package packagerversion="1.9.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 |
| | | http://pear.php.net/dtd/tasks-1.0.xsd |
| | | http://pear.php.net/dtd/package-2.0 |
| | | http://pear.php.net/dtd/package-2.0.xsd"> |
| | | <name>additional_message_headers</name> |
| | | <channel>pear.roundcube.net</channel> |
| | | <summary>Additional message headers for Roundcube</summary> |
| | | <description>Very simple plugin which will add additional headers to or remove them from outgoing messages.</description> |
| | | <lead> |
| | | <name>Ziba Scott</name> |
| | | <user>ziba</user> |
| | | <email>email@example.org</email> |
| | | <active>yes</active> |
| | | </lead> |
| | | <date>2010-01-16</date> |
| | | <time>18:19:33</time> |
| | | <version> |
| | | <release>1.1.0</release> |
| | | <api>1.1.0</api> |
| | | </version> |
| | | <stability> |
| | | <release>stable</release> |
| | | <api>stable</api> |
| | | </stability> |
| | | <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPL v2</license> |
| | | <notes>-</notes> |
| | | <contents> |
| | | <dir baseinstalldir="/" name="/"> |
| | | <file name="additional_message_headers.php" role="php"> |
| | | <tasks:replace from="@name@" to="name" type="package-info" /> |
| | | <tasks:replace from="@package_version@" to="version" type="package-info" /> |
| | | </file> |
| | | </dir> <!-- / --> |
| | | </contents> |
| | | <dependencies> |
| | | <required> |
| | | <php> |
| | | <min>5.2.1</min> |
| | | </php> |
| | | <pearinstaller> |
| | | <min>1.7.0</min> |
| | | </pearinstaller> |
| | | </required> |
| | | </dependencies> |
| | | <phprelease /> |
| | | </package> |
New file |
| | |
| | | /* |
| | | * Archive plugin script |
| | | * @version @package_version@ |
| | | */ |
| | | |
| | | function rcmail_archive(prop) |
| | | { |
| | | if (!rcmail.env.uid && (!rcmail.message_list || !rcmail.message_list.get_selection().length)) |
| | | return; |
| | | |
| | | if (rcmail.env.mailbox != rcmail.env.archive_folder) |
| | | rcmail.command('moveto', rcmail.env.archive_folder); |
| | | } |
| | | |
| | | // callback for app-onload event |
| | | if (window.rcmail) { |
| | | rcmail.addEventListener('init', function(evt) { |
| | | |
| | | // register command (directly enable in message view mode) |
| | | rcmail.register_command('plugin.archive', rcmail_archive, (rcmail.env.uid && rcmail.env.mailbox != rcmail.env.archive_folder)); |
| | | |
| | | // add event-listener to message list |
| | | if (rcmail.message_list) |
| | | rcmail.message_list.addEventListener('select', function(list){ |
| | | rcmail.enable_command('plugin.archive', (list.get_selection().length > 0 && rcmail.env.mailbox != rcmail.env.archive_folder)); |
| | | }); |
| | | |
| | | // set css style for archive folder |
| | | var li; |
| | | if (rcmail.env.archive_folder && rcmail.env.archive_folder_icon && (li = rcmail.get_folder_li(rcmail.env.archive_folder))) |
| | | $(li).css('background-image', 'url(' + rcmail.env.archive_folder_icon + ')'); |
| | | }) |
| | | } |
| | | |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Archive |
| | | * |
| | | * Plugin that adds a new button to the mailbox toolbar |
| | | * to move messages to a (user selectable) archive folder. |
| | | * |
| | | * @version @package_version@ |
| | | * @author Andre Rodier, Thomas Bruederli |
| | | */ |
| | | class archive extends rcube_plugin |
| | | { |
| | | public $task = 'mail|settings'; |
| | | |
| | | function init() |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | // There is no "Archived flags" |
| | | // $GLOBALS['IMAP_FLAGS']['ARCHIVED'] = 'Archive'; |
| | | if ($rcmail->task == 'mail' && ($rcmail->action == '' || $rcmail->action == 'show') |
| | | && ($archive_folder = $rcmail->config->get('archive_mbox'))) { |
| | | $skin_path = $this->local_skin_path(); |
| | | |
| | | $this->include_script('archive.js'); |
| | | $this->add_texts('localization', true); |
| | | $this->add_button( |
| | | array( |
| | | 'command' => 'plugin.archive', |
| | | 'imagepas' => $skin_path.'/archive_pas.png', |
| | | 'imageact' => $skin_path.'/archive_act.png', |
| | | 'width' => 32, |
| | | 'height' => 32, |
| | | 'title' => 'buttontitle', |
| | | 'domain' => $this->ID, |
| | | ), |
| | | 'toolbar'); |
| | | |
| | | // register hook to localize the archive folder |
| | | $this->add_hook('render_mailboxlist', array($this, 'render_mailboxlist')); |
| | | |
| | | // set env variable for client |
| | | $rcmail->output->set_env('archive_folder', $archive_folder); |
| | | $rcmail->output->set_env('archive_folder_icon', $this->url($skin_path.'/foldericon.png')); |
| | | |
| | | // add archive folder to the list of default mailboxes |
| | | if (($default_folders = $rcmail->config->get('default_imap_folders')) && !in_array($archive_folder, $default_folders)) { |
| | | $default_folders[] = $archive_folder; |
| | | $rcmail->config->set('default_imap_folders', $default_folders); |
| | | } |
| | | } |
| | | else if ($rcmail->task == 'settings') { |
| | | $dont_override = $rcmail->config->get('dont_override', array()); |
| | | if (!in_array('archive_mbox', $dont_override)) { |
| | | $this->add_hook('preferences_list', array($this, 'prefs_table')); |
| | | $this->add_hook('preferences_save', array($this, 'save_prefs')); |
| | | } |
| | | } |
| | | } |
| | | |
| | | function render_mailboxlist($p) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | $archive_folder = $rcmail->config->get('archive_mbox'); |
| | | |
| | | // set localized name for the configured archive folder |
| | | if ($archive_folder) { |
| | | if (isset($p['list'][$archive_folder])) |
| | | $p['list'][$archive_folder]['name'] = $this->gettext('archivefolder'); |
| | | else // search in subfolders |
| | | $this->_mod_folder_name($p['list'], $archive_folder, $this->gettext('archivefolder')); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | function _mod_folder_name(&$list, $folder, $new_name) |
| | | { |
| | | foreach ($list as $idx => $item) { |
| | | if ($item['id'] == $folder) { |
| | | $list[$idx]['name'] = $new_name; |
| | | return true; |
| | | } else if (!empty($item['folders'])) |
| | | if ($this->_mod_folder_name($list[$idx]['folders'], $folder, $new_name)) |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | function prefs_table($args) |
| | | { |
| | | global $CURR_SECTION; |
| | | |
| | | if ($args['section'] == 'folders') { |
| | | $this->add_texts('localization'); |
| | | |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | // load folders list when needed |
| | | if ($CURR_SECTION) |
| | | $select = rcmail_mailbox_select(array('noselection' => '---', 'realnames' => true, |
| | | 'maxlength' => 30, 'exceptions' => array('INBOX'))); |
| | | else |
| | | $select = new html_select(); |
| | | |
| | | $args['blocks']['main']['options']['archive_mbox'] = array( |
| | | 'title' => $this->gettext('archivefolder'), |
| | | 'content' => $select->show($rcmail->config->get('archive_mbox'), array('name' => "_archive_mbox")) |
| | | ); |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | function save_prefs($args) |
| | | { |
| | | if ($args['section'] == 'folders') { |
| | | $args['prefs']['archive_mbox'] = get_input_value('_archive_mbox', RCUBE_INPUT_POST); |
| | | return $args; |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /* |
| | | |
| | | +-----------------------------------------------------------------------+ |
| | | | language/cs_CZ/labels.inc | |
| | | | | |
| | | | Language file of the Roundcube archive plugin | |
| | | | Copyright (C) 2005-2009, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Milan Kozak <hodza@hodza.net> | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | @version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ |
| | | |
| | | */ |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archivovat zprávu'; |
| | | $labels['archived'] = 'Úspěšně vloženo do archivu'; |
| | | $labels['archivefolder'] = 'Archiv'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Nachricht archivieren'; |
| | | $labels['archived'] = 'Nachricht erfolgreich archiviert'; |
| | | $labels['archivefolder'] = 'Archiv'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Nachricht archivieren'; |
| | | $labels['archived'] = 'Nachricht erfolgreich archiviert'; |
| | | $labels['archivefolder'] = 'Archiv'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archive this message'; |
| | | $labels['archived'] = 'Successfully archived'; |
| | | $labels['archivefolder'] = 'Archive'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // MPBAUPGRADE |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archivar este mensaje'; |
| | | $labels['archived'] = 'Mensaje Archivado'; |
| | | $labels['archivefolder'] = 'Archivo'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // MPBAUPGRADE |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archivar este mensaje'; |
| | | $labels['archived'] = 'Mensaje Archivado'; |
| | | $labels['archivefolder'] = 'Archivo'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Arhiveeri see kiri'; |
| | | $labels['archived'] = 'Edukalt arhiveeritud'; |
| | | $labels['archivefolder'] = 'Arhiveeri'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archiver ce message'; |
| | | $labels['archived'] = 'Message archivé avec success'; |
| | | $labels['archivefolder'] = 'Archive'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // MPBAUPGRADE |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Arquivar esta mensaxe'; |
| | | $labels['archived'] = 'Aquivouse a mensaxe'; |
| | | $labels['archivefolder'] = 'Arquivo'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // EN-Revision: 3891 |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'このメッセージのアーカイブ'; |
| | | $labels['archived'] = 'アーカイブに成功しました。'; |
| | | $labels['archivefolder'] = 'アーカイブ'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Archiveer dit bericht'; |
| | | $labels['archived'] = 'Succesvol gearchiveerd'; |
| | | $labels['archivefolder'] = 'Archief'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Przenieś do archiwum'; |
| | | $labels['archived'] = 'Pomyślnie zarchiwizowano'; |
| | | $labels['archivefolder'] = 'Archiwum'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Arquivar esta mensagem'; |
| | | $labels['archived'] = 'Arquivada com sucesso'; |
| | | $labels['archivefolder'] = 'Arquivo'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Переместить выбранное в архив'; |
| | | $labels['archived'] = 'Перенесено в Архив'; |
| | | $labels['archivefolder'] = 'Архив'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = 'Arkivera meddelande'; |
| | | $labels['archived'] = 'Meddelandet är arkiverat'; |
| | | $labels['archivefolder'] = 'Arkiv'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['buttontitle'] = '封存此信件'; |
| | | $labels['archived'] = '已成功封存'; |
| | | $labels['archivefolder'] = '封存'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 |
| | | http://pear.php.net/dtd/tasks-1.0.xsd |
| | | http://pear.php.net/dtd/package-2.0 |
| | | http://pear.php.net/dtd/package-2.0.xsd"> |
| | | <name>archive</name> |
| | | <channel>pear.roundcube.net</channel> |
| | | <summary>Archive feature for Roundcube</summary> |
| | | <description>This adds a button to move the selected messages to an archive folder. The folder can be selected in the settings panel.</description> |
| | | <lead> |
| | | <name>Thomas Bruederli</name> |
| | | <user>thomasb</user> |
| | | <email>roundcube@gmail.com</email> |
| | | <active>yes</active> |
| | | </lead> |
| | | <date>2010-02-06</date> |
| | | <time>12:12:00</time> |
| | | <version> |
| | | <release>1.4</release> |
| | | <api>1.4</api> |
| | | </version> |
| | | <stability> |
| | | <release>stable</release> |
| | | <api>stable</api> |
| | | </stability> |
| | | <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> |
| | | <notes>-</notes> |
| | | <contents> |
| | | <dir baseinstalldir="/" name="/"> |
| | | <file name="archive.php" role="php"> |
| | | <tasks:replace from="@name@" to="name" type="package-info"/> |
| | | <tasks:replace from="@package_version@" to="version" type="package-info"/> |
| | | </file> |
| | | <file name="archive.js" role="data"> |
| | | <tasks:replace from="@name@" to="name" type="package-info"/> |
| | | <tasks:replace from="@package_version@" to="version" type="package-info"/> |
| | | </file> |
| | | <file name="localization/en_US.inc" role="data"></file> |
| | | <file name="localization/cs_CZ.inc" role="data"></file> |
| | | <file name="localization/de_CH.inc" role="data"></file> |
| | | <file name="localization/de_DE.inc" role="data"></file> |
| | | <file name="localization/et_EE.inc" role="data"></file> |
| | | <file name="localization/fr_FR.inc" role="data"></file> |
| | | <file name="localization/pl_PL.inc" role="data"></file> |
| | | <file name="localization/ru_RU.inc" role="data"></file> |
| | | <file name="localization/zh_TW.inc" role="data"></file> |
| | | <file name="skins/default/archive_act.png" role="data"></file> |
| | | <file name="skins/default/archive_pas.png" role="data"></file> |
| | | <file name="skins/default/foldericon.png" role="data"></file> |
| | | </dir> |
| | | <!-- / --> |
| | | </contents> |
| | | <dependencies> |
| | | <required> |
| | | <php> |
| | | <min>5.2.1</min> |
| | | </php> |
| | | <pearinstaller> |
| | | <min>1.7.0</min> |
| | | </pearinstaller> |
| | | </required> |
| | | </dependencies> |
| | | <phprelease/> |
| | | </package> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Sample plugin to try out some hooks. |
| | | * This performs an automatic login if accessed from localhost |
| | | */ |
| | | class autologon extends rcube_plugin |
| | | { |
| | | public $task = 'login'; |
| | | |
| | | function init() |
| | | { |
| | | $this->add_hook('startup', array($this, 'startup')); |
| | | $this->add_hook('authenticate', array($this, 'authenticate')); |
| | | } |
| | | |
| | | function startup($args) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | // change action to login |
| | | if (empty($_SESSION['user_id']) && !empty($_GET['_autologin']) && $this->is_localhost()) |
| | | $args['action'] = 'login'; |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | function authenticate($args) |
| | | { |
| | | if (!empty($_GET['_autologin']) && $this->is_localhost()) { |
| | | $args['user'] = 'me'; |
| | | $args['pass'] = '******'; |
| | | $args['host'] = 'localhost'; |
| | | $args['cookiecheck'] = false; |
| | | $args['valid'] = true; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | function is_localhost() |
| | | { |
| | | return $_SERVER['REMOTE_ADDR'] == '::1' || $_SERVER['REMOTE_ADDR'] == '127.0.0.1'; |
| | | } |
| | | |
| | | } |
| | | |
New file |
| | |
| | | <?php |
| | | /** |
| | | * Filesystem Attachments |
| | | * |
| | | * This plugin which provides database backed storage for temporary |
| | | * attachment file handling. The primary advantage of this plugin |
| | | * is its compatibility with round-robin dns multi-server roundcube |
| | | * installations. |
| | | * |
| | | * This plugin relies on the core filesystem_attachments plugin |
| | | * |
| | | * @author Ziba Scott <ziba@umich.edu> |
| | | * |
| | | */ |
| | | require_once('plugins/filesystem_attachments/filesystem_attachments.php'); |
| | | class database_attachments extends filesystem_attachments |
| | | { |
| | | |
| | | // A prefix for the cache key used in the session and in the key field of the cache table |
| | | private $cache_prefix = "db_attach"; |
| | | |
| | | /** |
| | | * Helper method to generate a unique key for the given attachment file |
| | | */ |
| | | private function _key($args) |
| | | { |
| | | $uname = $args['path'] ? $args['path'] : $args['name']; |
| | | return $this->cache_prefix . $args['group'] . md5(mktime() . $uname . $_SESSION['user_id']); |
| | | } |
| | | |
| | | /** |
| | | * Save a newly uploaded attachment |
| | | */ |
| | | function upload($args) |
| | | { |
| | | $args['status'] = false; |
| | | $rcmail = rcmail::get_instance(); |
| | | $key = $this->_key($args); |
| | | |
| | | $data = file_get_contents($args['path']); |
| | | |
| | | if ($data === false) |
| | | return $args; |
| | | |
| | | $data = base64_encode($data); |
| | | |
| | | $status = $rcmail->db->query( |
| | | "INSERT INTO ".get_table_name('cache')." |
| | | (created, user_id, cache_key, data) |
| | | VALUES (".$rcmail->db->now().", ?, ?, ?)", |
| | | $_SESSION['user_id'], |
| | | $key, |
| | | $data); |
| | | |
| | | if ($status) { |
| | | $args['id'] = $key; |
| | | $args['status'] = true; |
| | | unset($args['path']); |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Save an attachment from a non-upload source (draft or forward) |
| | | */ |
| | | function save($args) |
| | | { |
| | | $args['status'] = false; |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | $key = $this->_key($args); |
| | | |
| | | if ($args['path']) { |
| | | $args['data'] = file_get_contents($args['path']); |
| | | |
| | | if ($args['data'] === false) |
| | | return $args; |
| | | } |
| | | |
| | | $data = base64_encode($args['data']); |
| | | |
| | | $status = $rcmail->db->query( |
| | | "INSERT INTO ".get_table_name('cache')." |
| | | (created, user_id, cache_key, data) |
| | | VALUES (".$rcmail->db->now().", ?, ?, ?)", |
| | | $_SESSION['user_id'], |
| | | $key, |
| | | $data); |
| | | |
| | | if ($status) { |
| | | $args['id'] = $key; |
| | | $args['status'] = true; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Remove an attachment from storage |
| | | * This is triggered by the remove attachment button on the compose screen |
| | | */ |
| | | function remove($args) |
| | | { |
| | | $args['status'] = false; |
| | | $rcmail = rcmail::get_instance(); |
| | | $status = $rcmail->db->query( |
| | | "DELETE FROM ".get_table_name('cache')." |
| | | WHERE user_id=? |
| | | AND cache_key=?", |
| | | $_SESSION['user_id'], |
| | | $args['id']); |
| | | |
| | | if ($status) { |
| | | $args['status'] = true; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * When composing an html message, image attachments may be shown |
| | | * For this plugin, $this->get() will check the file and |
| | | * return it's contents |
| | | */ |
| | | function display($args) |
| | | { |
| | | return $this->get($args); |
| | | } |
| | | |
| | | /** |
| | | * When displaying or sending the attachment the file contents are fetched |
| | | * using this method. This is also called by the attachment_display hook. |
| | | */ |
| | | function get($args) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | $sql_result = $rcmail->db->query( |
| | | "SELECT cache_id, data |
| | | FROM ".get_table_name('cache')." |
| | | WHERE user_id=? |
| | | AND cache_key=?", |
| | | $_SESSION['user_id'], |
| | | $args['id']); |
| | | |
| | | if ($sql_arr = $rcmail->db->fetch_assoc($sql_result)) { |
| | | $args['data'] = base64_decode($sql_arr['data']); |
| | | $args['status'] = true; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Delete all temp files associated with this user |
| | | */ |
| | | function cleanup($args) |
| | | { |
| | | $prefix = $this->cache_prefix . $args['group']; |
| | | $rcmail = rcmail::get_instance(); |
| | | $rcmail->db->query( |
| | | "DELETE FROM ".get_table_name('cache')." |
| | | WHERE user_id=? |
| | | AND cache_key like '{$prefix}%'", |
| | | $_SESSION['user_id']); |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Debug Logger |
| | | * |
| | | * Enhanced logging for debugging purposes. It is not recommened |
| | | * to be enabled on production systems without testing because of |
| | | * the somewhat increased memory, cpu and disk i/o overhead. |
| | | * |
| | | * Debug Logger listens for existing console("message") calls and |
| | | * introduces start and end tags as well as free form tagging |
| | | * which can redirect messages to files. The resulting log files |
| | | * provide timing and tag quantity results. |
| | | * |
| | | * Enable the plugin in config/main.inc.php and add your desired |
| | | * log types and files. |
| | | * |
| | | * @version 1.0 |
| | | * @author Ziba Scott |
| | | * @website http://roundcube.net |
| | | * |
| | | * Example: |
| | | * |
| | | * config/main.inc.php: |
| | | * |
| | | * // $rcmail_config['debug_logger'][type of logging] = name of file in log_dir |
| | | * // The 'master' log includes timing information |
| | | * $rcmail_config['debug_logger']['master'] = 'master'; |
| | | * // If you want sql messages to also go into a separate file |
| | | * $rcmail_config['debug_logger']['sql'] = 'sql'; |
| | | * |
| | | * index.php (just after $RCMAIL->plugins->init()): |
| | | * |
| | | * console("my test","start"); |
| | | * console("my message"); |
| | | * console("my sql calls","start"); |
| | | * console("cp -r * /dev/null","shell exec"); |
| | | * console("select * from example","sql"); |
| | | * console("select * from example","sql"); |
| | | * console("select * from example","sql"); |
| | | * console("end"); |
| | | * console("end"); |
| | | * |
| | | * |
| | | * logs/master (after reloading the main page): |
| | | * |
| | | * [17-Feb-2009 16:51:37 -0500] start: Task: mail. |
| | | * [17-Feb-2009 16:51:37 -0500] start: my test |
| | | * [17-Feb-2009 16:51:37 -0500] my message |
| | | * [17-Feb-2009 16:51:37 -0500] shell exec: cp -r * /dev/null |
| | | * [17-Feb-2009 16:51:37 -0500] start: my sql calls |
| | | * [17-Feb-2009 16:51:37 -0500] sql: select * from example |
| | | * [17-Feb-2009 16:51:37 -0500] sql: select * from example |
| | | * [17-Feb-2009 16:51:37 -0500] sql: select * from example |
| | | * [17-Feb-2009 16:51:37 -0500] end: my sql calls - 0.0018 seconds shell exec: 1, sql: 3, |
| | | * [17-Feb-2009 16:51:37 -0500] end: my test - 0.0055 seconds shell exec: 1, sql: 3, |
| | | * [17-Feb-2009 16:51:38 -0500] end: Task: mail. - 0.8854 seconds shell exec: 1, sql: 3, |
| | | * |
| | | * logs/sql (after reloading the main page): |
| | | * |
| | | * [17-Feb-2009 16:51:37 -0500] sql: select * from example |
| | | * [17-Feb-2009 16:51:37 -0500] sql: select * from example |
| | | * [17-Feb-2009 16:51:37 -0500] sql: select * from example |
| | | */ |
| | | class debug_logger extends rcube_plugin |
| | | { |
| | | function init() |
| | | { |
| | | require_once(dirname(__FILE__).'/runlog/runlog.php'); |
| | | $this->runlog = new runlog(); |
| | | |
| | | if(!rcmail::get_instance()->config->get('log_dir')){ |
| | | rcmail::get_instance()->config->set('log_dir',INSTALL_PATH.'logs'); |
| | | } |
| | | |
| | | $log_config = rcmail::get_instance()->config->get('debug_logger',array()); |
| | | |
| | | foreach($log_config as $type=>$file){ |
| | | $this->runlog->set_file(rcmail::get_instance()->config->get('log_dir').'/'.$file, $type); |
| | | } |
| | | |
| | | $start_string = ""; |
| | | $action = rcmail::get_instance()->action; |
| | | $task = rcmail::get_instance()->task; |
| | | if($action){ |
| | | $start_string .= "Action: ".$action.". "; |
| | | } |
| | | if($task){ |
| | | $start_string .= "Task: ".$task.". "; |
| | | } |
| | | $this->runlog->start($start_string); |
| | | |
| | | $this->add_hook('console', array($this, 'console')); |
| | | $this->add_hook('authenticate', array($this, 'authenticate')); |
| | | } |
| | | |
| | | function authenticate($args){ |
| | | $this->runlog->note('Authenticating '.$args['user'].'@'.$args['host']); |
| | | return $args; |
| | | } |
| | | |
| | | function console($args){ |
| | | $note = $args[0]; |
| | | $type = $args[1]; |
| | | |
| | | |
| | | if(!isset($args[1])){ |
| | | // This could be extended to detect types based on the |
| | | // file which called console. For now only rcube_imap.inc is supported |
| | | $bt = debug_backtrace(); |
| | | $file = $bt[3]['file']; |
| | | switch(basename($file)){ |
| | | case 'rcube_imap.php': |
| | | $type = 'imap'; |
| | | break; |
| | | default: |
| | | $type = FALSE; |
| | | break; |
| | | } |
| | | } |
| | | switch($note){ |
| | | case 'end': |
| | | $type = 'end'; |
| | | break; |
| | | } |
| | | |
| | | |
| | | switch($type){ |
| | | case 'start': |
| | | $this->runlog->start($note); |
| | | break; |
| | | case 'end': |
| | | $this->runlog->end(); |
| | | break; |
| | | default: |
| | | $this->runlog->note($note, $type); |
| | | break; |
| | | } |
| | | return $args; |
| | | } |
| | | |
| | | function __destruct(){ |
| | | $this->runlog->end(); |
| | | } |
| | | } |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * runlog |
| | | * |
| | | * @author Ziba Scott <ziba@umich.edu> |
| | | */ |
| | | class runlog { |
| | | |
| | | private $start_time = FALSE; |
| | | |
| | | private $parent_stack = array(); |
| | | |
| | | public $print_to_console = FALSE; |
| | | |
| | | private $file_handles = array(); |
| | | |
| | | private $indent = 0; |
| | | |
| | | public $threshold = 0; |
| | | |
| | | public $tag_count = array(); |
| | | |
| | | public $timestamp = "d-M-Y H:i:s O"; |
| | | |
| | | public $max_line_size = 150; |
| | | |
| | | private $run_log = array(); |
| | | |
| | | function runlog() |
| | | { |
| | | $this->start_time = microtime( TRUE ); |
| | | } |
| | | |
| | | public function start( $name, $tag = FALSE ) |
| | | { |
| | | $this->run_log[] = array( 'type' => 'start', |
| | | 'tag' => $tag, |
| | | 'index' => count($this->run_log), |
| | | 'value' => $name, |
| | | 'time' => microtime( TRUE ), |
| | | 'parents' => $this->parent_stack, |
| | | 'ended' => false, |
| | | ); |
| | | $this->parent_stack[] = $name; |
| | | |
| | | $this->print_to_console("start: ".$name, $tag, 'start'); |
| | | $this->print_to_file("start: ".$name, $tag, 'start'); |
| | | $this->indent++; |
| | | } |
| | | |
| | | public function end() |
| | | { |
| | | $name = array_pop( $this->parent_stack ); |
| | | foreach ( $this->run_log as $k => $entry ) { |
| | | if ( $entry['value'] == $name && $entry['type'] == 'start' && $entry['ended'] == false) { |
| | | $lastk = $k; |
| | | } |
| | | } |
| | | $start = $this->run_log[$lastk]['time']; |
| | | $this->run_log[$lastk]['duration'] = microtime( TRUE ) - $start; |
| | | $this->run_log[$lastk]['ended'] = true; |
| | | |
| | | $this->run_log[] = array( 'type' => 'end', |
| | | 'tag' => $this->run_log[$lastk]['tag'], |
| | | 'index' => $lastk, |
| | | 'value' => $name, |
| | | 'time' => microtime( TRUE ), |
| | | 'duration' => microtime( TRUE ) - $start, |
| | | 'parents' => $this->parent_stack, |
| | | ); |
| | | $this->indent--; |
| | | if($this->run_log[$lastk]['duration'] >= $this->threshold){ |
| | | $tag_report = ""; |
| | | foreach($this->tag_count as $tag=>$count){ |
| | | $tag_report .= "$tag: $count, "; |
| | | } |
| | | if(!empty($tag_report)){ |
| | | // $tag_report = "\n$tag_report\n"; |
| | | } |
| | | $end_txt = sprintf("end: $name - %0.4f seconds $tag_report", $this->run_log[$lastk]['duration'] ); |
| | | $this->print_to_console($end_txt, $this->run_log[$lastk]['tag'] , 'end'); |
| | | $this->print_to_file($end_txt, $this->run_log[$lastk]['tag'], 'end'); |
| | | } |
| | | } |
| | | |
| | | public function increase_tag_count($tag){ |
| | | if(!isset($this->tag_count[$tag])){ |
| | | $this->tag_count[$tag] = 0; |
| | | } |
| | | $this->tag_count[$tag]++; |
| | | } |
| | | |
| | | public function get_text(){ |
| | | $text = ""; |
| | | foreach($this->run_log as $entry){ |
| | | $text .= str_repeat(" ",count($entry['parents'])); |
| | | if($entry['tag'] != 'text'){ |
| | | $text .= $entry['tag'].': '; |
| | | } |
| | | $text .= $entry['value']; |
| | | |
| | | if($entry['tag'] == 'end'){ |
| | | $text .= sprintf(" - %0.4f seconds", $entry['duration'] ); |
| | | } |
| | | |
| | | $text .= "\n"; |
| | | } |
| | | return $text; |
| | | } |
| | | |
| | | public function set_file($filename, $tag = 'master'){ |
| | | if(!isset($this->file_handle[$tag])){ |
| | | $this->file_handles[$tag] = fopen($filename, 'a'); |
| | | if(!$this->file_handles[$tag]){ |
| | | trigger_error('Could not open file for writing: '.$filename); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public function note( $msg, $tag = FALSE ) |
| | | { |
| | | if($tag){ |
| | | $this->increase_tag_count($tag); |
| | | } |
| | | if ( is_array( $msg )) { |
| | | $msg = '<pre>' . print_r( $msg, TRUE ) . '</pre>'; |
| | | } |
| | | $this->debug_messages[] = $msg; |
| | | $this->run_log[] = array( 'type' => 'note', |
| | | 'tag' => $tag ? $tag:"text", |
| | | 'value' => htmlentities($msg), |
| | | 'time' => microtime( TRUE ), |
| | | 'parents' => $this->parent_stack, |
| | | ); |
| | | |
| | | $this->print_to_file($msg, $tag); |
| | | $this->print_to_console($msg, $tag); |
| | | |
| | | } |
| | | |
| | | public function print_to_file($msg, $tag = FALSE, $type = FALSE){ |
| | | if(!$tag){ |
| | | $file_handle_tag = 'master'; |
| | | } |
| | | else{ |
| | | $file_handle_tag = $tag; |
| | | } |
| | | if($file_handle_tag != 'master' && isset($this->file_handles[$file_handle_tag])){ |
| | | $buffer = $this->get_indent(); |
| | | $buffer .= "$msg\n"; |
| | | if(!empty($this->timestamp)){ |
| | | $buffer = sprintf("[%s] %s",date($this->timestamp, mktime()), $buffer); |
| | | } |
| | | fwrite($this->file_handles[$file_handle_tag], wordwrap($buffer, $this->max_line_size, "\n ")); |
| | | } |
| | | if(isset($this->file_handles['master']) && $this->file_handles['master']){ |
| | | $buffer = $this->get_indent(); |
| | | if($tag){ |
| | | $buffer .= "$tag: "; |
| | | } |
| | | $msg = str_replace("\n","",$msg); |
| | | $buffer .= "$msg"; |
| | | if(!empty($this->timestamp)){ |
| | | $buffer = sprintf("[%s] %s",date($this->timestamp, mktime()), $buffer); |
| | | } |
| | | if(strlen($buffer) > $this->max_line_size){ |
| | | $buffer = substr($buffer,0,$this->max_line_size - 3)."..."; |
| | | } |
| | | fwrite($this->file_handles['master'], $buffer."\n"); |
| | | } |
| | | } |
| | | |
| | | public function print_to_console($msg, $tag=FALSE){ |
| | | if($this->print_to_console){ |
| | | if(is_array($this->print_to_console)){ |
| | | if(in_array($tag, $this->print_to_console)){ |
| | | echo $this->get_indent(); |
| | | if($tag){ |
| | | echo "$tag: "; |
| | | } |
| | | echo "$msg\n"; |
| | | } |
| | | } |
| | | else{ |
| | | echo $this->get_indent(); |
| | | if($tag){ |
| | | echo "$tag: "; |
| | | } |
| | | echo "$msg\n"; |
| | | } |
| | | } |
| | | } |
| | | |
| | | public function print_totals(){ |
| | | $totals = array(); |
| | | foreach ( $this->run_log as $k => $entry ) { |
| | | if ( $entry['type'] == 'start' && $entry['ended'] == true) { |
| | | $totals[$entry['value']]['duration'] += $entry['duration']; |
| | | $totals[$entry['value']]['count'] += 1; |
| | | } |
| | | } |
| | | if($this->file_handle){ |
| | | foreach($totals as $name=>$details){ |
| | | fwrite($this->file_handle,$name.": ".number_format($details['duration'],4)."sec, ".$details['count']." calls \n"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private function get_indent(){ |
| | | $buf = ""; |
| | | for($i = 0; $i < $this->indent; $i++){ |
| | | $buf .= " "; |
| | | } |
| | | return $buf; |
| | | } |
| | | |
| | | |
| | | function __destruct(){ |
| | | foreach($this->file_handles as $handle){ |
| | | fclose($handle); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Display Emoticons |
| | | * |
| | | * Sample plugin to replace emoticons in plain text message body with real icons |
| | | * |
| | | * @version 1.3 |
| | | * @author Thomas Bruederli |
| | | * @author Aleksander Machniak |
| | | * @website http://roundcube.net |
| | | */ |
| | | class emoticons extends rcube_plugin |
| | | { |
| | | public $task = 'mail'; |
| | | |
| | | function init() |
| | | { |
| | | $this->add_hook('message_part_after', array($this, 'replace')); |
| | | } |
| | | |
| | | function replace($args) |
| | | { |
| | | // This is a lookbehind assertion which will exclude html entities |
| | | // E.g. situation when ";)" in "")" shouldn't be replaced by the icon |
| | | // It's so long because of assertion format restrictions |
| | | $entity = '(?<!&' |
| | | . '[a-zA-Z0-9]{2}' . '|' . '#[0-9]{2}' . '|' |
| | | . '[a-zA-Z0-9]{3}' . '|' . '#[0-9]{3}' . '|' |
| | | . '[a-zA-Z0-9]{4}' . '|' . '#[0-9]{4}' . '|' |
| | | . '[a-zA-Z0-9]{5}' . '|' |
| | | . '[a-zA-Z0-9]{6}' . '|' |
| | | . '[a-zA-Z0-9]{7}' |
| | | . ')'; |
| | | |
| | | // map of emoticon replacements |
| | | $map = array( |
| | | '/:\)/' => $this->img_tag('smiley-smile.gif', ':)' ), |
| | | '/:-\)/' => $this->img_tag('smiley-smile.gif', ':-)' ), |
| | | '/(?<!mailto):D/' => $this->img_tag('smiley-laughing.gif', ':D' ), |
| | | '/:-D/' => $this->img_tag('smiley-laughing.gif', ':-D' ), |
| | | '/:\(/' => $this->img_tag('smiley-frown.gif', ':(' ), |
| | | '/:-\(/' => $this->img_tag('smiley-frown.gif', ':-(' ), |
| | | '/'.$entity.';\)/' => $this->img_tag('smiley-wink.gif', ';)' ), |
| | | '/'.$entity.';-\)/' => $this->img_tag('smiley-wink.gif', ';-)' ), |
| | | '/8\)/' => $this->img_tag('smiley-cool.gif', '8)' ), |
| | | '/8-\)/' => $this->img_tag('smiley-cool.gif', '8-)' ), |
| | | '/(?<!mailto):O/i' => $this->img_tag('smiley-surprised.gif', ':O' ), |
| | | '/(?<!mailto):-O/i' => $this->img_tag('smiley-surprised.gif', ':-O' ), |
| | | '/(?<!mailto):P/i' => $this->img_tag('smiley-tongue-out.gif', ':P' ), |
| | | '/(?<!mailto):-P/i' => $this->img_tag('smiley-tongue-out.gif', ':-P' ), |
| | | '/(?<!mailto):@/i' => $this->img_tag('smiley-yell.gif', ':@' ), |
| | | '/(?<!mailto):-@/i' => $this->img_tag('smiley-yell.gif', ':-@' ), |
| | | '/O:\)/i' => $this->img_tag('smiley-innocent.gif', 'O:)' ), |
| | | '/O:-\)/i' => $this->img_tag('smiley-innocent.gif', 'O:-)' ), |
| | | '/(?<!mailto):$/' => $this->img_tag('smiley-embarassed.gif', ':$' ), |
| | | '/(?<!mailto):-$/' => $this->img_tag('smiley-embarassed.gif', ':-$' ), |
| | | '/(?<!mailto):\*/i' => $this->img_tag('smiley-kiss.gif', ':*' ), |
| | | '/(?<!mailto):-\*/i' => $this->img_tag('smiley-kiss.gif', ':-*' ), |
| | | '/(?<!mailto):S/i' => $this->img_tag('smiley-undecided.gif', ':S' ), |
| | | '/(?<!mailto):-S/i' => $this->img_tag('smiley-undecided.gif', ':-S' ), |
| | | ); |
| | | |
| | | if ($args['type'] == 'plain') { |
| | | $args['body'] = preg_replace( |
| | | array_keys($map), array_values($map), $args['body']); |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | private function img_tag($ico, $title) |
| | | { |
| | | $path = './program/js/tiny_mce/plugins/emotions/img/'; |
| | | return html::img(array('src' => $path.$ico, 'title' => $title)); |
| | | } |
| | | } |
New file |
| | |
| | | ------------------------------------------------------------------ |
| | | THIS IS NOT EVEN AN "ALPHA" STATE. USE ONLY FOR DEVELOPMENT!!!!!!! |
| | | ------------------------------------------------------------------ |
| | | |
| | | WARNING: Don't use with gnupg-2.x! |
| | | |
| | | Enigma Plugin Status: |
| | | |
| | | * DONE: |
| | | |
| | | - PGP signed messages verification |
| | | - Handling of PGP keys files attached to incoming messages |
| | | - PGP encrypted messages decryption (started) |
| | | - PGP keys management UI (started) |
| | | |
| | | * TODO (must have): |
| | | |
| | | - Parsing of decrypted messages into array (see rcube_mime_struct) and then into rcube_message_part structure |
| | | (create core class rcube_mime_parser or take over PEAR::Mail_mimeDecode package and improve it) |
| | | - Sending encrypted/signed messages (probably some changes in core will be needed) |
| | | - Per-Identity settings (including keys/certs) (+ split Identities details page into tabs) |
| | | - Handling big messages with temp files (including changes in Roundcube core) |
| | | - Performance improvements (some caching, code review) |
| | | - better (and more) icons |
| | | |
| | | * TODO (later): |
| | | |
| | | - Keys generation |
| | | - Certs generation |
| | | - Keys/Certs info in Contacts details page (+ split Contact details page into tabs) |
| | | - Key server support |
| | | - S/MIME signed messages verification |
| | | - S/MIME encrypted messages decryption |
| | | - Handling of S/MIME certs files attached to incoming messages |
| | | - SSL (S/MIME) Certs management |
New file |
| | |
| | | <?php |
| | | |
| | | // Enigma Plugin options |
| | | // -------------------- |
| | | |
| | | // A driver to use for PGP. Default: "gnupg". |
| | | $rcmail_config['enigma_pgp_driver'] = 'gnupg'; |
| | | |
| | | // A driver to use for S/MIME. Default: "phpssl". |
| | | $rcmail_config['enigma_smime_driver'] = 'phpssl'; |
| | | |
| | | // Keys directory for all users. Default 'enigma/home'. |
| | | // Must be writeable by PHP process |
| | | $rcmail_config['enigma_pgp_homedir'] = null; |
New file |
| | |
| | | /* Enigma Plugin */ |
| | | |
| | | if (window.rcmail) |
| | | { |
| | | rcmail.addEventListener('init', function(evt) |
| | | { |
| | | if (rcmail.env.task == 'settings') { |
| | | rcmail.register_command('plugin.enigma', function() { rcmail.goto_url('plugin.enigma') }, true); |
| | | rcmail.register_command('plugin.enigma-key-import', function() { rcmail.enigma_key_import() }, true); |
| | | rcmail.register_command('plugin.enigma-key-export', function() { rcmail.enigma_key_export() }, true); |
| | | |
| | | if (rcmail.gui_objects.keyslist) |
| | | { |
| | | var p = rcmail; |
| | | rcmail.keys_list = new rcube_list_widget(rcmail.gui_objects.keyslist, |
| | | {multiselect:false, draggable:false, keyboard:false}); |
| | | rcmail.keys_list.addEventListener('select', function(o){ p.enigma_key_select(o); }); |
| | | rcmail.keys_list.init(); |
| | | rcmail.keys_list.focus(); |
| | | |
| | | rcmail.enigma_list(); |
| | | |
| | | rcmail.register_command('firstpage', function(props) {return rcmail.enigma_list_page('first'); }); |
| | | rcmail.register_command('previouspage', function(props) {return rcmail.enigma_list_page('previous'); }); |
| | | rcmail.register_command('nextpage', function(props) {return rcmail.enigma_list_page('next'); }); |
| | | rcmail.register_command('lastpage', function(props) {return rcmail.enigma_list_page('last'); }); |
| | | } |
| | | |
| | | if (rcmail.env.action == 'edit-prefs') { |
| | | rcmail.register_command('search', function(props) {return rcmail.enigma_search(props); }, true); |
| | | rcmail.register_command('reset-search', function(props) {return rcmail.enigma_search_reset(props); }, true); |
| | | } |
| | | else if (rcmail.env.action == 'plugin.enigma') { |
| | | rcmail.register_command('plugin.enigma-import', function() { rcmail.enigma_import() }, true); |
| | | rcmail.register_command('plugin.enigma-export', function() { rcmail.enigma_export() }, true); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /*********************************************************/ |
| | | /********* Enigma Settings/Keys/Certs UI *********/ |
| | | /*********************************************************/ |
| | | |
| | | // Display key(s) import form |
| | | rcube_webmail.prototype.enigma_key_import = function() |
| | | { |
| | | this.enigma_loadframe(null, '&_a=keyimport'); |
| | | }; |
| | | |
| | | // Submit key(s) form |
| | | rcube_webmail.prototype.enigma_import = function() |
| | | { |
| | | var form, file; |
| | | if (form = this.gui_objects.importform) { |
| | | file = document.getElementById('rcmimportfile'); |
| | | if (file && !file.value) { |
| | | alert(this.get_label('selectimportfile')); |
| | | return; |
| | | } |
| | | form.submit(); |
| | | this.set_busy(true, 'importwait'); |
| | | this.lock_form(form, true); |
| | | } |
| | | }; |
| | | |
| | | // list row selection handler |
| | | rcube_webmail.prototype.enigma_key_select = function(list) |
| | | { |
| | | var id; |
| | | if (id = list.get_single_selection()) |
| | | this.enigma_loadframe(id); |
| | | }; |
| | | |
| | | // load key frame |
| | | rcube_webmail.prototype.enigma_loadframe = function(id, url) |
| | | { |
| | | var frm, win; |
| | | if (this.env.contentframe && window.frames && (frm = window.frames[this.env.contentframe])) { |
| | | if (!id && !url && (win = window.frames[this.env.contentframe])) { |
| | | if (win.location && win.location.href.indexOf(this.env.blankpage)<0) |
| | | win.location.href = this.env.blankpage; |
| | | return; |
| | | } |
| | | this.set_busy(true); |
| | | if (!url) |
| | | url = '&_a=keyinfo&_id='+id; |
| | | frm.location.href = this.env.comm_path+'&_action=plugin.enigma&_framed=1' + url; |
| | | } |
| | | }; |
| | | |
| | | // Search keys/certs |
| | | rcube_webmail.prototype.enigma_search = function(props) |
| | | { |
| | | if (!props && this.gui_objects.qsearchbox) |
| | | props = this.gui_objects.qsearchbox.value; |
| | | |
| | | if (props || this.env.search_request) { |
| | | var params = {'_a': 'keysearch', '_q': urlencode(props)}, |
| | | lock = this.set_busy(true, 'searching'); |
| | | // if (this.gui_objects.search_filter) |
| | | // addurl += '&_filter=' + this.gui_objects.search_filter.value; |
| | | this.env.current_page = 1; |
| | | this.enigma_loadframe(); |
| | | this.enigma_clear_list(); |
| | | this.http_post('plugin.enigma', params, lock); |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | // Reset search filter and the list |
| | | rcube_webmail.prototype.enigma_search_reset = function(props) |
| | | { |
| | | var s = this.env.search_request; |
| | | this.reset_qsearch(); |
| | | |
| | | if (s) { |
| | | this.enigma_loadframe(); |
| | | this.enigma_clear_list(); |
| | | |
| | | // refresh the list |
| | | this.enigma_list(); |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | // Keys/certs listing |
| | | rcube_webmail.prototype.enigma_list = function(page) |
| | | { |
| | | var params = {'_a': 'keylist'}, |
| | | lock = this.set_busy(true, 'loading'); |
| | | |
| | | this.env.current_page = page ? page : 1; |
| | | |
| | | if (this.env.search_request) |
| | | params._q = this.env.search_request; |
| | | if (page) |
| | | params._p = page; |
| | | |
| | | this.enigma_clear_list(); |
| | | this.http_post('plugin.enigma', params, lock); |
| | | } |
| | | |
| | | // Change list page |
| | | rcube_webmail.prototype.enigma_list_page = function(page) |
| | | { |
| | | if (page == 'next') |
| | | page = this.env.current_page + 1; |
| | | else if (page == 'last') |
| | | page = this.env.pagecount; |
| | | else if (page == 'prev' && this.env.current_page > 1) |
| | | page = this.env.current_page - 1; |
| | | else if (page == 'first' && this.env.current_page > 1) |
| | | page = 1; |
| | | |
| | | this.enigma_list(page); |
| | | } |
| | | |
| | | // Remove list rows |
| | | rcube_webmail.prototype.enigma_clear_list = function() |
| | | { |
| | | this.enigma_loadframe(); |
| | | if (this.keys_list) |
| | | this.keys_list.clear(true); |
| | | } |
| | | |
| | | // Adds a row to the list |
| | | rcube_webmail.prototype.enigma_add_list_row = function(r) |
| | | { |
| | | if (!this.gui_objects.keyslist || !this.keys_list) |
| | | return false; |
| | | |
| | | var list = this.keys_list, |
| | | tbody = this.gui_objects.keyslist.tBodies[0], |
| | | rowcount = tbody.rows.length, |
| | | even = rowcount%2, |
| | | css_class = 'message' |
| | | + (even ? ' even' : ' odd'), |
| | | // for performance use DOM instead of jQuery here |
| | | row = document.createElement('tr'), |
| | | col = document.createElement('td'); |
| | | |
| | | row.id = 'rcmrow' + r.id; |
| | | row.className = css_class; |
| | | |
| | | col.innerHTML = r.name; |
| | | row.appendChild(col); |
| | | list.insert_row(row); |
| | | } |
| | | |
| | | /*********************************************************/ |
| | | /********* Enigma Message methods *********/ |
| | | /*********************************************************/ |
| | | |
| | | // Import attached keys/certs file |
| | | rcube_webmail.prototype.enigma_import_attachment = function(mime_id) |
| | | { |
| | | var lock = this.set_busy(true, 'loading'); |
| | | this.http_post('plugin.enigmaimport', '_uid='+this.env.uid+'&_mbox=' |
| | | +urlencode(this.env.mailbox)+'&_part='+urlencode(mime_id), lock); |
| | | |
| | | return false; |
| | | }; |
| | | |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Enigma Plugin for Roundcube | |
| | | | Version 0.1 | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | /* |
| | | This class contains only hooks and action handlers. |
| | | Most plugin logic is placed in enigma_engine and enigma_ui classes. |
| | | */ |
| | | |
| | | class enigma extends rcube_plugin |
| | | { |
| | | public $task = 'mail|settings'; |
| | | public $rc; |
| | | public $engine; |
| | | |
| | | private $env_loaded; |
| | | private $message; |
| | | private $keys_parts = array(); |
| | | private $keys_bodies = array(); |
| | | |
| | | |
| | | /** |
| | | * Plugin initialization. |
| | | */ |
| | | function init() |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | $this->rc = $rcmail; |
| | | |
| | | if ($this->rc->task == 'mail') { |
| | | // message parse/display hooks |
| | | $this->add_hook('message_part_structure', array($this, 'parse_structure')); |
| | | $this->add_hook('message_body_prefix', array($this, 'status_message')); |
| | | |
| | | // message displaying |
| | | if ($rcmail->action == 'show' || $rcmail->action == 'preview') { |
| | | $this->add_hook('message_load', array($this, 'message_load')); |
| | | $this->add_hook('template_object_messagebody', array($this, 'message_output')); |
| | | $this->register_action('plugin.enigmaimport', array($this, 'import_file')); |
| | | } |
| | | // message composing |
| | | else if ($rcmail->action == 'compose') { |
| | | $this->load_ui(); |
| | | $this->ui->init($section); |
| | | } |
| | | // message sending (and draft storing) |
| | | else if ($rcmail->action == 'sendmail') { |
| | | //$this->add_hook('outgoing_message_body', array($this, 'msg_encode')); |
| | | //$this->add_hook('outgoing_message_body', array($this, 'msg_sign')); |
| | | } |
| | | } |
| | | else if ($this->rc->task == 'settings') { |
| | | // add hooks for Enigma settings |
| | | $this->add_hook('preferences_sections_list', array($this, 'preferences_section')); |
| | | $this->add_hook('preferences_list', array($this, 'preferences_list')); |
| | | $this->add_hook('preferences_save', array($this, 'preferences_save')); |
| | | |
| | | // register handler for keys/certs management |
| | | $this->register_action('plugin.enigma', array($this, 'preferences_ui')); |
| | | |
| | | // grab keys/certs management iframe requests |
| | | $section = get_input_value('_section', RCUBE_INPUT_GET); |
| | | if ($this->rc->action == 'edit-prefs' && preg_match('/^enigma(certs|keys)/', $section)) { |
| | | $this->load_ui(); |
| | | $this->ui->init($section); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Plugin environment initialization. |
| | | */ |
| | | function load_env() |
| | | { |
| | | if ($this->env_loaded) |
| | | return; |
| | | |
| | | $this->env_loaded = true; |
| | | |
| | | // Add include path for Enigma classes and drivers |
| | | $include_path = $this->home . '/lib' . PATH_SEPARATOR; |
| | | $include_path .= ini_get('include_path'); |
| | | set_include_path($include_path); |
| | | |
| | | // load the Enigma plugin configuration |
| | | $this->load_config(); |
| | | |
| | | // include localization (if wasn't included before) |
| | | $this->add_texts('localization/'); |
| | | } |
| | | |
| | | /** |
| | | * Plugin UI initialization. |
| | | */ |
| | | function load_ui() |
| | | { |
| | | if ($this->ui) |
| | | return; |
| | | |
| | | // load config/localization |
| | | $this->load_env(); |
| | | |
| | | // Load UI |
| | | $this->ui = new enigma_ui($this, $this->home); |
| | | } |
| | | |
| | | /** |
| | | * Plugin engine initialization. |
| | | */ |
| | | function load_engine() |
| | | { |
| | | if ($this->engine) |
| | | return; |
| | | |
| | | // load config/localization |
| | | $this->load_env(); |
| | | |
| | | $this->engine = new enigma_engine($this); |
| | | } |
| | | |
| | | /** |
| | | * Handler for message_part_structure hook. |
| | | * Called for every part of the message. |
| | | * |
| | | * @param array Original parameters |
| | | * |
| | | * @return array Modified parameters |
| | | */ |
| | | function parse_structure($p) |
| | | { |
| | | $struct = $p['structure']; |
| | | |
| | | if ($p['mimetype'] == 'text/plain' || $p['mimetype'] == 'application/pgp') { |
| | | $this->parse_plain($p); |
| | | } |
| | | else if ($p['mimetype'] == 'multipart/signed') { |
| | | $this->parse_signed($p); |
| | | } |
| | | else if ($p['mimetype'] == 'multipart/encrypted') { |
| | | $this->parse_encrypted($p); |
| | | } |
| | | else if ($p['mimetype'] == 'application/pkcs7-mime') { |
| | | $this->parse_encrypted($p); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for preferences_sections_list hook. |
| | | * Adds Enigma settings sections into preferences sections list. |
| | | * |
| | | * @param array Original parameters |
| | | * |
| | | * @return array Modified parameters |
| | | */ |
| | | function preferences_section($p) |
| | | { |
| | | // add labels |
| | | $this->add_texts('localization/'); |
| | | |
| | | $p['list']['enigmasettings'] = array( |
| | | 'id' => 'enigmasettings', 'section' => $this->gettext('enigmasettings'), |
| | | ); |
| | | $p['list']['enigmacerts'] = array( |
| | | 'id' => 'enigmacerts', 'section' => $this->gettext('enigmacerts'), |
| | | ); |
| | | $p['list']['enigmakeys'] = array( |
| | | 'id' => 'enigmakeys', 'section' => $this->gettext('enigmakeys'), |
| | | ); |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for preferences_list hook. |
| | | * Adds options blocks into Enigma settings sections in Preferences. |
| | | * |
| | | * @param array Original parameters |
| | | * |
| | | * @return array Modified parameters |
| | | */ |
| | | function preferences_list($p) |
| | | { |
| | | if ($p['section'] == 'enigmasettings') { |
| | | // This makes that section is not removed from the list |
| | | $p['blocks']['dummy']['options']['dummy'] = array(); |
| | | } |
| | | else if ($p['section'] == 'enigmacerts') { |
| | | // This makes that section is not removed from the list |
| | | $p['blocks']['dummy']['options']['dummy'] = array(); |
| | | } |
| | | else if ($p['section'] == 'enigmakeys') { |
| | | // This makes that section is not removed from the list |
| | | $p['blocks']['dummy']['options']['dummy'] = array(); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for preferences_save hook. |
| | | * Executed on Enigma settings form submit. |
| | | * |
| | | * @param array Original parameters |
| | | * |
| | | * @return array Modified parameters |
| | | */ |
| | | function preferences_save($p) |
| | | { |
| | | if ($p['section'] == 'enigmasettings') { |
| | | $a['prefs'] = array( |
| | | // 'dummy' => get_input_value('_dummy', RCUBE_INPUT_POST), |
| | | ); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for keys/certs management UI template. |
| | | */ |
| | | function preferences_ui() |
| | | { |
| | | $this->load_ui(); |
| | | $this->ui->init(); |
| | | } |
| | | |
| | | /** |
| | | * Handler for message_body_prefix hook. |
| | | * Called for every displayed (content) part of the message. |
| | | * Adds infobox about signature verification and/or decryption |
| | | * status above the body. |
| | | * |
| | | * @param array Original parameters |
| | | * |
| | | * @return array Modified parameters |
| | | */ |
| | | function status_message($p) |
| | | { |
| | | $part_id = $p['part']->mime_id; |
| | | |
| | | // skip: not a message part |
| | | if ($p['part'] instanceof rcube_message) |
| | | return $p; |
| | | |
| | | // skip: message has no signed/encoded content |
| | | if (!$this->engine) |
| | | return $p; |
| | | |
| | | // Decryption status |
| | | if (isset($this->engine->decryptions[$part_id])) { |
| | | |
| | | // get decryption status |
| | | $status = $this->engine->decryptions[$part_id]; |
| | | |
| | | // Load UI and add css script |
| | | $this->load_ui(); |
| | | $this->ui->add_css(); |
| | | |
| | | // display status info |
| | | $attrib['id'] = 'enigma-message'; |
| | | |
| | | if ($status instanceof enigma_error) { |
| | | $attrib['class'] = 'enigmaerror'; |
| | | $code = $status->getCode(); |
| | | if ($code == enigma_error::E_KEYNOTFOUND) |
| | | $msg = Q(str_replace('$keyid', enigma_key::format_id($status->getData('id')), |
| | | $this->gettext('decryptnokey'))); |
| | | else if ($code == enigma_error::E_BADPASS) |
| | | $msg = Q($this->gettext('decryptbadpass')); |
| | | else |
| | | $msg = Q($this->gettext('decrypterror')); |
| | | } |
| | | else { |
| | | $attrib['class'] = 'enigmanotice'; |
| | | $msg = Q($this->gettext('decryptok')); |
| | | } |
| | | |
| | | $p['prefix'] .= html::div($attrib, $msg); |
| | | } |
| | | |
| | | // Signature verification status |
| | | if (isset($this->engine->signed_parts[$part_id]) |
| | | && ($sig = $this->engine->signatures[$this->engine->signed_parts[$part_id]]) |
| | | ) { |
| | | // add css script |
| | | $this->load_ui(); |
| | | $this->ui->add_css(); |
| | | |
| | | // display status info |
| | | $attrib['id'] = 'enigma-message'; |
| | | |
| | | if ($sig instanceof enigma_signature) { |
| | | if ($sig->valid) { |
| | | $attrib['class'] = 'enigmanotice'; |
| | | $sender = ($sig->name ? $sig->name . ' ' : '') . '<' . $sig->email . '>'; |
| | | $msg = Q(str_replace('$sender', $sender, $this->gettext('sigvalid'))); |
| | | } |
| | | else { |
| | | $attrib['class'] = 'enigmawarning'; |
| | | $sender = ($sig->name ? $sig->name . ' ' : '') . '<' . $sig->email . '>'; |
| | | $msg = Q(str_replace('$sender', $sender, $this->gettext('siginvalid'))); |
| | | } |
| | | } |
| | | else if ($sig->getCode() == enigma_error::E_KEYNOTFOUND) { |
| | | $attrib['class'] = 'enigmawarning'; |
| | | $msg = Q(str_replace('$keyid', enigma_key::format_id($sig->getData('id')), |
| | | $this->gettext('signokey'))); |
| | | } |
| | | else { |
| | | $attrib['class'] = 'enigmaerror'; |
| | | $msg = Q($this->gettext('sigerror')); |
| | | } |
| | | /* |
| | | $msg .= ' ' . html::a(array('href' => "#sigdetails", |
| | | 'onclick' => JS_OBJECT_NAME.".command('enigma-sig-details')"), |
| | | Q($this->gettext('showdetails'))); |
| | | */ |
| | | // test |
| | | // $msg .= '<br /><pre>'.$sig->body.'</pre>'; |
| | | |
| | | $p['prefix'] .= html::div($attrib, $msg); |
| | | |
| | | // Display each signature message only once |
| | | unset($this->engine->signatures[$this->engine->signed_parts[$part_id]]); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for plain/text message. |
| | | * |
| | | * @param array Reference to hook's parameters (see enigma::parse_structure()) |
| | | */ |
| | | private function parse_plain(&$p) |
| | | { |
| | | $this->load_engine(); |
| | | $this->engine->parse_plain($p); |
| | | } |
| | | |
| | | /** |
| | | * Handler for multipart/signed message. |
| | | * Verifies signature. |
| | | * |
| | | * @param array Reference to hook's parameters (see enigma::parse_structure()) |
| | | */ |
| | | private function parse_signed(&$p) |
| | | { |
| | | $this->load_engine(); |
| | | $this->engine->parse_signed($p); |
| | | } |
| | | |
| | | /** |
| | | * Handler for multipart/encrypted and application/pkcs7-mime message. |
| | | * |
| | | * @param array Reference to hook's parameters (see enigma::parse_structure()) |
| | | */ |
| | | private function parse_encrypted(&$p) |
| | | { |
| | | $this->load_engine(); |
| | | $this->engine->parse_encrypted($p); |
| | | } |
| | | |
| | | /** |
| | | * Handler for message_load hook. |
| | | * Check message bodies and attachments for keys/certs. |
| | | */ |
| | | function message_load($p) |
| | | { |
| | | $this->message = $p['object']; |
| | | |
| | | // handle attachments vcard attachments |
| | | foreach ((array)$this->message->attachments as $attachment) { |
| | | if ($this->is_keys_part($attachment)) { |
| | | $this->keys_parts[] = $attachment->mime_id; |
| | | } |
| | | } |
| | | // the same with message bodies |
| | | foreach ((array)$this->message->parts as $idx => $part) { |
| | | if ($this->is_keys_part($part)) { |
| | | $this->keys_parts[] = $part->mime_id; |
| | | $this->keys_bodies[] = $part->mime_id; |
| | | } |
| | | } |
| | | // @TODO: inline PGP keys |
| | | |
| | | if ($this->keys_parts) { |
| | | $this->add_texts('localization'); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for template_object_messagebody hook. |
| | | * This callback function adds a box below the message content |
| | | * if there is a key/cert attachment available |
| | | */ |
| | | function message_output($p) |
| | | { |
| | | $attach_script = false; |
| | | |
| | | foreach ($this->keys_parts as $part) { |
| | | |
| | | // remove part's body |
| | | if (in_array($part, $this->keys_bodies)) |
| | | $p['content'] = ''; |
| | | |
| | | $style = "margin:0 1em; padding:0.2em 0.5em; border:1px solid #999; width: auto" |
| | | ." border-radius:4px; -moz-border-radius:4px; -webkit-border-radius:4px"; |
| | | |
| | | // add box below messsage body |
| | | $p['content'] .= html::p(array('style' => $style), |
| | | html::a(array( |
| | | 'href' => "#", |
| | | 'onclick' => "return ".JS_OBJECT_NAME.".enigma_import_attachment('".JQ($part)."')", |
| | | 'title' => $this->gettext('keyattimport')), |
| | | html::img(array('src' => $this->url('skins/default/key_add.png'), 'style' => "vertical-align:middle"))) |
| | | . ' ' . html::span(null, $this->gettext('keyattfound'))); |
| | | |
| | | $attach_script = true; |
| | | } |
| | | |
| | | if ($attach_script) { |
| | | $this->include_script('enigma.js'); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | /** |
| | | * Handler for attached keys/certs import |
| | | */ |
| | | function import_file() |
| | | { |
| | | $this->load_engine(); |
| | | $this->engine->import_file(); |
| | | } |
| | | |
| | | /** |
| | | * Checks if specified message part is a PGP-key or S/MIME cert data |
| | | * |
| | | * @param rcube_message_part Part object |
| | | * |
| | | * @return boolean True if part is a key/cert |
| | | */ |
| | | private function is_keys_part($part) |
| | | { |
| | | // @TODO: S/MIME |
| | | return ( |
| | | // Content-Type: application/pgp-keys |
| | | $part->mimetype == 'application/pgp-keys' |
| | | ); |
| | | } |
| | | } |
New file |
| | |
| | | Order allow,deny |
| | | Deny from all |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Crypt_GPG is a package to use GPG from PHP |
| | | * |
| | | * This package provides an object oriented interface to GNU Privacy |
| | | * Guard (GPG). It requires the GPG executable to be on the system. |
| | | * |
| | | * Though GPG can support symmetric-key cryptography, this package is intended |
| | | * only to facilitate public-key cryptography. |
| | | * |
| | | * This file contains the main GPG class. The class in this file lets you |
| | | * encrypt, decrypt, sign and verify data; import and delete keys; and perform |
| | | * other useful GPG tasks. |
| | | * |
| | | * Example usage: |
| | | * <code> |
| | | * <?php |
| | | * // encrypt some data |
| | | * $gpg = new Crypt_GPG(); |
| | | * $gpg->addEncryptKey($mySecretKeyId); |
| | | * $encryptedData = $gpg->encrypt($data); |
| | | * ?> |
| | | * </code> |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: GPG.php 302814 2010-08-26 15:43:07Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | |
| | | /** |
| | | * Signature handler class |
| | | */ |
| | | require_once 'Crypt/GPG/VerifyStatusHandler.php'; |
| | | |
| | | /** |
| | | * Decryption handler class |
| | | */ |
| | | require_once 'Crypt/GPG/DecryptStatusHandler.php'; |
| | | |
| | | /** |
| | | * GPG key class |
| | | */ |
| | | require_once 'Crypt/GPG/Key.php'; |
| | | |
| | | /** |
| | | * GPG sub-key class |
| | | */ |
| | | require_once 'Crypt/GPG/SubKey.php'; |
| | | |
| | | /** |
| | | * GPG user id class |
| | | */ |
| | | require_once 'Crypt/GPG/UserId.php'; |
| | | |
| | | /** |
| | | * GPG process and I/O engine class |
| | | */ |
| | | require_once 'Crypt/GPG/Engine.php'; |
| | | |
| | | /** |
| | | * GPG exception classes |
| | | */ |
| | | require_once 'Crypt/GPG/Exceptions.php'; |
| | | |
| | | // {{{ class Crypt_GPG |
| | | |
| | | /** |
| | | * A class to use GPG from PHP |
| | | * |
| | | * This class provides an object oriented interface to GNU Privacy Guard (GPG). |
| | | * |
| | | * Though GPG can support symmetric-key cryptography, this class is intended |
| | | * only to facilitate public-key cryptography. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | class Crypt_GPG |
| | | { |
| | | // {{{ class error constants |
| | | |
| | | /** |
| | | * Error code returned when there is no error. |
| | | */ |
| | | const ERROR_NONE = 0; |
| | | |
| | | /** |
| | | * Error code returned when an unknown or unhandled error occurs. |
| | | */ |
| | | const ERROR_UNKNOWN = 1; |
| | | |
| | | /** |
| | | * Error code returned when a bad passphrase is used. |
| | | */ |
| | | const ERROR_BAD_PASSPHRASE = 2; |
| | | |
| | | /** |
| | | * Error code returned when a required passphrase is missing. |
| | | */ |
| | | const ERROR_MISSING_PASSPHRASE = 3; |
| | | |
| | | /** |
| | | * Error code returned when a key that is already in the keyring is |
| | | * imported. |
| | | */ |
| | | const ERROR_DUPLICATE_KEY = 4; |
| | | |
| | | /** |
| | | * Error code returned the required data is missing for an operation. |
| | | * |
| | | * This could be missing key data, missing encrypted data or missing |
| | | * signature data. |
| | | */ |
| | | const ERROR_NO_DATA = 5; |
| | | |
| | | /** |
| | | * Error code returned when an unsigned key is used. |
| | | */ |
| | | const ERROR_UNSIGNED_KEY = 6; |
| | | |
| | | /** |
| | | * Error code returned when a key that is not self-signed is used. |
| | | */ |
| | | const ERROR_NOT_SELF_SIGNED = 7; |
| | | |
| | | /** |
| | | * Error code returned when a public or private key that is not in the |
| | | * keyring is used. |
| | | */ |
| | | const ERROR_KEY_NOT_FOUND = 8; |
| | | |
| | | /** |
| | | * Error code returned when an attempt to delete public key having a |
| | | * private key is made. |
| | | */ |
| | | const ERROR_DELETE_PRIVATE_KEY = 9; |
| | | |
| | | /** |
| | | * Error code returned when one or more bad signatures are detected. |
| | | */ |
| | | const ERROR_BAD_SIGNATURE = 10; |
| | | |
| | | /** |
| | | * Error code returned when there is a problem reading GnuPG data files. |
| | | */ |
| | | const ERROR_FILE_PERMISSIONS = 11; |
| | | |
| | | // }}} |
| | | // {{{ class constants for data signing modes |
| | | |
| | | /** |
| | | * Signing mode for normal signing of data. The signed message will not |
| | | * be readable without special software. |
| | | * |
| | | * This is the default signing mode. |
| | | * |
| | | * @see Crypt_GPG::sign() |
| | | * @see Crypt_GPG::signFile() |
| | | */ |
| | | const SIGN_MODE_NORMAL = 1; |
| | | |
| | | /** |
| | | * Signing mode for clearsigning data. Clearsigned signatures are ASCII |
| | | * armored data and are readable without special software. If the signed |
| | | * message is unencrypted, the message will still be readable. The message |
| | | * text will be in the original encoding. |
| | | * |
| | | * @see Crypt_GPG::sign() |
| | | * @see Crypt_GPG::signFile() |
| | | */ |
| | | const SIGN_MODE_CLEAR = 2; |
| | | |
| | | /** |
| | | * Signing mode for creating a detached signature. When using detached |
| | | * signatures, only the signature data is returned. The original message |
| | | * text may be distributed separately from the signature data. This is |
| | | * useful for miltipart/signed email messages as per |
| | | * {@link http://www.ietf.org/rfc/rfc3156.txt RFC 3156}. |
| | | * |
| | | * @see Crypt_GPG::sign() |
| | | * @see Crypt_GPG::signFile() |
| | | */ |
| | | const SIGN_MODE_DETACHED = 3; |
| | | |
| | | // }}} |
| | | // {{{ class constants for fingerprint formats |
| | | |
| | | /** |
| | | * No formatting is performed. |
| | | * |
| | | * Example: C3BC615AD9C766E5A85C1F2716D27458B1BBA1C4 |
| | | * |
| | | * @see Crypt_GPG::getFingerprint() |
| | | */ |
| | | const FORMAT_NONE = 1; |
| | | |
| | | /** |
| | | * Fingerprint is formatted in the format used by the GnuPG gpg command's |
| | | * default output. |
| | | * |
| | | * Example: C3BC 615A D9C7 66E5 A85C 1F27 16D2 7458 B1BB A1C4 |
| | | * |
| | | * @see Crypt_GPG::getFingerprint() |
| | | */ |
| | | const FORMAT_CANONICAL = 2; |
| | | |
| | | /** |
| | | * Fingerprint is formatted in the format used when displaying X.509 |
| | | * certificates |
| | | * |
| | | * Example: C3:BC:61:5A:D9:C7:66:E5:A8:5C:1F:27:16:D2:74:58:B1:BB:A1:C4 |
| | | * |
| | | * @see Crypt_GPG::getFingerprint() |
| | | */ |
| | | const FORMAT_X509 = 3; |
| | | |
| | | // }}} |
| | | // {{{ other class constants |
| | | |
| | | /** |
| | | * URI at which package bugs may be reported. |
| | | */ |
| | | const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'; |
| | | |
| | | // }}} |
| | | // {{{ protected class properties |
| | | |
| | | /** |
| | | * Engine used to control the GPG subprocess |
| | | * |
| | | * @var Crypt_GPG_Engine |
| | | * |
| | | * @see Crypt_GPG::setEngine() |
| | | */ |
| | | protected $engine = null; |
| | | |
| | | /** |
| | | * Keys used to encrypt |
| | | * |
| | | * The array is of the form: |
| | | * <code> |
| | | * array( |
| | | * $key_id => array( |
| | | * 'fingerprint' => $fingerprint, |
| | | * 'passphrase' => null |
| | | * ) |
| | | * ); |
| | | * </code> |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG::addEncryptKey() |
| | | * @see Crypt_GPG::clearEncryptKeys() |
| | | */ |
| | | protected $encryptKeys = array(); |
| | | |
| | | /** |
| | | * Keys used to decrypt |
| | | * |
| | | * The array is of the form: |
| | | * <code> |
| | | * array( |
| | | * $key_id => array( |
| | | * 'fingerprint' => $fingerprint, |
| | | * 'passphrase' => $passphrase |
| | | * ) |
| | | * ); |
| | | * </code> |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG::addSignKey() |
| | | * @see Crypt_GPG::clearSignKeys() |
| | | */ |
| | | protected $signKeys = array(); |
| | | |
| | | /** |
| | | * Keys used to sign |
| | | * |
| | | * The array is of the form: |
| | | * <code> |
| | | * array( |
| | | * $key_id => array( |
| | | * 'fingerprint' => $fingerprint, |
| | | * 'passphrase' => $passphrase |
| | | * ) |
| | | * ); |
| | | * </code> |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG::addDecryptKey() |
| | | * @see Crypt_GPG::clearDecryptKeys() |
| | | */ |
| | | protected $decryptKeys = array(); |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new GPG object |
| | | * |
| | | * Available options are: |
| | | * |
| | | * - <kbd>string homedir</kbd> - the directory where the GPG |
| | | * keyring files are stored. If not |
| | | * specified, Crypt_GPG uses the |
| | | * default of <kbd>~/.gnupg</kbd>. |
| | | * - <kbd>string publicKeyring</kbd> - the file path of the public |
| | | * keyring. Use this if the public |
| | | * keyring is not in the homedir, or |
| | | * if the keyring is in a directory |
| | | * not writable by the process |
| | | * invoking GPG (like Apache). Then |
| | | * you can specify the path to the |
| | | * keyring with this option |
| | | * (/foo/bar/pubring.gpg), and specify |
| | | * a writable directory (like /tmp) |
| | | * using the <i>homedir</i> option. |
| | | * - <kbd>string privateKeyring</kbd> - the file path of the private |
| | | * keyring. Use this if the private |
| | | * keyring is not in the homedir, or |
| | | * if the keyring is in a directory |
| | | * not writable by the process |
| | | * invoking GPG (like Apache). Then |
| | | * you can specify the path to the |
| | | * keyring with this option |
| | | * (/foo/bar/secring.gpg), and specify |
| | | * a writable directory (like /tmp) |
| | | * using the <i>homedir</i> option. |
| | | * - <kbd>string trustDb</kbd> - the file path of the web-of-trust |
| | | * database. Use this if the trust |
| | | * database is not in the homedir, or |
| | | * if the database is in a directory |
| | | * not writable by the process |
| | | * invoking GPG (like Apache). Then |
| | | * you can specify the path to the |
| | | * trust database with this option |
| | | * (/foo/bar/trustdb.gpg), and specify |
| | | * a writable directory (like /tmp) |
| | | * using the <i>homedir</i> option. |
| | | * - <kbd>string binary</kbd> - the location of the GPG binary. If |
| | | * not specified, the driver attempts |
| | | * to auto-detect the GPG binary |
| | | * location using a list of known |
| | | * default locations for the current |
| | | * operating system. The option |
| | | * <kbd>gpgBinary</kbd> is a |
| | | * deprecated alias for this option. |
| | | * - <kbd>boolean debug</kbd> - whether or not to use debug mode. |
| | | * When debug mode is on, all |
| | | * communication to and from the GPG |
| | | * subprocess is logged. This can be |
| | | * |
| | | * @param array $options optional. An array of options used to create the |
| | | * GPG object. All options are optional and are |
| | | * represented as key-value pairs. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist |
| | | * and cannot be created. This can happen if <kbd>homedir</kbd> is |
| | | * not specified, Crypt_GPG is run as the web user, and the web |
| | | * user has no home directory. This exception is also thrown if any |
| | | * of the options <kbd>publicKeyring</kbd>, |
| | | * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are |
| | | * specified but the files do not exist or are are not readable. |
| | | * This can happen if the user running the Crypt_GPG process (for |
| | | * example, the Apache user) does not have permission to read the |
| | | * files. |
| | | * |
| | | * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or |
| | | * if no <kbd>binary</kbd> is provided and no suitable binary could |
| | | * be found. |
| | | */ |
| | | public function __construct(array $options = array()) |
| | | { |
| | | $this->setEngine(new Crypt_GPG_Engine($options)); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ importKey() |
| | | |
| | | /** |
| | | * Imports a public or private key into the keyring |
| | | * |
| | | * Keys may be removed from the keyring using |
| | | * {@link Crypt_GPG::deletePublicKey()} or |
| | | * {@link Crypt_GPG::deletePrivateKey()}. |
| | | * |
| | | * @param string $data the key data to be imported. |
| | | * |
| | | * @return array an associative array containing the following elements: |
| | | * - <kbd>fingerprint</kbd> - the fingerprint of the |
| | | * imported key, |
| | | * - <kbd>public_imported</kbd> - the number of public |
| | | * keys imported, |
| | | * - <kbd>public_unchanged</kbd> - the number of unchanged |
| | | * public keys, |
| | | * - <kbd>private_imported</kbd> - the number of private |
| | | * keys imported, |
| | | * - <kbd>private_unchanged</kbd> - the number of unchanged |
| | | * private keys. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if the key data is missing or if the |
| | | * data is is not valid key data. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function importKey($data) |
| | | { |
| | | return $this->_importKey($data, false); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ importKeyFile() |
| | | |
| | | /** |
| | | * Imports a public or private key file into the keyring |
| | | * |
| | | * Keys may be removed from the keyring using |
| | | * {@link Crypt_GPG::deletePublicKey()} or |
| | | * {@link Crypt_GPG::deletePrivateKey()}. |
| | | * |
| | | * @param string $filename the key file to be imported. |
| | | * |
| | | * @return array an associative array containing the following elements: |
| | | * - <kbd>fingerprint</kbd> - the fingerprint of the |
| | | * imported key, |
| | | * - <kbd>public_imported</kbd> - the number of public |
| | | * keys imported, |
| | | * - <kbd>public_unchanged</kbd> - the number of unchanged |
| | | * public keys, |
| | | * - <kbd>private_imported</kbd> - the number of private |
| | | * keys imported, |
| | | * - <kbd>private_unchanged</kbd> - the number of unchanged |
| | | * private keys. |
| | | * private keys. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if the key data is missing or if the |
| | | * data is is not valid key data. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the key file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function importKeyFile($filename) |
| | | { |
| | | return $this->_importKey($filename, true); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ exportPublicKey() |
| | | |
| | | /** |
| | | * Exports a public key from the keyring |
| | | * |
| | | * The exported key remains on the keyring. To delete the public key, use |
| | | * {@link Crypt_GPG::deletePublicKey()}. |
| | | * |
| | | * If more than one key fingerprint is available for the specified |
| | | * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the |
| | | * first public key is exported. |
| | | * |
| | | * @param string $keyId either the full uid of the public key, the email |
| | | * part of the uid of the public key or the key id of |
| | | * the public key. For example, |
| | | * "Test User (example) <test@example.com>", |
| | | * "test@example.com" or a hexadecimal string. |
| | | * @param boolean $armor optional. If true, ASCII armored data is returned; |
| | | * otherwise, binary data is returned. Defaults to |
| | | * true. |
| | | * |
| | | * @return string the public key data. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if a public key with the given |
| | | * <kbd>$keyId</kbd> is not found. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function exportPublicKey($keyId, $armor = true) |
| | | { |
| | | $fingerprint = $this->getFingerprint($keyId); |
| | | |
| | | if ($fingerprint === null) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Public key not found: ' . $keyId, |
| | | Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId); |
| | | } |
| | | |
| | | $keyData = ''; |
| | | $operation = '--export ' . escapeshellarg($fingerprint); |
| | | $arguments = ($armor) ? array('--armor') : array(); |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setOutput($keyData); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | if ($code !== Crypt_GPG::ERROR_NONE) { |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error exporting public key. Please use the ' . |
| | | '\'debug\' option when creating the Crypt_GPG object, and ' . |
| | | 'file a bug report at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | return $keyData; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ deletePublicKey() |
| | | |
| | | /** |
| | | * Deletes a public key from the keyring |
| | | * |
| | | * If more than one key fingerprint is available for the specified |
| | | * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the |
| | | * first public key is deleted. |
| | | * |
| | | * The private key must be deleted first or an exception will be thrown. |
| | | * See {@link Crypt_GPG::deletePrivateKey()}. |
| | | * |
| | | * @param string $keyId either the full uid of the public key, the email |
| | | * part of the uid of the public key or the key id of |
| | | * the public key. For example, |
| | | * "Test User (example) <test@example.com>", |
| | | * "test@example.com" or a hexadecimal string. |
| | | * |
| | | * @return void |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if a public key with the given |
| | | * <kbd>$keyId</kbd> is not found. |
| | | * |
| | | * @throws Crypt_GPG_DeletePrivateKeyException if the specified public key |
| | | * has an associated private key on the keyring. The private key |
| | | * must be deleted first. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function deletePublicKey($keyId) |
| | | { |
| | | $fingerprint = $this->getFingerprint($keyId); |
| | | |
| | | if ($fingerprint === null) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Public key not found: ' . $keyId, |
| | | Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId); |
| | | } |
| | | |
| | | $operation = '--delete-key ' . escapeshellarg($fingerprint); |
| | | $arguments = array( |
| | | '--batch', |
| | | '--yes' |
| | | ); |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | break; |
| | | case Crypt_GPG::ERROR_DELETE_PRIVATE_KEY: |
| | | throw new Crypt_GPG_DeletePrivateKeyException( |
| | | 'Private key must be deleted before public key can be ' . |
| | | 'deleted.', $code, $keyId); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error deleting public key. Please use the ' . |
| | | '\'debug\' option when creating the Crypt_GPG object, and ' . |
| | | 'file a bug report at ' . self::BUG_URI, $code); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ deletePrivateKey() |
| | | |
| | | /** |
| | | * Deletes a private key from the keyring |
| | | * |
| | | * If more than one key fingerprint is available for the specified |
| | | * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the |
| | | * first private key is deleted. |
| | | * |
| | | * Calls GPG with the <kbd>--delete-secret-key</kbd> command. |
| | | * |
| | | * @param string $keyId either the full uid of the private key, the email |
| | | * part of the uid of the private key or the key id of |
| | | * the private key. For example, |
| | | * "Test User (example) <test@example.com>", |
| | | * "test@example.com" or a hexadecimal string. |
| | | * |
| | | * @return void |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if a private key with the given |
| | | * <kbd>$keyId</kbd> is not found. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function deletePrivateKey($keyId) |
| | | { |
| | | $fingerprint = $this->getFingerprint($keyId); |
| | | |
| | | if ($fingerprint === null) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Private key not found: ' . $keyId, |
| | | Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId); |
| | | } |
| | | |
| | | $operation = '--delete-secret-key ' . escapeshellarg($fingerprint); |
| | | $arguments = array( |
| | | '--batch', |
| | | '--yes' |
| | | ); |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | break; |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Private key not found: ' . $keyId, |
| | | $code, $keyId); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error deleting private key. Please use the ' . |
| | | '\'debug\' option when creating the Crypt_GPG object, and ' . |
| | | 'file a bug report at ' . self::BUG_URI, $code); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getKeys() |
| | | |
| | | /** |
| | | * Gets the available keys in the keyring |
| | | * |
| | | * Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See |
| | | * the first section of <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG package} for a detailed |
| | | * description of how the GPG command output is parsed. |
| | | * |
| | | * @param string $keyId optional. Only keys with that match the specified |
| | | * pattern are returned. The pattern may be part of |
| | | * a user id, a key id or a key fingerprint. If not |
| | | * specified, all keys are returned. |
| | | * |
| | | * @return array an array of {@link Crypt_GPG_Key} objects. If no keys |
| | | * match the specified <kbd>$keyId</kbd> an empty array is |
| | | * returned. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG_Key |
| | | */ |
| | | public function getKeys($keyId = '') |
| | | { |
| | | // get private key fingerprints |
| | | if ($keyId == '') { |
| | | $operation = '--list-secret-keys'; |
| | | } else { |
| | | $operation = '--list-secret-keys ' . escapeshellarg($keyId); |
| | | } |
| | | |
| | | // According to The file 'doc/DETAILS' in the GnuPG distribution, using |
| | | // double '--with-fingerprint' also prints the fingerprint for subkeys. |
| | | $arguments = array( |
| | | '--with-colons', |
| | | '--with-fingerprint', |
| | | '--with-fingerprint', |
| | | '--fixed-list-mode' |
| | | ); |
| | | |
| | | $output = ''; |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | // ignore not found key errors |
| | | break; |
| | | case Crypt_GPG::ERROR_FILE_PERMISSIONS: |
| | | $filename = $this->engine->getErrorFilename(); |
| | | if ($filename) { |
| | | throw new Crypt_GPG_FileException(sprintf( |
| | | 'Error reading GnuPG data file \'%s\'. Check to make ' . |
| | | 'sure it is readable by the current user.', $filename), |
| | | $code, $filename); |
| | | } |
| | | throw new Crypt_GPG_FileException( |
| | | 'Error reading GnuPG data file. Check to make GnuPG data ' . |
| | | 'files are readable by the current user.', $code); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error getting keys. Please use the \'debug\' option ' . |
| | | 'when creating the Crypt_GPG object, and file a bug report ' . |
| | | 'at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | $privateKeyFingerprints = array(); |
| | | |
| | | $lines = explode(PHP_EOL, $output); |
| | | foreach ($lines as $line) { |
| | | $lineExp = explode(':', $line); |
| | | if ($lineExp[0] == 'fpr') { |
| | | $privateKeyFingerprints[] = $lineExp[9]; |
| | | } |
| | | } |
| | | |
| | | // get public keys |
| | | if ($keyId == '') { |
| | | $operation = '--list-public-keys'; |
| | | } else { |
| | | $operation = '--list-public-keys ' . escapeshellarg($keyId); |
| | | } |
| | | |
| | | $output = ''; |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | // ignore not found key errors |
| | | break; |
| | | case Crypt_GPG::ERROR_FILE_PERMISSIONS: |
| | | $filename = $this->engine->getErrorFilename(); |
| | | if ($filename) { |
| | | throw new Crypt_GPG_FileException(sprintf( |
| | | 'Error reading GnuPG data file \'%s\'. Check to make ' . |
| | | 'sure it is readable by the current user.', $filename), |
| | | $code, $filename); |
| | | } |
| | | throw new Crypt_GPG_FileException( |
| | | 'Error reading GnuPG data file. Check to make GnuPG data ' . |
| | | 'files are readable by the current user.', $code); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error getting keys. Please use the \'debug\' option ' . |
| | | 'when creating the Crypt_GPG object, and file a bug report ' . |
| | | 'at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | $keys = array(); |
| | | |
| | | $key = null; // current key |
| | | $subKey = null; // current sub-key |
| | | |
| | | $lines = explode(PHP_EOL, $output); |
| | | foreach ($lines as $line) { |
| | | $lineExp = explode(':', $line); |
| | | |
| | | if ($lineExp[0] == 'pub') { |
| | | |
| | | // new primary key means last key should be added to the array |
| | | if ($key !== null) { |
| | | $keys[] = $key; |
| | | } |
| | | |
| | | $key = new Crypt_GPG_Key(); |
| | | |
| | | $subKey = Crypt_GPG_SubKey::parse($line); |
| | | $key->addSubKey($subKey); |
| | | |
| | | } elseif ($lineExp[0] == 'sub') { |
| | | |
| | | $subKey = Crypt_GPG_SubKey::parse($line); |
| | | $key->addSubKey($subKey); |
| | | |
| | | } elseif ($lineExp[0] == 'fpr') { |
| | | |
| | | $fingerprint = $lineExp[9]; |
| | | |
| | | // set current sub-key fingerprint |
| | | $subKey->setFingerprint($fingerprint); |
| | | |
| | | // if private key exists, set has private to true |
| | | if (in_array($fingerprint, $privateKeyFingerprints)) { |
| | | $subKey->setHasPrivate(true); |
| | | } |
| | | |
| | | } elseif ($lineExp[0] == 'uid') { |
| | | |
| | | $string = stripcslashes($lineExp[9]); // as per documentation |
| | | $userId = new Crypt_GPG_UserId($string); |
| | | |
| | | if ($lineExp[1] == 'r') { |
| | | $userId->setRevoked(true); |
| | | } |
| | | |
| | | $key->addUserId($userId); |
| | | |
| | | } |
| | | } |
| | | |
| | | // add last key |
| | | if ($key !== null) { |
| | | $keys[] = $key; |
| | | } |
| | | |
| | | return $keys; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getFingerprint() |
| | | |
| | | /** |
| | | * Gets a key fingerprint from the keyring |
| | | * |
| | | * If more than one key fingerprint is available (for example, if you use |
| | | * a non-unique user id) only the first key fingerprint is returned. |
| | | * |
| | | * Calls the GPG <kbd>--list-keys</kbd> command with the |
| | | * <kbd>--with-fingerprint</kbd> option to retrieve a public key |
| | | * fingerprint. |
| | | * |
| | | * @param string $keyId either the full user id of the key, the email |
| | | * part of the user id of the key, or the key id of |
| | | * the key. For example, |
| | | * "Test User (example) <test@example.com>", |
| | | * "test@example.com" or a hexadecimal string. |
| | | * @param integer $format optional. How the fingerprint should be formatted. |
| | | * Use {@link Crypt_GPG::FORMAT_X509} for X.509 |
| | | * certificate format, |
| | | * {@link Crypt_GPG::FORMAT_CANONICAL} for the format |
| | | * used by GnuPG output and |
| | | * {@link Crypt_GPG::FORMAT_NONE} for no formatting. |
| | | * Defaults to <code>Crypt_GPG::FORMAT_NONE</code>. |
| | | * |
| | | * @return string the fingerprint of the key, or null if no fingerprint |
| | | * is found for the given <kbd>$keyId</kbd>. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function getFingerprint($keyId, $format = Crypt_GPG::FORMAT_NONE) |
| | | { |
| | | $output = ''; |
| | | $operation = '--list-keys ' . escapeshellarg($keyId); |
| | | $arguments = array( |
| | | '--with-colons', |
| | | '--with-fingerprint' |
| | | ); |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | // ignore not found key errors |
| | | break; |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error getting key fingerprint. Please use the ' . |
| | | '\'debug\' option when creating the Crypt_GPG object, and ' . |
| | | 'file a bug report at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | $fingerprint = null; |
| | | |
| | | $lines = explode(PHP_EOL, $output); |
| | | foreach ($lines as $line) { |
| | | if (substr($line, 0, 3) == 'fpr') { |
| | | $lineExp = explode(':', $line); |
| | | $fingerprint = $lineExp[9]; |
| | | |
| | | switch ($format) { |
| | | case Crypt_GPG::FORMAT_CANONICAL: |
| | | $fingerprintExp = str_split($fingerprint, 4); |
| | | $format = '%s %s %s %s %s %s %s %s %s %s'; |
| | | $fingerprint = vsprintf($format, $fingerprintExp); |
| | | break; |
| | | |
| | | case Crypt_GPG::FORMAT_X509: |
| | | $fingerprintExp = str_split($fingerprint, 2); |
| | | $fingerprint = implode(':', $fingerprintExp); |
| | | break; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return $fingerprint; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ encrypt() |
| | | |
| | | /** |
| | | * Encrypts string data |
| | | * |
| | | * Data is ASCII armored by default but may optionally be returned as |
| | | * binary. |
| | | * |
| | | * @param string $data the data to be encrypted. |
| | | * @param boolean $armor optional. If true, ASCII armored data is returned; |
| | | * otherwise, binary data is returned. Defaults to |
| | | * true. |
| | | * |
| | | * @return string the encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. |
| | | * See {@link Crypt_GPG::addEncryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @sensitive $data |
| | | */ |
| | | public function encrypt($data, $armor = true) |
| | | { |
| | | return $this->_encrypt($data, false, null, $armor); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ encryptFile() |
| | | |
| | | /** |
| | | * Encrypts a file |
| | | * |
| | | * Encrypted data is ASCII armored by default but may optionally be saved |
| | | * as binary. |
| | | * |
| | | * @param string $filename the filename of the file to encrypt. |
| | | * @param string $encryptedFile optional. The filename of the file in |
| | | * which to store the encrypted data. If null |
| | | * or unspecified, the encrypted data is |
| | | * returned as a string. |
| | | * @param boolean $armor optional. If true, ASCII armored data is |
| | | * returned; otherwise, binary data is |
| | | * returned. Defaults to true. |
| | | * |
| | | * @return void|string if the <kbd>$encryptedFile</kbd> parameter is null, |
| | | * a string containing the encrypted data is returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. |
| | | * See {@link Crypt_GPG::addEncryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function encryptFile($filename, $encryptedFile = null, $armor = true) |
| | | { |
| | | return $this->_encrypt($filename, true, $encryptedFile, $armor); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ encryptAndSign() |
| | | |
| | | /** |
| | | * Encrypts and signs data |
| | | * |
| | | * Data is encrypted and signed in a single pass. |
| | | * |
| | | * NOTE: Until GnuPG version 1.4.10, it was not possible to verify |
| | | * encrypted-signed data without decrypting it at the same time. If you try |
| | | * to use {@link Crypt_GPG::verify()} method on encrypted-signed data with |
| | | * earlier GnuPG versions, you will get an error. Please use |
| | | * {@link Crypt_GPG::decryptAndVerify()} to verify encrypted-signed data. |
| | | * |
| | | * @param string $data the data to be encrypted and signed. |
| | | * @param boolean $armor optional. If true, ASCII armored data is returned; |
| | | * otherwise, binary data is returned. Defaults to |
| | | * true. |
| | | * |
| | | * @return string the encrypted signed data. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified |
| | | * or if no signing key is specified. See |
| | | * {@link Crypt_GPG::addEncryptKey()} and |
| | | * {@link Crypt_GPG::addSignKey()}. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is |
| | | * incorrect or if a required passphrase is not specified. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG::decryptAndVerify() |
| | | */ |
| | | public function encryptAndSign($data, $armor = true) |
| | | { |
| | | return $this->_encryptAndSign($data, false, null, $armor); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ encryptAndSignFile() |
| | | |
| | | /** |
| | | * Encrypts and signs a file |
| | | * |
| | | * The file is encrypted and signed in a single pass. |
| | | * |
| | | * NOTE: Until GnuPG version 1.4.10, it was not possible to verify |
| | | * encrypted-signed files without decrypting them at the same time. If you |
| | | * try to use {@link Crypt_GPG::verify()} method on encrypted-signed files |
| | | * with earlier GnuPG versions, you will get an error. Please use |
| | | * {@link Crypt_GPG::decryptAndVerifyFile()} to verify encrypted-signed |
| | | * files. |
| | | * |
| | | * @param string $filename the name of the file containing the data to |
| | | * be encrypted and signed. |
| | | * @param string $signedFile optional. The name of the file in which the |
| | | * encrypted, signed data should be stored. If |
| | | * null or unspecified, the encrypted, signed |
| | | * data is returned as a string. |
| | | * @param boolean $armor optional. If true, ASCII armored data is |
| | | * returned; otherwise, binary data is returned. |
| | | * Defaults to true. |
| | | * |
| | | * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a |
| | | * string containing the encrypted, signed data is |
| | | * returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified |
| | | * or if no signing key is specified. See |
| | | * {@link Crypt_GPG::addEncryptKey()} and |
| | | * {@link Crypt_GPG::addSignKey()}. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is |
| | | * incorrect or if a required passphrase is not specified. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG::decryptAndVerifyFile() |
| | | */ |
| | | public function encryptAndSignFile($filename, $signedFile = null, |
| | | $armor = true |
| | | ) { |
| | | return $this->_encryptAndSign($filename, true, $signedFile, $armor); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ decrypt() |
| | | |
| | | /** |
| | | * Decrypts string data |
| | | * |
| | | * This method assumes the required private key is available in the keyring |
| | | * and throws an exception if the private key is not available. To add a |
| | | * private key to the keyring, use the {@link Crypt_GPG::importKey()} or |
| | | * {@link Crypt_GPG::importKeyFile()} methods. |
| | | * |
| | | * @param string $encryptedData the data to be decrypted. |
| | | * |
| | | * @return string the decrypted data. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function decrypt($encryptedData) |
| | | { |
| | | return $this->_decrypt($encryptedData, false, null); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ decryptFile() |
| | | |
| | | /** |
| | | * Decrypts a file |
| | | * |
| | | * This method assumes the required private key is available in the keyring |
| | | * and throws an exception if the private key is not available. To add a |
| | | * private key to the keyring, use the {@link Crypt_GPG::importKey()} or |
| | | * {@link Crypt_GPG::importKeyFile()} methods. |
| | | * |
| | | * @param string $encryptedFile the name of the encrypted file data to |
| | | * decrypt. |
| | | * @param string $decryptedFile optional. The name of the file to which the |
| | | * decrypted data should be written. If null |
| | | * or unspecified, the decrypted data is |
| | | * returned as a string. |
| | | * |
| | | * @return void|string if the <kbd>$decryptedFile</kbd> parameter is null, |
| | | * a string containing the decrypted data is returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function decryptFile($encryptedFile, $decryptedFile = null) |
| | | { |
| | | return $this->_decrypt($encryptedFile, true, $decryptedFile); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ decryptAndVerify() |
| | | |
| | | /** |
| | | * Decrypts and verifies string data |
| | | * |
| | | * This method assumes the required private key is available in the keyring |
| | | * and throws an exception if the private key is not available. To add a |
| | | * private key to the keyring, use the {@link Crypt_GPG::importKey()} or |
| | | * {@link Crypt_GPG::importKeyFile()} methods. |
| | | * |
| | | * @param string $encryptedData the encrypted, signed data to be decrypted |
| | | * and verified. |
| | | * |
| | | * @return array two element array. The array has an element 'data' |
| | | * containing the decrypted data and an element |
| | | * 'signatures' containing an array of |
| | | * {@link Crypt_GPG_Signature} objects for the signed data. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function decryptAndVerify($encryptedData) |
| | | { |
| | | return $this->_decryptAndVerify($encryptedData, false, null); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ decryptAndVerifyFile() |
| | | |
| | | /** |
| | | * Decrypts and verifies a signed, encrypted file |
| | | * |
| | | * This method assumes the required private key is available in the keyring |
| | | * and throws an exception if the private key is not available. To add a |
| | | * private key to the keyring, use the {@link Crypt_GPG::importKey()} or |
| | | * {@link Crypt_GPG::importKeyFile()} methods. |
| | | * |
| | | * @param string $encryptedFile the name of the signed, encrypted file to |
| | | * to decrypt and verify. |
| | | * @param string $decryptedFile optional. The name of the file to which the |
| | | * decrypted data should be written. If null |
| | | * or unspecified, the decrypted data is |
| | | * returned in the results array. |
| | | * |
| | | * @return array two element array. The array has an element 'data' |
| | | * containing the decrypted data and an element |
| | | * 'signatures' containing an array of |
| | | * {@link Crypt_GPG_Signature} objects for the signed data. |
| | | * If the decrypted data is written to a file, the 'data' |
| | | * element is null. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function decryptAndVerifyFile($encryptedFile, $decryptedFile = null) |
| | | { |
| | | return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ sign() |
| | | |
| | | /** |
| | | * Signs data |
| | | * |
| | | * Data may be signed using any one of the three available signing modes: |
| | | * - {@link Crypt_GPG::SIGN_MODE_NORMAL} |
| | | * - {@link Crypt_GPG::SIGN_MODE_CLEAR} |
| | | * - {@link Crypt_GPG::SIGN_MODE_DETACHED} |
| | | * |
| | | * @param string $data the data to be signed. |
| | | * @param boolean $mode optional. The data signing mode to use. Should |
| | | * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL}, |
| | | * {@link Crypt_GPG::SIGN_MODE_CLEAR} or |
| | | * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not |
| | | * specified, defaults to |
| | | * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>. |
| | | * @param boolean $armor optional. If true, ASCII armored data is |
| | | * returned; otherwise, binary data is returned. |
| | | * Defaults to true. This has no effect if the |
| | | * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is |
| | | * used. |
| | | * @param boolean $textmode optional. If true, line-breaks in signed data |
| | | * are normalized. Use this option when signing |
| | | * e-mail, or for greater compatibility between |
| | | * systems with different line-break formats. |
| | | * Defaults to false. This has no effect if the |
| | | * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is |
| | | * used as clear-signing always uses textmode. |
| | | * |
| | | * @return string the signed data, or the signature data if a detached |
| | | * signature is requested. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. |
| | | * See {@link Crypt_GPG::addSignKey()}. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is |
| | | * incorrect or if a required passphrase is not specified. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function sign($data, $mode = Crypt_GPG::SIGN_MODE_NORMAL, |
| | | $armor = true, $textmode = false |
| | | ) { |
| | | return $this->_sign($data, false, null, $mode, $armor, $textmode); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ signFile() |
| | | |
| | | /** |
| | | * Signs a file |
| | | * |
| | | * The file may be signed using any one of the three available signing |
| | | * modes: |
| | | * - {@link Crypt_GPG::SIGN_MODE_NORMAL} |
| | | * - {@link Crypt_GPG::SIGN_MODE_CLEAR} |
| | | * - {@link Crypt_GPG::SIGN_MODE_DETACHED} |
| | | * |
| | | * @param string $filename the name of the file containing the data to |
| | | * be signed. |
| | | * @param string $signedFile optional. The name of the file in which the |
| | | * signed data should be stored. If null or |
| | | * unspecified, the signed data is returned as a |
| | | * string. |
| | | * @param boolean $mode optional. The data signing mode to use. Should |
| | | * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL}, |
| | | * {@link Crypt_GPG::SIGN_MODE_CLEAR} or |
| | | * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not |
| | | * specified, defaults to |
| | | * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>. |
| | | * @param boolean $armor optional. If true, ASCII armored data is |
| | | * returned; otherwise, binary data is returned. |
| | | * Defaults to true. This has no effect if the |
| | | * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is |
| | | * used. |
| | | * @param boolean $textmode optional. If true, line-breaks in signed data |
| | | * are normalized. Use this option when signing |
| | | * e-mail, or for greater compatibility between |
| | | * systems with different line-break formats. |
| | | * Defaults to false. This has no effect if the |
| | | * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is |
| | | * used as clear-signing always uses textmode. |
| | | * |
| | | * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a |
| | | * string containing the signed data (or the signature |
| | | * data if a detached signature is requested) is |
| | | * returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. |
| | | * See {@link Crypt_GPG::addSignKey()}. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is |
| | | * incorrect or if a required passphrase is not specified. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function signFile($filename, $signedFile = null, |
| | | $mode = Crypt_GPG::SIGN_MODE_NORMAL, $armor = true, $textmode = false |
| | | ) { |
| | | return $this->_sign( |
| | | $filename, |
| | | true, |
| | | $signedFile, |
| | | $mode, |
| | | $armor, |
| | | $textmode |
| | | ); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ verify() |
| | | |
| | | /** |
| | | * Verifies signed data |
| | | * |
| | | * The {@link Crypt_GPG::decrypt()} method may be used to get the original |
| | | * message if the signed data is not clearsigned and does not use a |
| | | * detached signature. |
| | | * |
| | | * @param string $signedData the signed data to be verified. |
| | | * @param string $signature optional. If verifying data signed using a |
| | | * detached signature, this must be the detached |
| | | * signature data. The data that was signed is |
| | | * specified in <kbd>$signedData</kbd>. |
| | | * |
| | | * @return array an array of {@link Crypt_GPG_Signature} objects for the |
| | | * signed data. For each signature that is valid, the |
| | | * {@link Crypt_GPG_Signature::isValid()} will return true. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if the provided data is not signed |
| | | * data. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG_Signature |
| | | */ |
| | | public function verify($signedData, $signature = '') |
| | | { |
| | | return $this->_verify($signedData, false, $signature); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ verifyFile() |
| | | |
| | | /** |
| | | * Verifies a signed file |
| | | * |
| | | * The {@link Crypt_GPG::decryptFile()} method may be used to get the |
| | | * original message if the signed data is not clearsigned and does not use |
| | | * a detached signature. |
| | | * |
| | | * @param string $filename the signed file to be verified. |
| | | * @param string $signature optional. If verifying a file signed using a |
| | | * detached signature, this must be the detached |
| | | * signature data. The file that was signed is |
| | | * specified in <kbd>$filename</kbd>. |
| | | * |
| | | * @return array an array of {@link Crypt_GPG_Signature} objects for the |
| | | * signed data. For each signature that is valid, the |
| | | * {@link Crypt_GPG_Signature::isValid()} will return true. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if the provided data is not signed |
| | | * data. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG_Signature |
| | | */ |
| | | public function verifyFile($filename, $signature = '') |
| | | { |
| | | return $this->_verify($filename, true, $signature); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addDecryptKey() |
| | | |
| | | /** |
| | | * Adds a key to use for decryption |
| | | * |
| | | * @param mixed $key the key to use. This may be a key identifier, |
| | | * user id, fingerprint, {@link Crypt_GPG_Key} or |
| | | * {@link Crypt_GPG_SubKey}. The key must be able |
| | | * to encrypt. |
| | | * @param string $passphrase optional. The passphrase of the key required |
| | | * for decryption. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::decrypt() |
| | | * @see Crypt_GPG::decryptFile() |
| | | * @see Crypt_GPG::clearDecryptKeys() |
| | | * @see Crypt_GPG::_addKey() |
| | | * @see Crypt_GPG_DecryptStatusHandler |
| | | * |
| | | * @sensitive $passphrase |
| | | */ |
| | | public function addDecryptKey($key, $passphrase = null) |
| | | { |
| | | $this->_addKey($this->decryptKeys, true, false, $key, $passphrase); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addEncryptKey() |
| | | |
| | | /** |
| | | * Adds a key to use for encryption |
| | | * |
| | | * @param mixed $key the key to use. This may be a key identifier, user id |
| | | * user id, fingerprint, {@link Crypt_GPG_Key} or |
| | | * {@link Crypt_GPG_SubKey}. The key must be able to |
| | | * encrypt. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::encrypt() |
| | | * @see Crypt_GPG::encryptFile() |
| | | * @see Crypt_GPG::clearEncryptKeys() |
| | | * @see Crypt_GPG::_addKey() |
| | | */ |
| | | public function addEncryptKey($key) |
| | | { |
| | | $this->_addKey($this->encryptKeys, true, false, $key); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addSignKey() |
| | | |
| | | /** |
| | | * Adds a key to use for signing |
| | | * |
| | | * @param mixed $key the key to use. This may be a key identifier, |
| | | * user id, fingerprint, {@link Crypt_GPG_Key} or |
| | | * {@link Crypt_GPG_SubKey}. The key must be able |
| | | * to sign. |
| | | * @param string $passphrase optional. The passphrase of the key required |
| | | * for signing. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::sign() |
| | | * @see Crypt_GPG::signFile() |
| | | * @see Crypt_GPG::clearSignKeys() |
| | | * @see Crypt_GPG::handleSignStatus() |
| | | * @see Crypt_GPG::_addKey() |
| | | * |
| | | * @sensitive $passphrase |
| | | */ |
| | | public function addSignKey($key, $passphrase = null) |
| | | { |
| | | $this->_addKey($this->signKeys, false, true, $key, $passphrase); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ clearDecryptKeys() |
| | | |
| | | /** |
| | | * Clears all decryption keys |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::decrypt() |
| | | * @see Crypt_GPG::addDecryptKey() |
| | | */ |
| | | public function clearDecryptKeys() |
| | | { |
| | | $this->decryptKeys = array(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ clearEncryptKeys() |
| | | |
| | | /** |
| | | * Clears all encryption keys |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::encrypt() |
| | | * @see Crypt_GPG::addEncryptKey() |
| | | */ |
| | | public function clearEncryptKeys() |
| | | { |
| | | $this->encryptKeys = array(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ clearSignKeys() |
| | | |
| | | /** |
| | | * Clears all signing keys |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::sign() |
| | | * @see Crypt_GPG::addSignKey() |
| | | */ |
| | | public function clearSignKeys() |
| | | { |
| | | $this->signKeys = array(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ handleSignStatus() |
| | | |
| | | /** |
| | | * Handles the status output from GPG for the sign operation |
| | | * |
| | | * This method is responsible for sending the passphrase commands when |
| | | * required by the {@link Crypt_GPG::sign()} method. See <b>doc/DETAILS</b> |
| | | * in the {@link http://www.gnupg.org/download/ GPG distribution} for |
| | | * detailed information on GPG's status output. |
| | | * |
| | | * @param string $line the status line to handle. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::sign() |
| | | */ |
| | | public function handleSignStatus($line) |
| | | { |
| | | $tokens = explode(' ', $line); |
| | | switch ($tokens[0]) { |
| | | case 'NEED_PASSPHRASE': |
| | | $subKeyId = $tokens[1]; |
| | | if (array_key_exists($subKeyId, $this->signKeys)) { |
| | | $passphrase = $this->signKeys[$subKeyId]['passphrase']; |
| | | $this->engine->sendCommand($passphrase); |
| | | } else { |
| | | $this->engine->sendCommand(''); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ handleImportKeyStatus() |
| | | |
| | | /** |
| | | * Handles the status output from GPG for the import operation |
| | | * |
| | | * This method is responsible for building the result array that is |
| | | * returned from the {@link Crypt_GPG::importKey()} method. See |
| | | * <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG distribution} for detailed |
| | | * information on GPG's status output. |
| | | * |
| | | * @param string $line the status line to handle. |
| | | * @param array &$result the current result array being processed. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG::importKey() |
| | | * @see Crypt_GPG::importKeyFile() |
| | | * @see Crypt_GPG_Engine::addStatusHandler() |
| | | */ |
| | | public function handleImportKeyStatus($line, array &$result) |
| | | { |
| | | $tokens = explode(' ', $line); |
| | | switch ($tokens[0]) { |
| | | case 'IMPORT_OK': |
| | | $result['fingerprint'] = $tokens[2]; |
| | | break; |
| | | |
| | | case 'IMPORT_RES': |
| | | $result['public_imported'] = intval($tokens[3]); |
| | | $result['public_unchanged'] = intval($tokens[5]); |
| | | $result['private_imported'] = intval($tokens[11]); |
| | | $result['private_unchanged'] = intval($tokens[12]); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setEngine() |
| | | |
| | | /** |
| | | * Sets the I/O engine to use for GnuPG operations |
| | | * |
| | | * Normally this method does not need to be used. It provides a means for |
| | | * dependency injection. |
| | | * |
| | | * @param Crypt_GPG_Engine $engine the engine to use. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function setEngine(Crypt_GPG_Engine $engine) |
| | | { |
| | | $this->engine = $engine; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _addKey() |
| | | |
| | | /** |
| | | * Adds a key to one of the internal key arrays |
| | | * |
| | | * This handles resolving full key objects from the provided |
| | | * <kbd>$key</kbd> value. |
| | | * |
| | | * @param array &$array the array to which the key should be added. |
| | | * @param boolean $encrypt whether or not the key must be able to |
| | | * encrypt. |
| | | * @param boolean $sign whether or not the key must be able to sign. |
| | | * @param mixed $key the key to add. This may be a key identifier, |
| | | * user id, fingerprint, {@link Crypt_GPG_Key} or |
| | | * {@link Crypt_GPG_SubKey}. |
| | | * @param string $passphrase optional. The passphrase associated with the |
| | | * key. |
| | | * |
| | | * @return void |
| | | * |
| | | * @sensitive $passphrase |
| | | */ |
| | | private function _addKey(array &$array, $encrypt, $sign, $key, |
| | | $passphrase = null |
| | | ) { |
| | | $subKeys = array(); |
| | | |
| | | if (is_scalar($key)) { |
| | | $keys = $this->getKeys($key); |
| | | if (count($keys) == 0) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Key "' . $key . '" not found.', 0, $key); |
| | | } |
| | | $key = $keys[0]; |
| | | } |
| | | |
| | | if ($key instanceof Crypt_GPG_Key) { |
| | | if ($encrypt && !$key->canEncrypt()) { |
| | | throw new InvalidArgumentException( |
| | | 'Key "' . $key . '" cannot encrypt.'); |
| | | } |
| | | |
| | | if ($sign && !$key->canSign()) { |
| | | throw new InvalidArgumentException( |
| | | 'Key "' . $key . '" cannot sign.'); |
| | | } |
| | | |
| | | foreach ($key->getSubKeys() as $subKey) { |
| | | $canEncrypt = $subKey->canEncrypt(); |
| | | $canSign = $subKey->canSign(); |
| | | if ( ($encrypt && $sign && $canEncrypt && $canSign) |
| | | || ($encrypt && !$sign && $canEncrypt) |
| | | || (!$encrypt && $sign && $canSign) |
| | | ) { |
| | | // We add all subkeys that meet the requirements because we |
| | | // were not told which subkey is required. |
| | | $subKeys[] = $subKey; |
| | | } |
| | | } |
| | | } elseif ($key instanceof Crypt_GPG_SubKey) { |
| | | $subKeys[] = $key; |
| | | } |
| | | |
| | | if (count($subKeys) === 0) { |
| | | throw new InvalidArgumentException( |
| | | 'Key "' . $key . '" is not in a recognized format.'); |
| | | } |
| | | |
| | | foreach ($subKeys as $subKey) { |
| | | if ($encrypt && !$subKey->canEncrypt()) { |
| | | throw new InvalidArgumentException( |
| | | 'Key "' . $key . '" cannot encrypt.'); |
| | | } |
| | | |
| | | if ($sign && !$subKey->canSign()) { |
| | | throw new InvalidArgumentException( |
| | | 'Key "' . $key . '" cannot sign.'); |
| | | } |
| | | |
| | | $array[$subKey->getId()] = array( |
| | | 'fingerprint' => $subKey->getFingerprint(), |
| | | 'passphrase' => $passphrase |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _importKey() |
| | | |
| | | /** |
| | | * Imports a public or private key into the keyring |
| | | * |
| | | * @param string $key the key to be imported. |
| | | * @param boolean $isFile whether or not the input is a filename. |
| | | * |
| | | * @return array an associative array containing the following elements: |
| | | * - <kbd>fingerprint</kbd> - the fingerprint of the |
| | | * imported key, |
| | | * - <kbd>public_imported</kbd> - the number of public |
| | | * keys imported, |
| | | * - <kbd>public_unchanged</kbd> - the number of unchanged |
| | | * public keys, |
| | | * - <kbd>private_imported</kbd> - the number of private |
| | | * keys imported, |
| | | * - <kbd>private_unchanged</kbd> - the number of unchanged |
| | | * private keys. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if the key data is missing or if the |
| | | * data is is not valid key data. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the key file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | private function _importKey($key, $isFile) |
| | | { |
| | | $result = array(); |
| | | |
| | | if ($isFile) { |
| | | $input = @fopen($key, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open key file "' . |
| | | $key . '" for importing.', 0, $key); |
| | | } |
| | | } else { |
| | | $input = strval($key); |
| | | if ($input == '') { |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'No valid GPG key data found.', Crypt_GPG::ERROR_NO_DATA); |
| | | } |
| | | } |
| | | |
| | | $arguments = array(); |
| | | $version = $this->engine->getVersion(); |
| | | |
| | | if ( version_compare($version, '1.0.5', 'ge') |
| | | && version_compare($version, '1.0.7', 'lt') |
| | | ) { |
| | | $arguments[] = '--allow-secret-key-import'; |
| | | } |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->addStatusHandler( |
| | | array($this, 'handleImportKeyStatus'), |
| | | array(&$result) |
| | | ); |
| | | |
| | | $this->engine->setOperation('--import', $arguments); |
| | | $this->engine->setInput($input); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_DUPLICATE_KEY: |
| | | case Crypt_GPG::ERROR_NONE: |
| | | // ignore duplicate key import errors |
| | | break; |
| | | case Crypt_GPG::ERROR_NO_DATA: |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'No valid GPG key data found.', $code); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error importing GPG key. Please use the \'debug\' ' . |
| | | 'option when creating the Crypt_GPG object, and file a bug ' . |
| | | 'report at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _encrypt() |
| | | |
| | | /** |
| | | * Encrypts data |
| | | * |
| | | * @param string $data the data to encrypt. |
| | | * @param boolean $isFile whether or not the data is a filename. |
| | | * @param string $outputFile the filename of the file in which to store |
| | | * the encrypted data. If null, the encrypted |
| | | * data is returned as a string. |
| | | * @param boolean $armor if true, ASCII armored data is returned; |
| | | * otherwise, binary data is returned. |
| | | * |
| | | * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a |
| | | * string containing the encrypted data is returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. |
| | | * See {@link Crypt_GPG::addEncryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | private function _encrypt($data, $isFile, $outputFile, $armor) |
| | | { |
| | | if (count($this->encryptKeys) === 0) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'No encryption keys specified.'); |
| | | } |
| | | |
| | | if ($isFile) { |
| | | $input = @fopen($data, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open input file "' . |
| | | $data . '" for encryption.', 0, $data); |
| | | } |
| | | } else { |
| | | $input = strval($data); |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | $output = ''; |
| | | } else { |
| | | $output = @fopen($outputFile, 'wb'); |
| | | if ($output === false) { |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | throw new Crypt_GPG_FileException('Could not open output ' . |
| | | 'file "' . $outputFile . '" for storing encrypted data.', |
| | | 0, $outputFile); |
| | | } |
| | | } |
| | | |
| | | $arguments = ($armor) ? array('--armor') : array(); |
| | | foreach ($this->encryptKeys as $key) { |
| | | $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']); |
| | | } |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->setInput($input); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation('--encrypt', $arguments); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | if ($outputFile !== null) { |
| | | fclose($output); |
| | | } |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | if ($code !== Crypt_GPG::ERROR_NONE) { |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error encrypting data. Please use the \'debug\' ' . |
| | | 'option when creating the Crypt_GPG object, and file a bug ' . |
| | | 'report at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | return $output; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _decrypt() |
| | | |
| | | /** |
| | | * Decrypts data |
| | | * |
| | | * @param string $data the data to be decrypted. |
| | | * @param boolean $isFile whether or not the data is a filename. |
| | | * @param string $outputFile the name of the file to which the decrypted |
| | | * data should be written. If null, the decrypted |
| | | * data is returned as a string. |
| | | * |
| | | * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a |
| | | * string containing the decrypted data is returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | private function _decrypt($data, $isFile, $outputFile) |
| | | { |
| | | if ($isFile) { |
| | | $input = @fopen($data, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open input file "' . |
| | | $data . '" for decryption.', 0, $data); |
| | | } |
| | | } else { |
| | | $input = strval($data); |
| | | if ($input == '') { |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'Cannot decrypt data. No PGP encrypted data was found in '. |
| | | 'the provided data.', Crypt_GPG::ERROR_NO_DATA); |
| | | } |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | $output = ''; |
| | | } else { |
| | | $output = @fopen($outputFile, 'wb'); |
| | | if ($output === false) { |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | throw new Crypt_GPG_FileException('Could not open output ' . |
| | | 'file "' . $outputFile . '" for storing decrypted data.', |
| | | 0, $outputFile); |
| | | } |
| | | } |
| | | |
| | | $handler = new Crypt_GPG_DecryptStatusHandler($this->engine, |
| | | $this->decryptKeys); |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->addStatusHandler(array($handler, 'handle')); |
| | | $this->engine->setOperation('--decrypt'); |
| | | $this->engine->setInput($input); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | if ($outputFile !== null) { |
| | | fclose($output); |
| | | } |
| | | |
| | | // if there was any problem decrypting the data, the handler will |
| | | // deal with it here. |
| | | $handler->throwException(); |
| | | |
| | | if ($outputFile === null) { |
| | | return $output; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _sign() |
| | | |
| | | /** |
| | | * Signs data |
| | | * |
| | | * @param string $data the data to be signed. |
| | | * @param boolean $isFile whether or not the data is a filename. |
| | | * @param string $outputFile the name of the file in which the signed data |
| | | * should be stored. If null, the signed data is |
| | | * returned as a string. |
| | | * @param boolean $mode the data signing mode to use. Should be one of |
| | | * {@link Crypt_GPG::SIGN_MODE_NORMAL}, |
| | | * {@link Crypt_GPG::SIGN_MODE_CLEAR} or |
| | | * {@link Crypt_GPG::SIGN_MODE_DETACHED}. |
| | | * @param boolean $armor if true, ASCII armored data is returned; |
| | | * otherwise, binary data is returned. This has |
| | | * no effect if the mode |
| | | * <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is |
| | | * used. |
| | | * @param boolean $textmode if true, line-breaks in signed data be |
| | | * normalized. Use this option when signing |
| | | * e-mail, or for greater compatibility between |
| | | * systems with different line-break formats. |
| | | * Defaults to false. This has no effect if the |
| | | * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is |
| | | * used as clear-signing always uses textmode. |
| | | * |
| | | * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a |
| | | * string containing the signed data (or the signature |
| | | * data if a detached signature is requested) is |
| | | * returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. |
| | | * See {@link Crypt_GPG::addSignKey()}. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is |
| | | * incorrect or if a required passphrase is not specified. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | private function _sign($data, $isFile, $outputFile, $mode, $armor, |
| | | $textmode |
| | | ) { |
| | | if (count($this->signKeys) === 0) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'No signing keys specified.'); |
| | | } |
| | | |
| | | if ($isFile) { |
| | | $input = @fopen($data, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open input ' . |
| | | 'file "' . $data . '" for signing.', 0, $data); |
| | | } |
| | | } else { |
| | | $input = strval($data); |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | $output = ''; |
| | | } else { |
| | | $output = @fopen($outputFile, 'wb'); |
| | | if ($output === false) { |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | throw new Crypt_GPG_FileException('Could not open output ' . |
| | | 'file "' . $outputFile . '" for storing signed ' . |
| | | 'data.', 0, $outputFile); |
| | | } |
| | | } |
| | | |
| | | switch ($mode) { |
| | | case Crypt_GPG::SIGN_MODE_DETACHED: |
| | | $operation = '--detach-sign'; |
| | | break; |
| | | case Crypt_GPG::SIGN_MODE_CLEAR: |
| | | $operation = '--clearsign'; |
| | | break; |
| | | case Crypt_GPG::SIGN_MODE_NORMAL: |
| | | default: |
| | | $operation = '--sign'; |
| | | break; |
| | | } |
| | | |
| | | $arguments = array(); |
| | | |
| | | if ($armor) { |
| | | $arguments[] = '--armor'; |
| | | } |
| | | if ($textmode) { |
| | | $arguments[] = '--textmode'; |
| | | } |
| | | |
| | | foreach ($this->signKeys as $key) { |
| | | $arguments[] = '--local-user ' . |
| | | escapeshellarg($key['fingerprint']); |
| | | } |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->addStatusHandler(array($this, 'handleSignStatus')); |
| | | $this->engine->setInput($input); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | if ($outputFile !== null) { |
| | | fclose($output); |
| | | } |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | break; |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Cannot sign data. Private key not found. Import the '. |
| | | 'private key before trying to sign data.', $code, |
| | | $this->engine->getErrorKeyId()); |
| | | case Crypt_GPG::ERROR_BAD_PASSPHRASE: |
| | | throw new Crypt_GPG_BadPassphraseException( |
| | | 'Cannot sign data. Incorrect passphrase provided.', $code); |
| | | case Crypt_GPG::ERROR_MISSING_PASSPHRASE: |
| | | throw new Crypt_GPG_BadPassphraseException( |
| | | 'Cannot sign data. No passphrase provided.', $code); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error signing data. Please use the \'debug\' option ' . |
| | | 'when creating the Crypt_GPG object, and file a bug report ' . |
| | | 'at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | return $output; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _encryptAndSign() |
| | | |
| | | /** |
| | | * Encrypts and signs data |
| | | * |
| | | * @param string $data the data to be encrypted and signed. |
| | | * @param boolean $isFile whether or not the data is a filename. |
| | | * @param string $outputFile the name of the file in which the encrypted, |
| | | * signed data should be stored. If null, the |
| | | * encrypted, signed data is returned as a |
| | | * string. |
| | | * @param boolean $armor if true, ASCII armored data is returned; |
| | | * otherwise, binary data is returned. |
| | | * |
| | | * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a |
| | | * string containing the encrypted, signed data is |
| | | * returned. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified |
| | | * or if no signing key is specified. See |
| | | * {@link Crypt_GPG::addEncryptKey()} and |
| | | * {@link Crypt_GPG::addSignKey()}. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is |
| | | * incorrect or if a required passphrase is not specified. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | private function _encryptAndSign($data, $isFile, $outputFile, $armor) |
| | | { |
| | | if (count($this->signKeys) === 0) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'No signing keys specified.'); |
| | | } |
| | | |
| | | if (count($this->encryptKeys) === 0) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'No encryption keys specified.'); |
| | | } |
| | | |
| | | |
| | | if ($isFile) { |
| | | $input = @fopen($data, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open input ' . |
| | | 'file "' . $data . '" for encrypting and signing.', 0, |
| | | $data); |
| | | } |
| | | } else { |
| | | $input = strval($data); |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | $output = ''; |
| | | } else { |
| | | $output = @fopen($outputFile, 'wb'); |
| | | if ($output === false) { |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | throw new Crypt_GPG_FileException('Could not open output ' . |
| | | 'file "' . $outputFile . '" for storing encrypted, ' . |
| | | 'signed data.', 0, $outputFile); |
| | | } |
| | | } |
| | | |
| | | $arguments = ($armor) ? array('--armor') : array(); |
| | | |
| | | foreach ($this->signKeys as $key) { |
| | | $arguments[] = '--local-user ' . |
| | | escapeshellarg($key['fingerprint']); |
| | | } |
| | | |
| | | foreach ($this->encryptKeys as $key) { |
| | | $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']); |
| | | } |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->addStatusHandler(array($this, 'handleSignStatus')); |
| | | $this->engine->setInput($input); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation('--encrypt --sign', $arguments); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | if ($outputFile !== null) { |
| | | fclose($output); |
| | | } |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | break; |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Cannot sign encrypted data. Private key not found. Import '. |
| | | 'the private key before trying to sign the encrypted data.', |
| | | $code, $this->engine->getErrorKeyId()); |
| | | case Crypt_GPG::ERROR_BAD_PASSPHRASE: |
| | | throw new Crypt_GPG_BadPassphraseException( |
| | | 'Cannot sign encrypted data. Incorrect passphrase provided.', |
| | | $code); |
| | | case Crypt_GPG::ERROR_MISSING_PASSPHRASE: |
| | | throw new Crypt_GPG_BadPassphraseException( |
| | | 'Cannot sign encrypted data. No passphrase provided.', $code); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error encrypting and signing data. Please use the ' . |
| | | '\'debug\' option when creating the Crypt_GPG object, and ' . |
| | | 'file a bug report at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | return $output; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _verify() |
| | | |
| | | /** |
| | | * Verifies data |
| | | * |
| | | * @param string $data the signed data to be verified. |
| | | * @param boolean $isFile whether or not the data is a filename. |
| | | * @param string $signature if verifying a file signed using a detached |
| | | * signature, this must be the detached signature |
| | | * data. Otherwise, specify ''. |
| | | * |
| | | * @return array an array of {@link Crypt_GPG_Signature} objects for the |
| | | * signed data. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if the provided data is not signed |
| | | * data. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG_Signature |
| | | */ |
| | | private function _verify($data, $isFile, $signature) |
| | | { |
| | | if ($signature == '') { |
| | | $operation = '--verify'; |
| | | $arguments = array(); |
| | | } else { |
| | | // Signed data goes in FD_MESSAGE, detached signature data goes in |
| | | // FD_INPUT. |
| | | $operation = '--verify - "-&' . Crypt_GPG_Engine::FD_MESSAGE. '"'; |
| | | $arguments = array('--enable-special-filenames'); |
| | | } |
| | | |
| | | $handler = new Crypt_GPG_VerifyStatusHandler(); |
| | | |
| | | if ($isFile) { |
| | | $input = @fopen($data, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open input ' . |
| | | 'file "' . $data . '" for verifying.', 0, $data); |
| | | } |
| | | } else { |
| | | $input = strval($data); |
| | | if ($input == '') { |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'No valid signature data found.', Crypt_GPG::ERROR_NO_DATA); |
| | | } |
| | | } |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->addStatusHandler(array($handler, 'handle')); |
| | | |
| | | if ($signature == '') { |
| | | // signed or clearsigned data |
| | | $this->engine->setInput($input); |
| | | } else { |
| | | // detached signature |
| | | $this->engine->setInput($signature); |
| | | $this->engine->setMessage($input); |
| | | } |
| | | |
| | | $this->engine->setOperation($operation, $arguments); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | $code = $this->engine->getErrorCode(); |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | case Crypt_GPG::ERROR_BAD_SIGNATURE: |
| | | break; |
| | | case Crypt_GPG::ERROR_NO_DATA: |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'No valid signature data found.', $code); |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Public key required for data verification not in keyring.', |
| | | $code, $this->engine->getErrorKeyId()); |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error validating signature details. Please use the ' . |
| | | '\'debug\' option when creating the Crypt_GPG object, and ' . |
| | | 'file a bug report at ' . self::BUG_URI, $code); |
| | | } |
| | | |
| | | return $handler->getSignatures(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _decryptAndVerify() |
| | | |
| | | /** |
| | | * Decrypts and verifies encrypted, signed data |
| | | * |
| | | * @param string $data the encrypted signed data to be decrypted and |
| | | * verified. |
| | | * @param boolean $isFile whether or not the data is a filename. |
| | | * @param string $outputFile the name of the file to which the decrypted |
| | | * data should be written. If null, the decrypted |
| | | * data is returned in the results array. |
| | | * |
| | | * @return array two element array. The array has an element 'data' |
| | | * containing the decrypted data and an element |
| | | * 'signatures' containing an array of |
| | | * {@link Crypt_GPG_Signature} objects for the signed data. |
| | | * If the decrypted data is written to a file, the 'data' |
| | | * element is null. |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring or it the public |
| | | * key needed for verification is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG signed, encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the output file is not writeable or |
| | | * if the input file is not readable. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @see Crypt_GPG_Signature |
| | | */ |
| | | private function _decryptAndVerify($data, $isFile, $outputFile) |
| | | { |
| | | if ($isFile) { |
| | | $input = @fopen($data, 'rb'); |
| | | if ($input === false) { |
| | | throw new Crypt_GPG_FileException('Could not open input ' . |
| | | 'file "' . $data . '" for decrypting and verifying.', 0, |
| | | $data); |
| | | } |
| | | } else { |
| | | $input = strval($data); |
| | | if ($input == '') { |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'No valid encrypted signed data found.', |
| | | Crypt_GPG::ERROR_NO_DATA); |
| | | } |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | $output = ''; |
| | | } else { |
| | | $output = @fopen($outputFile, 'wb'); |
| | | if ($output === false) { |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | throw new Crypt_GPG_FileException('Could not open output ' . |
| | | 'file "' . $outputFile . '" for storing decrypted data.', |
| | | 0, $outputFile); |
| | | } |
| | | } |
| | | |
| | | $verifyHandler = new Crypt_GPG_VerifyStatusHandler(); |
| | | |
| | | $decryptHandler = new Crypt_GPG_DecryptStatusHandler($this->engine, |
| | | $this->decryptKeys); |
| | | |
| | | $this->engine->reset(); |
| | | $this->engine->addStatusHandler(array($verifyHandler, 'handle')); |
| | | $this->engine->addStatusHandler(array($decryptHandler, 'handle')); |
| | | $this->engine->setInput($input); |
| | | $this->engine->setOutput($output); |
| | | $this->engine->setOperation('--decrypt'); |
| | | $this->engine->run(); |
| | | |
| | | if ($isFile) { |
| | | fclose($input); |
| | | } |
| | | |
| | | if ($outputFile !== null) { |
| | | fclose($output); |
| | | } |
| | | |
| | | $return = array( |
| | | 'data' => null, |
| | | 'signatures' => $verifyHandler->getSignatures() |
| | | ); |
| | | |
| | | // if there was any problem decrypting the data, the handler will |
| | | // deal with it here. |
| | | try { |
| | | $decryptHandler->throwException(); |
| | | } catch (Exception $e) { |
| | | if ($e instanceof Crypt_GPG_KeyNotFoundException) { |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Public key required for data verification not in ', |
| | | 'the keyring. Either no suitable private decryption key ' . |
| | | 'is in the keyring or the public key required for data ' . |
| | | 'verification is not in the keyring. Import a suitable ' . |
| | | 'key before trying to decrypt and verify this data.', |
| | | self::ERROR_KEY_NOT_FOUND, $this->engine->getErrorKeyId()); |
| | | } |
| | | |
| | | if ($e instanceof Crypt_GPG_NoDataException) { |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'Cannot decrypt and verify data. No PGP encrypted data ' . |
| | | 'was found in the provided data.', self::ERROR_NO_DATA); |
| | | } |
| | | |
| | | throw $e; |
| | | } |
| | | |
| | | if ($outputFile === null) { |
| | | $return['data'] = $output; |
| | | } |
| | | |
| | | return $return; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Crypt_GPG is a package to use GPG from PHP |
| | | * |
| | | * This file contains an object that handles GPG's status output for the |
| | | * decrypt operation. |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008-2009 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: DecryptStatusHandler.php 302814 2010-08-26 15:43:07Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | |
| | | /** |
| | | * Crypt_GPG base class |
| | | */ |
| | | require_once 'Crypt/GPG.php'; |
| | | |
| | | /** |
| | | * GPG exception classes |
| | | */ |
| | | require_once 'Crypt/GPG/Exceptions.php'; |
| | | |
| | | |
| | | /** |
| | | * Status line handler for the decrypt operation |
| | | * |
| | | * This class is used internally by Crypt_GPG and does not need be used |
| | | * directly. See the {@link Crypt_GPG} class for end-user API. |
| | | * |
| | | * This class is responsible for sending the passphrase commands when required |
| | | * by the {@link Crypt_GPG::decrypt()} method. See <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG distribution} for detailed |
| | | * information on GPG's status output for the decrypt operation. |
| | | * |
| | | * This class is also responsible for parsing error status and throwing a |
| | | * meaningful exception in the event that decryption fails. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | class Crypt_GPG_DecryptStatusHandler |
| | | { |
| | | // {{{ protected properties |
| | | |
| | | /** |
| | | * Keys used to decrypt |
| | | * |
| | | * The array is of the form: |
| | | * <code> |
| | | * array( |
| | | * $key_id => array( |
| | | * 'fingerprint' => $fingerprint, |
| | | * 'passphrase' => $passphrase |
| | | * ) |
| | | * ); |
| | | * </code> |
| | | * |
| | | * @var array |
| | | */ |
| | | protected $keys = array(); |
| | | |
| | | /** |
| | | * Engine used to which passphrases are passed |
| | | * |
| | | * @var Crypt_GPG_Engine |
| | | */ |
| | | protected $engine = null; |
| | | |
| | | /** |
| | | * The id of the current sub-key used for decryption |
| | | * |
| | | * @var string |
| | | */ |
| | | protected $currentSubKey = ''; |
| | | |
| | | /** |
| | | * Whether or not decryption succeeded |
| | | * |
| | | * If the message is only signed (compressed) and not encrypted, this is |
| | | * always true. If the message is encrypted, this flag is set to false |
| | | * until we know the decryption succeeded. |
| | | * |
| | | * @var boolean |
| | | */ |
| | | protected $decryptionOkay = true; |
| | | |
| | | /** |
| | | * Whether or not there was no data for decryption |
| | | * |
| | | * @var boolean |
| | | */ |
| | | protected $noData = false; |
| | | |
| | | /** |
| | | * Keys for which the passhprase is missing |
| | | * |
| | | * This contains primary user ids indexed by sub-key id and is used to |
| | | * create helpful exception messages. |
| | | * |
| | | * @var array |
| | | */ |
| | | protected $missingPassphrases = array(); |
| | | |
| | | /** |
| | | * Keys for which the passhprase is incorrect |
| | | * |
| | | * This contains primary user ids indexed by sub-key id and is used to |
| | | * create helpful exception messages. |
| | | * |
| | | * @var array |
| | | */ |
| | | protected $badPassphrases = array(); |
| | | |
| | | /** |
| | | * Keys that can be used to decrypt the data but are missing from the |
| | | * keychain |
| | | * |
| | | * This is an array with both the key and value being the sub-key id of |
| | | * the missing keys. |
| | | * |
| | | * @var array |
| | | */ |
| | | protected $missingKeys = array(); |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new decryption status handler |
| | | * |
| | | * @param Crypt_GPG_Engine $engine the GPG engine to which passphrases are |
| | | * passed. |
| | | * @param array $keys the decryption keys to use. |
| | | */ |
| | | public function __construct(Crypt_GPG_Engine $engine, array $keys) |
| | | { |
| | | $this->engine = $engine; |
| | | $this->keys = $keys; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ handle() |
| | | |
| | | /** |
| | | * Handles a status line |
| | | * |
| | | * @param string $line the status line to handle. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function handle($line) |
| | | { |
| | | $tokens = explode(' ', $line); |
| | | switch ($tokens[0]) { |
| | | case 'ENC_TO': |
| | | // Now we know the message is encrypted. Set flag to check if |
| | | // decryption succeeded. |
| | | $this->decryptionOkay = false; |
| | | |
| | | // this is the new key message |
| | | $this->currentSubKeyId = $tokens[1]; |
| | | break; |
| | | |
| | | case 'NEED_PASSPHRASE': |
| | | // send passphrase to the GPG engine |
| | | $subKeyId = $tokens[1]; |
| | | if (array_key_exists($subKeyId, $this->keys)) { |
| | | $passphrase = $this->keys[$subKeyId]['passphrase']; |
| | | $this->engine->sendCommand($passphrase); |
| | | } else { |
| | | $this->engine->sendCommand(''); |
| | | } |
| | | break; |
| | | |
| | | case 'USERID_HINT': |
| | | // remember the user id for pretty exception messages |
| | | $this->badPassphrases[$tokens[1]] |
| | | = implode(' ', array_splice($tokens, 2)); |
| | | |
| | | break; |
| | | |
| | | case 'GOOD_PASSPHRASE': |
| | | // if we got a good passphrase, remove the key from the list of |
| | | // bad passphrases. |
| | | unset($this->badPassphrases[$this->currentSubKeyId]); |
| | | break; |
| | | |
| | | case 'MISSING_PASSPHRASE': |
| | | $this->missingPassphrases[$this->currentSubKeyId] |
| | | = $this->currentSubKeyId; |
| | | |
| | | break; |
| | | |
| | | case 'NO_SECKEY': |
| | | // note: this message is also received if there are multiple |
| | | // recipients and a previous key had a correct passphrase. |
| | | $this->missingKeys[$tokens[1]] = $tokens[1]; |
| | | break; |
| | | |
| | | case 'NODATA': |
| | | $this->noData = true; |
| | | break; |
| | | |
| | | case 'DECRYPTION_OKAY': |
| | | // If the message is encrypted, this is the all-clear signal. |
| | | $this->decryptionOkay = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ throwException() |
| | | |
| | | /** |
| | | * Takes the final status of the decrypt operation and throws an |
| | | * appropriate exception |
| | | * |
| | | * If decryption was successful, no exception is thrown. |
| | | * |
| | | * @return void |
| | | * |
| | | * @throws Crypt_GPG_KeyNotFoundException if the private key needed to |
| | | * decrypt the data is not in the user's keyring. |
| | | * |
| | | * @throws Crypt_GPG_NoDataException if specified data does not contain |
| | | * GPG encrypted data. |
| | | * |
| | | * @throws Crypt_GPG_BadPassphraseException if a required passphrase is |
| | | * incorrect or if a required passphrase is not specified. See |
| | | * {@link Crypt_GPG::addDecryptKey()}. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <i>debug</i> option and file a bug report if these |
| | | * exceptions occur. |
| | | */ |
| | | public function throwException() |
| | | { |
| | | $code = Crypt_GPG::ERROR_NONE; |
| | | |
| | | if (!$this->decryptionOkay) { |
| | | if (count($this->badPassphrases) > 0) { |
| | | $code = Crypt_GPG::ERROR_BAD_PASSPHRASE; |
| | | } elseif (count($this->missingKeys) > 0) { |
| | | $code = Crypt_GPG::ERROR_KEY_NOT_FOUND; |
| | | } else { |
| | | $code = Crypt_GPG::ERROR_UNKNOWN; |
| | | } |
| | | } elseif ($this->noData) { |
| | | $code = Crypt_GPG::ERROR_NO_DATA; |
| | | } |
| | | |
| | | switch ($code) { |
| | | case Crypt_GPG::ERROR_NONE: |
| | | break; |
| | | |
| | | case Crypt_GPG::ERROR_KEY_NOT_FOUND: |
| | | if (count($this->missingKeys) > 0) { |
| | | $keyId = reset($this->missingKeys); |
| | | } else { |
| | | $keyId = ''; |
| | | } |
| | | throw new Crypt_GPG_KeyNotFoundException( |
| | | 'Cannot decrypt data. No suitable private key is in the ' . |
| | | 'keyring. Import a suitable private key before trying to ' . |
| | | 'decrypt this data.', $code, $keyId); |
| | | |
| | | case Crypt_GPG::ERROR_BAD_PASSPHRASE: |
| | | $badPassphrases = array_diff_key( |
| | | $this->badPassphrases, |
| | | $this->missingPassphrases |
| | | ); |
| | | |
| | | $missingPassphrases = array_intersect_key( |
| | | $this->badPassphrases, |
| | | $this->missingPassphrases |
| | | ); |
| | | |
| | | $message = 'Cannot decrypt data.'; |
| | | if (count($badPassphrases) > 0) { |
| | | $message = ' Incorrect passphrase provided for keys: "' . |
| | | implode('", "', $badPassphrases) . '".'; |
| | | } |
| | | if (count($missingPassphrases) > 0) { |
| | | $message = ' No passphrase provided for keys: "' . |
| | | implode('", "', $badPassphrases) . '".'; |
| | | } |
| | | |
| | | throw new Crypt_GPG_BadPassphraseException($message, $code, |
| | | $badPassphrases, $missingPassphrases); |
| | | |
| | | case Crypt_GPG::ERROR_NO_DATA: |
| | | throw new Crypt_GPG_NoDataException( |
| | | 'Cannot decrypt data. No PGP encrypted data was found in '. |
| | | 'the provided data.', $code); |
| | | |
| | | default: |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error decrypting data.', $code); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Crypt_GPG is a package to use GPG from PHP |
| | | * |
| | | * This file contains an engine that handles GPG subprocess control and I/O. |
| | | * PHP's process manipulation functions are used to handle the GPG subprocess. |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: Engine.php 302822 2010-08-26 17:30:57Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | |
| | | /** |
| | | * Crypt_GPG base class. |
| | | */ |
| | | require_once 'Crypt/GPG.php'; |
| | | |
| | | /** |
| | | * GPG exception classes. |
| | | */ |
| | | require_once 'Crypt/GPG/Exceptions.php'; |
| | | |
| | | /** |
| | | * Standard PEAR exception is used if GPG binary is not found. |
| | | */ |
| | | require_once 'PEAR/Exception.php'; |
| | | |
| | | // {{{ class Crypt_GPG_Engine |
| | | |
| | | /** |
| | | * Native PHP Crypt_GPG I/O engine |
| | | * |
| | | * This class is used internally by Crypt_GPG and does not need be used |
| | | * directly. See the {@link Crypt_GPG} class for end-user API. |
| | | * |
| | | * This engine uses PHP's native process control functions to directly control |
| | | * the GPG process. The GPG executable is required to be on the system. |
| | | * |
| | | * All data is passed to the GPG subprocess using file descriptors. This is the |
| | | * most secure method of passing data to the GPG subprocess. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | class Crypt_GPG_Engine |
| | | { |
| | | // {{{ constants |
| | | |
| | | /** |
| | | * Size of data chunks that are sent to and retrieved from the IPC pipes. |
| | | * |
| | | * PHP reads 8192 bytes. If this is set to less than 8192, PHP reads 8192 |
| | | * and buffers the rest so we might as well just read 8192. |
| | | * |
| | | * Using values other than 8192 also triggers PHP bugs. |
| | | * |
| | | * @see http://bugs.php.net/bug.php?id=35224 |
| | | */ |
| | | const CHUNK_SIZE = 8192; |
| | | |
| | | /** |
| | | * Standard input file descriptor. This is used to pass data to the GPG |
| | | * process. |
| | | */ |
| | | const FD_INPUT = 0; |
| | | |
| | | /** |
| | | * Standard output file descriptor. This is used to receive normal output |
| | | * from the GPG process. |
| | | */ |
| | | const FD_OUTPUT = 1; |
| | | |
| | | /** |
| | | * Standard output file descriptor. This is used to receive error output |
| | | * from the GPG process. |
| | | */ |
| | | const FD_ERROR = 2; |
| | | |
| | | /** |
| | | * GPG status output file descriptor. The status file descriptor outputs |
| | | * detailed information for many GPG commands. See the second section of |
| | | * the file <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG package} for a detailed |
| | | * description of GPG's status output. |
| | | */ |
| | | const FD_STATUS = 3; |
| | | |
| | | /** |
| | | * Command input file descriptor. This is used for methods requiring |
| | | * passphrases. |
| | | */ |
| | | const FD_COMMAND = 4; |
| | | |
| | | /** |
| | | * Extra message input file descriptor. This is used for passing signed |
| | | * data when verifying a detached signature. |
| | | */ |
| | | const FD_MESSAGE = 5; |
| | | |
| | | /** |
| | | * Minimum version of GnuPG that is supported. |
| | | */ |
| | | const MIN_VERSION = '1.0.2'; |
| | | |
| | | // }}} |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * Whether or not to use debugging mode |
| | | * |
| | | * When set to true, every GPG command is echoed before it is run. Sensitive |
| | | * data is always handled using pipes and is not specified as part of the |
| | | * command. As a result, sensitive data is never displayed when debug is |
| | | * enabled. Sensitive data includes private key data and passphrases. |
| | | * |
| | | * Debugging is off by default. |
| | | * |
| | | * @var boolean |
| | | * @see Crypt_GPG_Engine::__construct() |
| | | */ |
| | | private $_debug = false; |
| | | |
| | | /** |
| | | * Location of GPG binary |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::__construct() |
| | | * @see Crypt_GPG_Engine::_getBinary() |
| | | */ |
| | | private $_binary = ''; |
| | | |
| | | /** |
| | | * Directory containing the GPG key files |
| | | * |
| | | * This property only contains the path when the <i>homedir</i> option |
| | | * is specified in the constructor. |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::__construct() |
| | | */ |
| | | private $_homedir = ''; |
| | | |
| | | /** |
| | | * File path of the public keyring |
| | | * |
| | | * This property only contains the file path when the <i>public_keyring</i> |
| | | * option is specified in the constructor. |
| | | * |
| | | * If the specified file path starts with <kbd>~/</kbd>, the path is |
| | | * relative to the <i>homedir</i> if specified, otherwise to |
| | | * <kbd>~/.gnupg</kbd>. |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::__construct() |
| | | */ |
| | | private $_publicKeyring = ''; |
| | | |
| | | /** |
| | | * File path of the private (secret) keyring |
| | | * |
| | | * This property only contains the file path when the <i>private_keyring</i> |
| | | * option is specified in the constructor. |
| | | * |
| | | * If the specified file path starts with <kbd>~/</kbd>, the path is |
| | | * relative to the <i>homedir</i> if specified, otherwise to |
| | | * <kbd>~/.gnupg</kbd>. |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::__construct() |
| | | */ |
| | | private $_privateKeyring = ''; |
| | | |
| | | /** |
| | | * File path of the trust database |
| | | * |
| | | * This property only contains the file path when the <i>trust_db</i> |
| | | * option is specified in the constructor. |
| | | * |
| | | * If the specified file path starts with <kbd>~/</kbd>, the path is |
| | | * relative to the <i>homedir</i> if specified, otherwise to |
| | | * <kbd>~/.gnupg</kbd>. |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::__construct() |
| | | */ |
| | | private $_trustDb = ''; |
| | | |
| | | /** |
| | | * Array of pipes used for communication with the GPG binary |
| | | * |
| | | * This is an array of file descriptor resources. |
| | | * |
| | | * @var array |
| | | */ |
| | | private $_pipes = array(); |
| | | |
| | | /** |
| | | * Array of currently opened pipes |
| | | * |
| | | * This array is used to keep track of remaining opened pipes so they can |
| | | * be closed when the GPG subprocess is finished. This array is a subset of |
| | | * the {@link Crypt_GPG_Engine::$_pipes} array and contains opened file |
| | | * descriptor resources. |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG_Engine::_closePipe() |
| | | */ |
| | | private $_openPipes = array(); |
| | | |
| | | /** |
| | | * A handle for the GPG process |
| | | * |
| | | * @var resource |
| | | */ |
| | | private $_process = null; |
| | | |
| | | /** |
| | | * Whether or not the operating system is Darwin (OS X) |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_isDarwin = false; |
| | | |
| | | /** |
| | | * Commands to be sent to GPG's command input stream |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::sendCommand() |
| | | */ |
| | | private $_commandBuffer = ''; |
| | | |
| | | /** |
| | | * Array of status line handlers |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG_Engine::addStatusHandler() |
| | | */ |
| | | private $_statusHandlers = array(); |
| | | |
| | | /** |
| | | * Array of error line handlers |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG_Engine::addErrorHandler() |
| | | */ |
| | | private $_errorHandlers = array(); |
| | | |
| | | /** |
| | | * The error code of the current operation |
| | | * |
| | | * @var integer |
| | | * @see Crypt_GPG_Engine::getErrorCode() |
| | | */ |
| | | private $_errorCode = Crypt_GPG::ERROR_NONE; |
| | | |
| | | /** |
| | | * File related to the error code of the current operation |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::getErrorFilename() |
| | | */ |
| | | private $_errorFilename = ''; |
| | | |
| | | /** |
| | | * Key id related to the error code of the current operation |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::getErrorKeyId() |
| | | */ |
| | | private $_errorkeyId = ''; |
| | | |
| | | /** |
| | | * The number of currently needed passphrases |
| | | * |
| | | * If this is not zero when the GPG command is completed, the error code is |
| | | * set to {@link Crypt_GPG::ERROR_MISSING_PASSPHRASE}. |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_needPassphrase = 0; |
| | | |
| | | /** |
| | | * The input source |
| | | * |
| | | * This is data to send to GPG. Either a string or a stream resource. |
| | | * |
| | | * @var string|resource |
| | | * @see Crypt_GPG_Engine::setInput() |
| | | */ |
| | | private $_input = null; |
| | | |
| | | /** |
| | | * The extra message input source |
| | | * |
| | | * Either a string or a stream resource. |
| | | * |
| | | * @var string|resource |
| | | * @see Crypt_GPG_Engine::setMessage() |
| | | */ |
| | | private $_message = null; |
| | | |
| | | /** |
| | | * The output location |
| | | * |
| | | * This is where the output from GPG is sent. Either a string or a stream |
| | | * resource. |
| | | * |
| | | * @var string|resource |
| | | * @see Crypt_GPG_Engine::setOutput() |
| | | */ |
| | | private $_output = ''; |
| | | |
| | | /** |
| | | * The GPG operation to execute |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::setOperation() |
| | | */ |
| | | private $_operation; |
| | | |
| | | /** |
| | | * Arguments for the current operation |
| | | * |
| | | * @var array |
| | | * @see Crypt_GPG_Engine::setOperation() |
| | | */ |
| | | private $_arguments = array(); |
| | | |
| | | /** |
| | | * The version number of the GPG binary |
| | | * |
| | | * @var string |
| | | * @see Crypt_GPG_Engine::getVersion() |
| | | */ |
| | | private $_version = ''; |
| | | |
| | | /** |
| | | * Cached value indicating whether or not mbstring function overloading is |
| | | * on for strlen |
| | | * |
| | | * This is cached for optimal performance inside the I/O loop. |
| | | * |
| | | * @var boolean |
| | | * @see Crypt_GPG_Engine::_byteLength() |
| | | * @see Crypt_GPG_Engine::_byteSubstring() |
| | | */ |
| | | private static $_mbStringOverload = null; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new GPG engine |
| | | * |
| | | * Available options are: |
| | | * |
| | | * - <kbd>string homedir</kbd> - the directory where the GPG |
| | | * keyring files are stored. If not |
| | | * specified, Crypt_GPG uses the |
| | | * default of <kbd>~/.gnupg</kbd>. |
| | | * - <kbd>string publicKeyring</kbd> - the file path of the public |
| | | * keyring. Use this if the public |
| | | * keyring is not in the homedir, or |
| | | * if the keyring is in a directory |
| | | * not writable by the process |
| | | * invoking GPG (like Apache). Then |
| | | * you can specify the path to the |
| | | * keyring with this option |
| | | * (/foo/bar/pubring.gpg), and specify |
| | | * a writable directory (like /tmp) |
| | | * using the <i>homedir</i> option. |
| | | * - <kbd>string privateKeyring</kbd> - the file path of the private |
| | | * keyring. Use this if the private |
| | | * keyring is not in the homedir, or |
| | | * if the keyring is in a directory |
| | | * not writable by the process |
| | | * invoking GPG (like Apache). Then |
| | | * you can specify the path to the |
| | | * keyring with this option |
| | | * (/foo/bar/secring.gpg), and specify |
| | | * a writable directory (like /tmp) |
| | | * using the <i>homedir</i> option. |
| | | * - <kbd>string trustDb</kbd> - the file path of the web-of-trust |
| | | * database. Use this if the trust |
| | | * database is not in the homedir, or |
| | | * if the database is in a directory |
| | | * not writable by the process |
| | | * invoking GPG (like Apache). Then |
| | | * you can specify the path to the |
| | | * trust database with this option |
| | | * (/foo/bar/trustdb.gpg), and specify |
| | | * a writable directory (like /tmp) |
| | | * using the <i>homedir</i> option. |
| | | * - <kbd>string binary</kbd> - the location of the GPG binary. If |
| | | * not specified, the driver attempts |
| | | * to auto-detect the GPG binary |
| | | * location using a list of known |
| | | * default locations for the current |
| | | * operating system. The option |
| | | * <kbd>gpgBinary</kbd> is a |
| | | * deprecated alias for this option. |
| | | * - <kbd>boolean debug</kbd> - whether or not to use debug mode. |
| | | * When debug mode is on, all |
| | | * communication to and from the GPG |
| | | * subprocess is logged. This can be |
| | | * useful to diagnose errors when |
| | | * using Crypt_GPG. |
| | | * |
| | | * @param array $options optional. An array of options used to create the |
| | | * GPG object. All options are optional and are |
| | | * represented as key-value pairs. |
| | | * |
| | | * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist |
| | | * and cannot be created. This can happen if <kbd>homedir</kbd> is |
| | | * not specified, Crypt_GPG is run as the web user, and the web |
| | | * user has no home directory. This exception is also thrown if any |
| | | * of the options <kbd>publicKeyring</kbd>, |
| | | * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are |
| | | * specified but the files do not exist or are are not readable. |
| | | * This can happen if the user running the Crypt_GPG process (for |
| | | * example, the Apache user) does not have permission to read the |
| | | * files. |
| | | * |
| | | * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or |
| | | * if no <kbd>binary</kbd> is provided and no suitable binary could |
| | | * be found. |
| | | */ |
| | | public function __construct(array $options = array()) |
| | | { |
| | | $this->_isDarwin = (strncmp(strtoupper(PHP_OS), 'DARWIN', 6) === 0); |
| | | |
| | | // populate mbstring overloading cache if not set |
| | | if (self::$_mbStringOverload === null) { |
| | | self::$_mbStringOverload = (extension_loaded('mbstring') |
| | | && (ini_get('mbstring.func_overload') & 0x02) === 0x02); |
| | | } |
| | | |
| | | // get homedir |
| | | if (array_key_exists('homedir', $options)) { |
| | | $this->_homedir = (string)$options['homedir']; |
| | | } else { |
| | | // note: this requires the package OS dep exclude 'windows' |
| | | $info = posix_getpwuid(posix_getuid()); |
| | | $this->_homedir = $info['dir'].'/.gnupg'; |
| | | } |
| | | |
| | | // attempt to create homedir if it does not exist |
| | | if (!is_dir($this->_homedir)) { |
| | | if (@mkdir($this->_homedir, 0777, true)) { |
| | | // Set permissions on homedir. Parent directories are created |
| | | // with 0777, homedir is set to 0700. |
| | | chmod($this->_homedir, 0700); |
| | | } else { |
| | | throw new Crypt_GPG_FileException('The \'homedir\' "' . |
| | | $this->_homedir . '" is not readable or does not exist '. |
| | | 'and cannot be created. This can happen if \'homedir\' '. |
| | | 'is not specified in the Crypt_GPG options, Crypt_GPG is '. |
| | | 'run as the web user, and the web user has no home '. |
| | | 'directory.', |
| | | 0, $this->_homedir); |
| | | } |
| | | } |
| | | |
| | | // get binary |
| | | if (array_key_exists('binary', $options)) { |
| | | $this->_binary = (string)$options['binary']; |
| | | } elseif (array_key_exists('gpgBinary', $options)) { |
| | | // deprecated alias |
| | | $this->_binary = (string)$options['gpgBinary']; |
| | | } else { |
| | | $this->_binary = $this->_getBinary(); |
| | | } |
| | | |
| | | if ($this->_binary == '' || !is_executable($this->_binary)) { |
| | | throw new PEAR_Exception('GPG binary not found. If you are sure '. |
| | | 'the GPG binary is installed, please specify the location of '. |
| | | 'the GPG binary using the \'binary\' driver option.'); |
| | | } |
| | | |
| | | /* |
| | | * Note: |
| | | * |
| | | * Normally, GnuPG expects keyrings to be in the homedir and expects |
| | | * to be able to write temporary files in the homedir. Sometimes, |
| | | * keyrings are not in the homedir, or location of the keyrings does |
| | | * not allow writing temporary files. In this case, the <i>homedir</i> |
| | | * option by itself is not enough to specify the keyrings because GnuPG |
| | | * can not write required temporary files. Additional options are |
| | | * provided so you can specify the location of the keyrings separately |
| | | * from the homedir. |
| | | */ |
| | | |
| | | // get public keyring |
| | | if (array_key_exists('publicKeyring', $options)) { |
| | | $this->_publicKeyring = (string)$options['publicKeyring']; |
| | | if (!is_readable($this->_publicKeyring)) { |
| | | throw new Crypt_GPG_FileException('The \'publicKeyring\' "' . |
| | | $this->_publicKeyring . '" does not exist or is ' . |
| | | 'not readable. Check the location and ensure the file ' . |
| | | 'permissions are correct.', 0, $this->_publicKeyring); |
| | | } |
| | | } |
| | | |
| | | // get private keyring |
| | | if (array_key_exists('privateKeyring', $options)) { |
| | | $this->_privateKeyring = (string)$options['privateKeyring']; |
| | | if (!is_readable($this->_privateKeyring)) { |
| | | throw new Crypt_GPG_FileException('The \'privateKeyring\' "' . |
| | | $this->_privateKeyring . '" does not exist or is ' . |
| | | 'not readable. Check the location and ensure the file ' . |
| | | 'permissions are correct.', 0, $this->_privateKeyring); |
| | | } |
| | | } |
| | | |
| | | // get trust database |
| | | if (array_key_exists('trustDb', $options)) { |
| | | $this->_trustDb = (string)$options['trustDb']; |
| | | if (!is_readable($this->_trustDb)) { |
| | | throw new Crypt_GPG_FileException('The \'trustDb\' "' . |
| | | $this->_trustDb . '" does not exist or is not readable. ' . |
| | | 'Check the location and ensure the file permissions are ' . |
| | | 'correct.', 0, $this->_trustDb); |
| | | } |
| | | } |
| | | |
| | | if (array_key_exists('debug', $options)) { |
| | | $this->_debug = (boolean)$options['debug']; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ __destruct() |
| | | |
| | | /** |
| | | * Closes open GPG subprocesses when this object is destroyed |
| | | * |
| | | * Subprocesses should never be left open by this class unless there is |
| | | * an unknown error and unexpected script termination occurs. |
| | | */ |
| | | public function __destruct() |
| | | { |
| | | $this->_closeSubprocess(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addErrorHandler() |
| | | |
| | | /** |
| | | * Adds an error handler method |
| | | * |
| | | * The method is run every time a new error line is received from the GPG |
| | | * subprocess. The handler method must accept the error line to be handled |
| | | * as its first parameter. |
| | | * |
| | | * @param callback $callback the callback method to use. |
| | | * @param array $args optional. Additional arguments to pass as |
| | | * parameters to the callback method. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function addErrorHandler($callback, array $args = array()) |
| | | { |
| | | $this->_errorHandlers[] = array( |
| | | 'callback' => $callback, |
| | | 'args' => $args |
| | | ); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addStatusHandler() |
| | | |
| | | /** |
| | | * Adds a status handler method |
| | | * |
| | | * The method is run every time a new status line is received from the |
| | | * GPG subprocess. The handler method must accept the status line to be |
| | | * handled as its first parameter. |
| | | * |
| | | * @param callback $callback the callback method to use. |
| | | * @param array $args optional. Additional arguments to pass as |
| | | * parameters to the callback method. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function addStatusHandler($callback, array $args = array()) |
| | | { |
| | | $this->_statusHandlers[] = array( |
| | | 'callback' => $callback, |
| | | 'args' => $args |
| | | ); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ sendCommand() |
| | | |
| | | /** |
| | | * Sends a command to the GPG subprocess over the command file-descriptor |
| | | * pipe |
| | | * |
| | | * @param string $command the command to send. |
| | | * |
| | | * @return void |
| | | * |
| | | * @sensitive $command |
| | | */ |
| | | public function sendCommand($command) |
| | | { |
| | | if (array_key_exists(self::FD_COMMAND, $this->_openPipes)) { |
| | | $this->_commandBuffer .= $command . PHP_EOL; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ reset() |
| | | |
| | | /** |
| | | * Resets the GPG engine, preparing it for a new operation |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG_Engine::run() |
| | | * @see Crypt_GPG_Engine::setOperation() |
| | | */ |
| | | public function reset() |
| | | { |
| | | $this->_operation = ''; |
| | | $this->_arguments = array(); |
| | | $this->_input = null; |
| | | $this->_message = null; |
| | | $this->_output = ''; |
| | | $this->_errorCode = Crypt_GPG::ERROR_NONE; |
| | | $this->_needPassphrase = 0; |
| | | $this->_commandBuffer = ''; |
| | | |
| | | $this->_statusHandlers = array(); |
| | | $this->_errorHandlers = array(); |
| | | |
| | | $this->addStatusHandler(array($this, '_handleErrorStatus')); |
| | | $this->addErrorHandler(array($this, '_handleErrorError')); |
| | | |
| | | if ($this->_debug) { |
| | | $this->addStatusHandler(array($this, '_handleDebugStatus')); |
| | | $this->addErrorHandler(array($this, '_handleDebugError')); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ run() |
| | | |
| | | /** |
| | | * Runs the current GPG operation |
| | | * |
| | | * This creates and manages the GPG subprocess. |
| | | * |
| | | * The operation must be set with {@link Crypt_GPG_Engine::setOperation()} |
| | | * before this method is called. |
| | | * |
| | | * @return void |
| | | * |
| | | * @throws Crypt_GPG_InvalidOperationException if no operation is specified. |
| | | * |
| | | * @see Crypt_GPG_Engine::reset() |
| | | * @see Crypt_GPG_Engine::setOperation() |
| | | */ |
| | | public function run() |
| | | { |
| | | if ($this->_operation === '') { |
| | | throw new Crypt_GPG_InvalidOperationException('No GPG operation ' . |
| | | 'specified. Use Crypt_GPG_Engine::setOperation() before ' . |
| | | 'calling Crypt_GPG_Engine::run().'); |
| | | } |
| | | |
| | | $this->_openSubprocess(); |
| | | $this->_process(); |
| | | $this->_closeSubprocess(); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getErrorCode() |
| | | |
| | | /** |
| | | * Gets the error code of the last executed operation |
| | | * |
| | | * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has |
| | | * been executed. |
| | | * |
| | | * @return integer the error code of the last executed operation. |
| | | */ |
| | | public function getErrorCode() |
| | | { |
| | | return $this->_errorCode; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getErrorFilename() |
| | | |
| | | /** |
| | | * Gets the file related to the error code of the last executed operation |
| | | * |
| | | * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has |
| | | * been executed. If there is no file related to the error, an empty string |
| | | * is returned. |
| | | * |
| | | * @return string the file related to the error code of the last executed |
| | | * operation. |
| | | */ |
| | | public function getErrorFilename() |
| | | { |
| | | return $this->_errorFilename; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getErrorKeyId() |
| | | |
| | | /** |
| | | * Gets the key id related to the error code of the last executed operation |
| | | * |
| | | * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has |
| | | * been executed. If there is no key id related to the error, an empty |
| | | * string is returned. |
| | | * |
| | | * @return string the key id related to the error code of the last executed |
| | | * operation. |
| | | */ |
| | | public function getErrorKeyId() |
| | | { |
| | | return $this->_errorKeyId; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setInput() |
| | | |
| | | /** |
| | | * Sets the input source for the current GPG operation |
| | | * |
| | | * @param string|resource &$input either a reference to the string |
| | | * containing the input data or an open |
| | | * stream resource containing the input |
| | | * data. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function setInput(&$input) |
| | | { |
| | | $this->_input =& $input; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setMessage() |
| | | |
| | | /** |
| | | * Sets the message source for the current GPG operation |
| | | * |
| | | * Detached signature data should be specified here. |
| | | * |
| | | * @param string|resource &$message either a reference to the string |
| | | * containing the message data or an open |
| | | * stream resource containing the message |
| | | * data. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function setMessage(&$message) |
| | | { |
| | | $this->_message =& $message; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setOutput() |
| | | |
| | | /** |
| | | * Sets the output destination for the current GPG operation |
| | | * |
| | | * @param string|resource &$output either a reference to the string in |
| | | * which to store GPG output or an open |
| | | * stream resource to which the output data |
| | | * should be written. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function setOutput(&$output) |
| | | { |
| | | $this->_output =& $output; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setOperation() |
| | | |
| | | /** |
| | | * Sets the operation to perform |
| | | * |
| | | * @param string $operation the operation to perform. This should be one |
| | | * of GPG's operations. For example, |
| | | * <kbd>--encrypt</kbd>, <kbd>--decrypt</kbd>, |
| | | * <kbd>--sign</kbd>, etc. |
| | | * @param array $arguments optional. Additional arguments for the GPG |
| | | * subprocess. See the GPG manual for specific |
| | | * values. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG_Engine::reset() |
| | | * @see Crypt_GPG_Engine::run() |
| | | */ |
| | | public function setOperation($operation, array $arguments = array()) |
| | | { |
| | | $this->_operation = $operation; |
| | | $this->_arguments = $arguments; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getVersion() |
| | | |
| | | /** |
| | | * Gets the version of the GnuPG binary |
| | | * |
| | | * @return string a version number string containing the version of GnuPG |
| | | * being used. This value is suitable to use with PHP's |
| | | * version_compare() function. |
| | | * |
| | | * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. |
| | | * Use the <kbd>debug</kbd> option and file a bug report if these |
| | | * exceptions occur. |
| | | * |
| | | * @throws Crypt_GPG_UnsupportedException if the provided binary is not |
| | | * GnuPG or if the GnuPG version is less than 1.0.2. |
| | | */ |
| | | public function getVersion() |
| | | { |
| | | if ($this->_version == '') { |
| | | |
| | | $options = array( |
| | | 'homedir' => $this->_homedir, |
| | | 'binary' => $this->_binary, |
| | | 'debug' => $this->_debug |
| | | ); |
| | | |
| | | $engine = new self($options); |
| | | $info = ''; |
| | | |
| | | // Set a garbage version so we do not end up looking up the version |
| | | // recursively. |
| | | $engine->_version = '1.0.0'; |
| | | |
| | | $engine->reset(); |
| | | $engine->setOutput($info); |
| | | $engine->setOperation('--version'); |
| | | $engine->run(); |
| | | |
| | | $code = $this->getErrorCode(); |
| | | |
| | | if ($code !== Crypt_GPG::ERROR_NONE) { |
| | | throw new Crypt_GPG_Exception( |
| | | 'Unknown error getting GnuPG version information. Please ' . |
| | | 'use the \'debug\' option when creating the Crypt_GPG ' . |
| | | 'object, and file a bug report at ' . Crypt_GPG::BUG_URI, |
| | | $code); |
| | | } |
| | | |
| | | $matches = array(); |
| | | $expression = '/gpg \(GnuPG\) (\S+)/'; |
| | | |
| | | if (preg_match($expression, $info, $matches) === 1) { |
| | | $this->_version = $matches[1]; |
| | | } else { |
| | | throw new Crypt_GPG_Exception( |
| | | 'No GnuPG version information provided by the binary "' . |
| | | $this->_binary . '". Are you sure it is GnuPG?'); |
| | | } |
| | | |
| | | if (version_compare($this->_version, self::MIN_VERSION, 'lt')) { |
| | | throw new Crypt_GPG_Exception( |
| | | 'The version of GnuPG being used (' . $this->_version . |
| | | ') is not supported by Crypt_GPG. The minimum version ' . |
| | | 'required by Crypt_GPG is ' . self::MIN_VERSION); |
| | | } |
| | | } |
| | | |
| | | |
| | | return $this->_version; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _handleErrorStatus() |
| | | |
| | | /** |
| | | * Handles error values in the status output from GPG |
| | | * |
| | | * This method is responsible for setting the |
| | | * {@link Crypt_GPG_Engine::$_errorCode}. See <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG distribution} for detailed |
| | | * information on GPG's status output. |
| | | * |
| | | * @param string $line the status line to handle. |
| | | * |
| | | * @return void |
| | | */ |
| | | private function _handleErrorStatus($line) |
| | | { |
| | | $tokens = explode(' ', $line); |
| | | switch ($tokens[0]) { |
| | | case 'BAD_PASSPHRASE': |
| | | $this->_errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE; |
| | | break; |
| | | |
| | | case 'MISSING_PASSPHRASE': |
| | | $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE; |
| | | break; |
| | | |
| | | case 'NODATA': |
| | | $this->_errorCode = Crypt_GPG::ERROR_NO_DATA; |
| | | break; |
| | | |
| | | case 'DELETE_PROBLEM': |
| | | if ($tokens[1] == '1') { |
| | | $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; |
| | | break; |
| | | } elseif ($tokens[1] == '2') { |
| | | $this->_errorCode = Crypt_GPG::ERROR_DELETE_PRIVATE_KEY; |
| | | break; |
| | | } |
| | | break; |
| | | |
| | | case 'IMPORT_RES': |
| | | if ($tokens[12] > 0) { |
| | | $this->_errorCode = Crypt_GPG::ERROR_DUPLICATE_KEY; |
| | | } |
| | | break; |
| | | |
| | | case 'NO_PUBKEY': |
| | | case 'NO_SECKEY': |
| | | $this->_errorKeyId = $tokens[1]; |
| | | $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; |
| | | break; |
| | | |
| | | case 'NEED_PASSPHRASE': |
| | | $this->_needPassphrase++; |
| | | break; |
| | | |
| | | case 'GOOD_PASSPHRASE': |
| | | $this->_needPassphrase--; |
| | | break; |
| | | |
| | | case 'EXPSIG': |
| | | case 'EXPKEYSIG': |
| | | case 'REVKEYSIG': |
| | | case 'BADSIG': |
| | | $this->_errorCode = Crypt_GPG::ERROR_BAD_SIGNATURE; |
| | | break; |
| | | |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _handleErrorError() |
| | | |
| | | /** |
| | | * Handles error values in the error output from GPG |
| | | * |
| | | * This method is responsible for setting the |
| | | * {@link Crypt_GPG_Engine::$_errorCode}. |
| | | * |
| | | * @param string $line the error line to handle. |
| | | * |
| | | * @return void |
| | | */ |
| | | private function _handleErrorError($line) |
| | | { |
| | | if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { |
| | | $pattern = '/no valid OpenPGP data found/'; |
| | | if (preg_match($pattern, $line) === 1) { |
| | | $this->_errorCode = Crypt_GPG::ERROR_NO_DATA; |
| | | } |
| | | } |
| | | |
| | | if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { |
| | | $pattern = '/No secret key|secret key not available/'; |
| | | if (preg_match($pattern, $line) === 1) { |
| | | $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; |
| | | } |
| | | } |
| | | |
| | | if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { |
| | | $pattern = '/No public key|public key not found/'; |
| | | if (preg_match($pattern, $line) === 1) { |
| | | $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; |
| | | } |
| | | } |
| | | |
| | | if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { |
| | | $matches = array(); |
| | | $pattern = '/can\'t (?:access|open) `(.*?)\'/'; |
| | | if (preg_match($pattern, $line, $matches) === 1) { |
| | | $this->_errorFilename = $matches[1]; |
| | | $this->_errorCode = Crypt_GPG::ERROR_FILE_PERMISSIONS; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _handleDebugStatus() |
| | | |
| | | /** |
| | | * Displays debug output for status lines |
| | | * |
| | | * @param string $line the status line to handle. |
| | | * |
| | | * @return void |
| | | */ |
| | | private function _handleDebugStatus($line) |
| | | { |
| | | $this->_debug('STATUS: ' . $line); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _handleDebugError() |
| | | |
| | | /** |
| | | * Displays debug output for error lines |
| | | * |
| | | * @param string $line the error line to handle. |
| | | * |
| | | * @return void |
| | | */ |
| | | private function _handleDebugError($line) |
| | | { |
| | | $this->_debug('ERROR: ' . $line); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _process() |
| | | |
| | | /** |
| | | * Performs internal streaming operations for the subprocess using either |
| | | * strings or streams as input / output points |
| | | * |
| | | * This is the main I/O loop for streaming to and from the GPG subprocess. |
| | | * |
| | | * The implementation of this method is verbose mainly for performance |
| | | * reasons. Adding streams to a lookup array and looping the array inside |
| | | * the main I/O loop would be siginficantly slower for large streams. |
| | | * |
| | | * @return void |
| | | * |
| | | * @throws Crypt_GPG_Exception if there is an error selecting streams for |
| | | * reading or writing. If this occurs, please file a bug report at |
| | | * http://pear.php.net/bugs/report.php?package=Crypt_GPG. |
| | | */ |
| | | private function _process() |
| | | { |
| | | $this->_debug('BEGIN PROCESSING'); |
| | | |
| | | $this->_commandBuffer = ''; // buffers input to GPG |
| | | $messageBuffer = ''; // buffers input to GPG |
| | | $inputBuffer = ''; // buffers input to GPG |
| | | $outputBuffer = ''; // buffers output from GPG |
| | | $statusBuffer = ''; // buffers output from GPG |
| | | $errorBuffer = ''; // buffers output from GPG |
| | | $inputComplete = false; // input stream is completely buffered |
| | | $messageComplete = false; // message stream is completely buffered |
| | | |
| | | if (is_string($this->_input)) { |
| | | $inputBuffer = $this->_input; |
| | | $inputComplete = true; |
| | | } |
| | | |
| | | if (is_string($this->_message)) { |
| | | $messageBuffer = $this->_message; |
| | | $messageComplete = true; |
| | | } |
| | | |
| | | if (is_string($this->_output)) { |
| | | $outputBuffer =& $this->_output; |
| | | } |
| | | |
| | | // convenience variables |
| | | $fdInput = $this->_pipes[self::FD_INPUT]; |
| | | $fdOutput = $this->_pipes[self::FD_OUTPUT]; |
| | | $fdError = $this->_pipes[self::FD_ERROR]; |
| | | $fdStatus = $this->_pipes[self::FD_STATUS]; |
| | | $fdCommand = $this->_pipes[self::FD_COMMAND]; |
| | | $fdMessage = $this->_pipes[self::FD_MESSAGE]; |
| | | |
| | | while (true) { |
| | | |
| | | $inputStreams = array(); |
| | | $outputStreams = array(); |
| | | $exceptionStreams = array(); |
| | | |
| | | // set up input streams |
| | | if (is_resource($this->_input) && !$inputComplete) { |
| | | if (feof($this->_input)) { |
| | | $inputComplete = true; |
| | | } else { |
| | | $inputStreams[] = $this->_input; |
| | | } |
| | | } |
| | | |
| | | // close GPG input pipe if there is no more data |
| | | if ($inputBuffer == '' && $inputComplete) { |
| | | $this->_debug('=> closing GPG input pipe'); |
| | | $this->_closePipe(self::FD_INPUT); |
| | | } |
| | | |
| | | if (is_resource($this->_message) && !$messageComplete) { |
| | | if (feof($this->_message)) { |
| | | $messageComplete = true; |
| | | } else { |
| | | $inputStreams[] = $this->_message; |
| | | } |
| | | } |
| | | |
| | | // close GPG message pipe if there is no more data |
| | | if ($messageBuffer == '' && $messageComplete) { |
| | | $this->_debug('=> closing GPG message pipe'); |
| | | $this->_closePipe(self::FD_MESSAGE); |
| | | } |
| | | |
| | | if (!feof($fdOutput)) { |
| | | $inputStreams[] = $fdOutput; |
| | | } |
| | | |
| | | if (!feof($fdStatus)) { |
| | | $inputStreams[] = $fdStatus; |
| | | } |
| | | |
| | | if (!feof($fdError)) { |
| | | $inputStreams[] = $fdError; |
| | | } |
| | | |
| | | // set up output streams |
| | | if ($outputBuffer != '' && is_resource($this->_output)) { |
| | | $outputStreams[] = $this->_output; |
| | | } |
| | | |
| | | if ($this->_commandBuffer != '') { |
| | | $outputStreams[] = $fdCommand; |
| | | } |
| | | |
| | | if ($messageBuffer != '') { |
| | | $outputStreams[] = $fdMessage; |
| | | } |
| | | |
| | | if ($inputBuffer != '') { |
| | | $outputStreams[] = $fdInput; |
| | | } |
| | | |
| | | // no streams left to read or write, we're all done |
| | | if (count($inputStreams) === 0 && count($outputStreams) === 0) { |
| | | break; |
| | | } |
| | | |
| | | $this->_debug('selecting streams'); |
| | | |
| | | $ready = stream_select( |
| | | $inputStreams, |
| | | $outputStreams, |
| | | $exceptionStreams, |
| | | null |
| | | ); |
| | | |
| | | $this->_debug('=> got ' . $ready); |
| | | |
| | | if ($ready === false) { |
| | | throw new Crypt_GPG_Exception( |
| | | 'Error selecting stream for communication with GPG ' . |
| | | 'subprocess. Please file a bug report at: ' . |
| | | 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'); |
| | | } |
| | | |
| | | if ($ready === 0) { |
| | | throw new Crypt_GPG_Exception( |
| | | 'stream_select() returned 0. This can not happen! Please ' . |
| | | 'file a bug report at: ' . |
| | | 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'); |
| | | } |
| | | |
| | | // write input (to GPG) |
| | | if (in_array($fdInput, $outputStreams)) { |
| | | $this->_debug('GPG is ready for input'); |
| | | |
| | | $chunk = self::_byteSubstring( |
| | | $inputBuffer, |
| | | 0, |
| | | self::CHUNK_SIZE |
| | | ); |
| | | |
| | | $length = self::_byteLength($chunk); |
| | | |
| | | $this->_debug( |
| | | '=> about to write ' . $length . ' bytes to GPG input' |
| | | ); |
| | | |
| | | $length = fwrite($fdInput, $chunk, $length); |
| | | |
| | | $this->_debug('=> wrote ' . $length . ' bytes'); |
| | | |
| | | $inputBuffer = self::_byteSubstring( |
| | | $inputBuffer, |
| | | $length |
| | | ); |
| | | } |
| | | |
| | | // read input (from PHP stream) |
| | | if (in_array($this->_input, $inputStreams)) { |
| | | $this->_debug('input stream is ready for reading'); |
| | | $this->_debug( |
| | | '=> about to read ' . self::CHUNK_SIZE . |
| | | ' bytes from input stream' |
| | | ); |
| | | |
| | | $chunk = fread($this->_input, self::CHUNK_SIZE); |
| | | $length = self::_byteLength($chunk); |
| | | $inputBuffer .= $chunk; |
| | | |
| | | $this->_debug('=> read ' . $length . ' bytes'); |
| | | } |
| | | |
| | | // write message (to GPG) |
| | | if (in_array($fdMessage, $outputStreams)) { |
| | | $this->_debug('GPG is ready for message data'); |
| | | |
| | | $chunk = self::_byteSubstring( |
| | | $messageBuffer, |
| | | 0, |
| | | self::CHUNK_SIZE |
| | | ); |
| | | |
| | | $length = self::_byteLength($chunk); |
| | | |
| | | $this->_debug( |
| | | '=> about to write ' . $length . ' bytes to GPG message' |
| | | ); |
| | | |
| | | $length = fwrite($fdMessage, $chunk, $length); |
| | | $this->_debug('=> wrote ' . $length . ' bytes'); |
| | | |
| | | $messageBuffer = self::_byteSubstring($messageBuffer, $length); |
| | | } |
| | | |
| | | // read message (from PHP stream) |
| | | if (in_array($this->_message, $inputStreams)) { |
| | | $this->_debug('message stream is ready for reading'); |
| | | $this->_debug( |
| | | '=> about to read ' . self::CHUNK_SIZE . |
| | | ' bytes from message stream' |
| | | ); |
| | | |
| | | $chunk = fread($this->_message, self::CHUNK_SIZE); |
| | | $length = self::_byteLength($chunk); |
| | | $messageBuffer .= $chunk; |
| | | |
| | | $this->_debug('=> read ' . $length . ' bytes'); |
| | | } |
| | | |
| | | // read output (from GPG) |
| | | if (in_array($fdOutput, $inputStreams)) { |
| | | $this->_debug('GPG output stream ready for reading'); |
| | | $this->_debug( |
| | | '=> about to read ' . self::CHUNK_SIZE . |
| | | ' bytes from GPG output' |
| | | ); |
| | | |
| | | $chunk = fread($fdOutput, self::CHUNK_SIZE); |
| | | $length = self::_byteLength($chunk); |
| | | $outputBuffer .= $chunk; |
| | | |
| | | $this->_debug('=> read ' . $length . ' bytes'); |
| | | } |
| | | |
| | | // write output (to PHP stream) |
| | | if (in_array($this->_output, $outputStreams)) { |
| | | $this->_debug('output stream is ready for data'); |
| | | |
| | | $chunk = self::_byteSubstring( |
| | | $outputBuffer, |
| | | 0, |
| | | self::CHUNK_SIZE |
| | | ); |
| | | |
| | | $length = self::_byteLength($chunk); |
| | | |
| | | $this->_debug( |
| | | '=> about to write ' . $length . ' bytes to output stream' |
| | | ); |
| | | |
| | | $length = fwrite($this->_output, $chunk, $length); |
| | | |
| | | $this->_debug('=> wrote ' . $length . ' bytes'); |
| | | |
| | | $outputBuffer = self::_byteSubstring($outputBuffer, $length); |
| | | } |
| | | |
| | | // read error (from GPG) |
| | | if (in_array($fdError, $inputStreams)) { |
| | | $this->_debug('GPG error stream ready for reading'); |
| | | $this->_debug( |
| | | '=> about to read ' . self::CHUNK_SIZE . |
| | | ' bytes from GPG error' |
| | | ); |
| | | |
| | | $chunk = fread($fdError, self::CHUNK_SIZE); |
| | | $length = self::_byteLength($chunk); |
| | | $errorBuffer .= $chunk; |
| | | |
| | | $this->_debug('=> read ' . $length . ' bytes'); |
| | | |
| | | // pass lines to error handlers |
| | | while (($pos = strpos($errorBuffer, PHP_EOL)) !== false) { |
| | | $line = self::_byteSubstring($errorBuffer, 0, $pos); |
| | | foreach ($this->_errorHandlers as $handler) { |
| | | array_unshift($handler['args'], $line); |
| | | call_user_func_array( |
| | | $handler['callback'], |
| | | $handler['args'] |
| | | ); |
| | | |
| | | array_shift($handler['args']); |
| | | } |
| | | $errorBuffer = self::_byteSubString( |
| | | $errorBuffer, |
| | | $pos + self::_byteLength(PHP_EOL) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // read status (from GPG) |
| | | if (in_array($fdStatus, $inputStreams)) { |
| | | $this->_debug('GPG status stream ready for reading'); |
| | | $this->_debug( |
| | | '=> about to read ' . self::CHUNK_SIZE . |
| | | ' bytes from GPG status' |
| | | ); |
| | | |
| | | $chunk = fread($fdStatus, self::CHUNK_SIZE); |
| | | $length = self::_byteLength($chunk); |
| | | $statusBuffer .= $chunk; |
| | | |
| | | $this->_debug('=> read ' . $length . ' bytes'); |
| | | |
| | | // pass lines to status handlers |
| | | while (($pos = strpos($statusBuffer, PHP_EOL)) !== false) { |
| | | $line = self::_byteSubstring($statusBuffer, 0, $pos); |
| | | // only pass lines beginning with magic prefix |
| | | if (self::_byteSubstring($line, 0, 9) == '[GNUPG:] ') { |
| | | $line = self::_byteSubstring($line, 9); |
| | | foreach ($this->_statusHandlers as $handler) { |
| | | array_unshift($handler['args'], $line); |
| | | call_user_func_array( |
| | | $handler['callback'], |
| | | $handler['args'] |
| | | ); |
| | | |
| | | array_shift($handler['args']); |
| | | } |
| | | } |
| | | $statusBuffer = self::_byteSubString( |
| | | $statusBuffer, |
| | | $pos + self::_byteLength(PHP_EOL) |
| | | ); |
| | | } |
| | | } |
| | | |
| | | // write command (to GPG) |
| | | if (in_array($fdCommand, $outputStreams)) { |
| | | $this->_debug('GPG is ready for command data'); |
| | | |
| | | // send commands |
| | | $chunk = self::_byteSubstring( |
| | | $this->_commandBuffer, |
| | | 0, |
| | | self::CHUNK_SIZE |
| | | ); |
| | | |
| | | $length = self::_byteLength($chunk); |
| | | |
| | | $this->_debug( |
| | | '=> about to write ' . $length . ' bytes to GPG command' |
| | | ); |
| | | |
| | | $length = fwrite($fdCommand, $chunk, $length); |
| | | |
| | | $this->_debug('=> wrote ' . $length); |
| | | |
| | | $this->_commandBuffer = self::_byteSubstring( |
| | | $this->_commandBuffer, |
| | | $length |
| | | ); |
| | | } |
| | | |
| | | } // end loop while streams are open |
| | | |
| | | $this->_debug('END PROCESSING'); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _openSubprocess() |
| | | |
| | | /** |
| | | * Opens an internal GPG subprocess for the current operation |
| | | * |
| | | * Opens a GPG subprocess, then connects the subprocess to some pipes. Sets |
| | | * the private class property {@link Crypt_GPG_Engine::$_process} to |
| | | * the new subprocess. |
| | | * |
| | | * @return void |
| | | * |
| | | * @throws Crypt_GPG_OpenSubprocessException if the subprocess could not be |
| | | * opened. |
| | | * |
| | | * @see Crypt_GPG_Engine::setOperation() |
| | | * @see Crypt_GPG_Engine::_closeSubprocess() |
| | | * @see Crypt_GPG_Engine::$_process |
| | | */ |
| | | private function _openSubprocess() |
| | | { |
| | | $version = $this->getVersion(); |
| | | |
| | | $env = $_ENV; |
| | | |
| | | // Newer versions of GnuPG return localized results. Crypt_GPG only |
| | | // works with English, so set the locale to 'C' for the subprocess. |
| | | $env['LC_ALL'] = 'C'; |
| | | |
| | | $commandLine = $this->_binary; |
| | | |
| | | $defaultArguments = array( |
| | | '--status-fd ' . escapeshellarg(self::FD_STATUS), |
| | | '--command-fd ' . escapeshellarg(self::FD_COMMAND), |
| | | '--no-secmem-warning', |
| | | '--no-tty', |
| | | '--no-default-keyring', // ignored if keying files are not specified |
| | | '--no-options' // prevent creation of ~/.gnupg directory |
| | | ); |
| | | |
| | | if (version_compare($version, '1.0.7', 'ge')) { |
| | | if (version_compare($version, '2.0.0', 'lt')) { |
| | | $defaultArguments[] = '--no-use-agent'; |
| | | } |
| | | $defaultArguments[] = '--no-permission-warning'; |
| | | } |
| | | |
| | | if (version_compare($version, '1.4.2', 'ge')) { |
| | | $defaultArguments[] = '--exit-on-status-write-error'; |
| | | } |
| | | |
| | | if (version_compare($version, '1.3.2', 'ge')) { |
| | | $defaultArguments[] = '--trust-model always'; |
| | | } else { |
| | | $defaultArguments[] = '--always-trust'; |
| | | } |
| | | |
| | | $arguments = array_merge($defaultArguments, $this->_arguments); |
| | | |
| | | if ($this->_homedir) { |
| | | $arguments[] = '--homedir ' . escapeshellarg($this->_homedir); |
| | | |
| | | // the random seed file makes subsequent actions faster so only |
| | | // disable it if we have to. |
| | | if (!is_writeable($this->_homedir)) { |
| | | $arguments[] = '--no-random-seed-file'; |
| | | } |
| | | } |
| | | |
| | | if ($this->_publicKeyring) { |
| | | $arguments[] = '--keyring ' . escapeshellarg($this->_publicKeyring); |
| | | } |
| | | |
| | | if ($this->_privateKeyring) { |
| | | $arguments[] = '--secret-keyring ' . |
| | | escapeshellarg($this->_privateKeyring); |
| | | } |
| | | |
| | | if ($this->_trustDb) { |
| | | $arguments[] = '--trustdb-name ' . escapeshellarg($this->_trustDb); |
| | | } |
| | | |
| | | $commandLine .= ' ' . implode(' ', $arguments) . ' ' . |
| | | $this->_operation; |
| | | |
| | | // Binary operations will not work on Windows with PHP < 5.2.6. This is |
| | | // in case stream_select() ever works on Windows. |
| | | $rb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'r' : 'rb'; |
| | | $wb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'w' : 'wb'; |
| | | |
| | | $descriptorSpec = array( |
| | | self::FD_INPUT => array('pipe', $rb), // stdin |
| | | self::FD_OUTPUT => array('pipe', $wb), // stdout |
| | | self::FD_ERROR => array('pipe', $wb), // stderr |
| | | self::FD_STATUS => array('pipe', $wb), // status |
| | | self::FD_COMMAND => array('pipe', $rb), // command |
| | | self::FD_MESSAGE => array('pipe', $rb) // message |
| | | ); |
| | | |
| | | $this->_debug('OPENING SUBPROCESS WITH THE FOLLOWING COMMAND:'); |
| | | $this->_debug($commandLine); |
| | | |
| | | $this->_process = proc_open( |
| | | $commandLine, |
| | | $descriptorSpec, |
| | | $this->_pipes, |
| | | null, |
| | | $env, |
| | | array('binary_pipes' => true) |
| | | ); |
| | | |
| | | if (!is_resource($this->_process)) { |
| | | throw new Crypt_GPG_OpenSubprocessException( |
| | | 'Unable to open GPG subprocess.', 0, $commandLine); |
| | | } |
| | | |
| | | $this->_openPipes = $this->_pipes; |
| | | $this->_errorCode = Crypt_GPG::ERROR_NONE; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _closeSubprocess() |
| | | |
| | | /** |
| | | * Closes a the internal GPG subprocess |
| | | * |
| | | * Closes the internal GPG subprocess. Sets the private class property |
| | | * {@link Crypt_GPG_Engine::$_process} to null. |
| | | * |
| | | * @return void |
| | | * |
| | | * @see Crypt_GPG_Engine::_openSubprocess() |
| | | * @see Crypt_GPG_Engine::$_process |
| | | */ |
| | | private function _closeSubprocess() |
| | | { |
| | | if (is_resource($this->_process)) { |
| | | $this->_debug('CLOSING SUBPROCESS'); |
| | | |
| | | // close remaining open pipes |
| | | foreach (array_keys($this->_openPipes) as $pipeNumber) { |
| | | $this->_closePipe($pipeNumber); |
| | | } |
| | | |
| | | $exitCode = proc_close($this->_process); |
| | | |
| | | if ($exitCode != 0) { |
| | | $this->_debug( |
| | | '=> subprocess returned an unexpected exit code: ' . |
| | | $exitCode |
| | | ); |
| | | |
| | | if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { |
| | | if ($this->_needPassphrase > 0) { |
| | | $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE; |
| | | } else { |
| | | $this->_errorCode = Crypt_GPG::ERROR_UNKNOWN; |
| | | } |
| | | } |
| | | } |
| | | |
| | | $this->_process = null; |
| | | $this->_pipes = array(); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _closePipe() |
| | | |
| | | /** |
| | | * Closes an opened pipe used to communicate with the GPG subprocess |
| | | * |
| | | * If the pipe is already closed, it is ignored. If the pipe is open, it |
| | | * is flushed and then closed. |
| | | * |
| | | * @param integer $pipeNumber the file descriptor number of the pipe to |
| | | * close. |
| | | * |
| | | * @return void |
| | | */ |
| | | private function _closePipe($pipeNumber) |
| | | { |
| | | $pipeNumber = intval($pipeNumber); |
| | | if (array_key_exists($pipeNumber, $this->_openPipes)) { |
| | | fflush($this->_openPipes[$pipeNumber]); |
| | | fclose($this->_openPipes[$pipeNumber]); |
| | | unset($this->_openPipes[$pipeNumber]); |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _getBinary() |
| | | |
| | | /** |
| | | * Gets the name of the GPG binary for the current operating system |
| | | * |
| | | * This method is called if the '<kbd>binary</kbd>' option is <i>not</i> |
| | | * specified when creating this driver. |
| | | * |
| | | * @return string the name of the GPG binary for the current operating |
| | | * system. If no suitable binary could be found, an empty |
| | | * string is returned. |
| | | */ |
| | | private function _getBinary() |
| | | { |
| | | $binary = ''; |
| | | |
| | | if ($this->_isDarwin) { |
| | | $binaryFiles = array( |
| | | '/opt/local/bin/gpg', // MacPorts |
| | | '/usr/local/bin/gpg', // Mac GPG |
| | | '/sw/bin/gpg', // Fink |
| | | '/usr/bin/gpg' |
| | | ); |
| | | } else { |
| | | $binaryFiles = array( |
| | | '/usr/bin/gpg', |
| | | '/usr/local/bin/gpg' |
| | | ); |
| | | } |
| | | |
| | | foreach ($binaryFiles as $binaryFile) { |
| | | if (is_executable($binaryFile)) { |
| | | $binary = $binaryFile; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return $binary; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _debug() |
| | | |
| | | /** |
| | | * Displays debug text if debugging is turned on |
| | | * |
| | | * Debugging text is prepended with a debug identifier and echoed to stdout. |
| | | * |
| | | * @param string $text the debugging text to display. |
| | | * |
| | | * @return void |
| | | */ |
| | | private function _debug($text) |
| | | { |
| | | if ($this->_debug) { |
| | | if (array_key_exists('SHELL', $_ENV)) { |
| | | foreach (explode(PHP_EOL, $text) as $line) { |
| | | echo "Crypt_GPG DEBUG: ", $line, PHP_EOL; |
| | | } |
| | | } else { |
| | | // running on a web server, format debug output nicely |
| | | foreach (explode(PHP_EOL, $text) as $line) { |
| | | echo "Crypt_GPG DEBUG: <strong>", $line, |
| | | '</strong><br />', PHP_EOL; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _byteLength() |
| | | |
| | | /** |
| | | * Gets the length of a string in bytes even if mbstring function |
| | | * overloading is turned on |
| | | * |
| | | * This is used for stream-based communication with the GPG subprocess. |
| | | * |
| | | * @param string $string the string for which to get the length. |
| | | * |
| | | * @return integer the length of the string in bytes. |
| | | * |
| | | * @see Crypt_GPG_Engine::$_mbStringOverload |
| | | */ |
| | | private static function _byteLength($string) |
| | | { |
| | | if (self::$_mbStringOverload) { |
| | | return mb_strlen($string, '8bit'); |
| | | } |
| | | |
| | | return strlen((binary)$string); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _byteSubstring() |
| | | |
| | | /** |
| | | * Gets the substring of a string in bytes even if mbstring function |
| | | * overloading is turned on |
| | | * |
| | | * This is used for stream-based communication with the GPG subprocess. |
| | | * |
| | | * @param string $string the input string. |
| | | * @param integer $start the starting point at which to get the substring. |
| | | * @param integer $length optional. The length of the substring. |
| | | * |
| | | * @return string the extracted part of the string. Unlike the default PHP |
| | | * <kbd>substr()</kbd> function, the returned value is |
| | | * always a string and never false. |
| | | * |
| | | * @see Crypt_GPG_Engine::$_mbStringOverload |
| | | */ |
| | | private static function _byteSubstring($string, $start, $length = null) |
| | | { |
| | | if (self::$_mbStringOverload) { |
| | | if ($length === null) { |
| | | return mb_substr( |
| | | $string, |
| | | $start, |
| | | self::_byteLength($string) - $start, '8bit' |
| | | ); |
| | | } |
| | | |
| | | return mb_substr($string, $start, $length, '8bit'); |
| | | } |
| | | |
| | | if ($length === null) { |
| | | return (string)substr((binary)$string, $start); |
| | | } |
| | | |
| | | return (string)substr((binary)$string, $start, $length); |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Various exception handling classes for Crypt_GPG |
| | | * |
| | | * Crypt_GPG provides an object oriented interface to GNU Privacy |
| | | * Guard (GPG). It requires the GPG executable to be on the system. |
| | | * |
| | | * This file contains various exception classes used by the Crypt_GPG package. |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: Exceptions.php 273745 2009-01-18 05:24:25Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | |
| | | /** |
| | | * PEAR Exception handler and base class |
| | | */ |
| | | require_once 'PEAR/Exception.php'; |
| | | |
| | | // {{{ class Crypt_GPG_Exception |
| | | |
| | | /** |
| | | * An exception thrown by the Crypt_GPG package |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_Exception extends PEAR_Exception |
| | | { |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_FileException |
| | | |
| | | /** |
| | | * An exception thrown when a file is used in ways it cannot be used |
| | | * |
| | | * For example, if an output file is specified and the file is not writeable, or |
| | | * if an input file is specified and the file is not readable, this exception |
| | | * is thrown. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2007-2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_FileException extends Crypt_GPG_Exception |
| | | { |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * The name of the file that caused this exception |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_filename = ''; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new Crypt_GPG_FileException |
| | | * |
| | | * @param string $message an error message. |
| | | * @param integer $code a user defined error code. |
| | | * @param string $filename the name of the file that caused this exception. |
| | | */ |
| | | public function __construct($message, $code = 0, $filename = '') |
| | | { |
| | | $this->_filename = $filename; |
| | | parent::__construct($message, $code); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getFilename() |
| | | |
| | | /** |
| | | * Returns the filename of the file that caused this exception |
| | | * |
| | | * @return string the filename of the file that caused this exception. |
| | | * |
| | | * @see Crypt_GPG_FileException::$_filename |
| | | */ |
| | | public function getFilename() |
| | | { |
| | | return $this->_filename; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_OpenSubprocessException |
| | | |
| | | /** |
| | | * An exception thrown when the GPG subprocess cannot be opened |
| | | * |
| | | * This exception is thrown when the {@link Crypt_GPG_Engine} tries to open a |
| | | * new subprocess and fails. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_OpenSubprocessException extends Crypt_GPG_Exception |
| | | { |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * The command used to try to open the subprocess |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_command = ''; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new Crypt_GPG_OpenSubprocessException |
| | | * |
| | | * @param string $message an error message. |
| | | * @param integer $code a user defined error code. |
| | | * @param string $command the command that was called to open the |
| | | * new subprocess. |
| | | * |
| | | * @see Crypt_GPG::_openSubprocess() |
| | | */ |
| | | public function __construct($message, $code = 0, $command = '') |
| | | { |
| | | $this->_command = $command; |
| | | parent::__construct($message, $code); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getCommand() |
| | | |
| | | /** |
| | | * Returns the contents of the internal _command property |
| | | * |
| | | * @return string the command used to open the subprocess. |
| | | * |
| | | * @see Crypt_GPG_OpenSubprocessException::$_command |
| | | */ |
| | | public function getCommand() |
| | | { |
| | | return $this->_command; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_InvalidOperationException |
| | | |
| | | /** |
| | | * An exception thrown when an invalid GPG operation is attempted |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_InvalidOperationException extends Crypt_GPG_Exception |
| | | { |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * The attempted operation |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_operation = ''; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new Crypt_GPG_OpenSubprocessException |
| | | * |
| | | * @param string $message an error message. |
| | | * @param integer $code a user defined error code. |
| | | * @param string $operation the operation. |
| | | */ |
| | | public function __construct($message, $code = 0, $operation = '') |
| | | { |
| | | $this->_operation = $operation; |
| | | parent::__construct($message, $code); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getOperation() |
| | | |
| | | /** |
| | | * Returns the contents of the internal _operation property |
| | | * |
| | | * @return string the attempted operation. |
| | | * |
| | | * @see Crypt_GPG_InvalidOperationException::$_operation |
| | | */ |
| | | public function getOperation() |
| | | { |
| | | return $this->_operation; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_KeyNotFoundException |
| | | |
| | | /** |
| | | * An exception thrown when Crypt_GPG fails to find the key for various |
| | | * operations |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_KeyNotFoundException extends Crypt_GPG_Exception |
| | | { |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * The key identifier that was searched for |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_keyId = ''; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new Crypt_GPG_KeyNotFoundException |
| | | * |
| | | * @param string $message an error message. |
| | | * @param integer $code a user defined error code. |
| | | * @param string $keyId the key identifier of the key. |
| | | */ |
| | | public function __construct($message, $code = 0, $keyId= '') |
| | | { |
| | | $this->_keyId = $keyId; |
| | | parent::__construct($message, $code); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getKeyId() |
| | | |
| | | /** |
| | | * Gets the key identifier of the key that was not found |
| | | * |
| | | * @return string the key identifier of the key that was not found. |
| | | */ |
| | | public function getKeyId() |
| | | { |
| | | return $this->_keyId; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_NoDataException |
| | | |
| | | /** |
| | | * An exception thrown when Crypt_GPG cannot find valid data for various |
| | | * operations |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2006 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_NoDataException extends Crypt_GPG_Exception |
| | | { |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_BadPassphraseException |
| | | |
| | | /** |
| | | * An exception thrown when a required passphrase is incorrect or missing |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2006-2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_BadPassphraseException extends Crypt_GPG_Exception |
| | | { |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * Keys for which the passhprase is missing |
| | | * |
| | | * This contains primary user ids indexed by sub-key id. |
| | | * |
| | | * @var array |
| | | */ |
| | | private $_missingPassphrases = array(); |
| | | |
| | | /** |
| | | * Keys for which the passhprase is incorrect |
| | | * |
| | | * This contains primary user ids indexed by sub-key id. |
| | | * |
| | | * @var array |
| | | */ |
| | | private $_badPassphrases = array(); |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new Crypt_GPG_BadPassphraseException |
| | | * |
| | | * @param string $message an error message. |
| | | * @param integer $code a user defined error code. |
| | | * @param string $badPassphrases an array containing user ids of keys |
| | | * for which the passphrase is incorrect. |
| | | * @param string $missingPassphrases an array containing user ids of keys |
| | | * for which the passphrase is missing. |
| | | */ |
| | | public function __construct($message, $code = 0, |
| | | array $badPassphrases = array(), array $missingPassphrases = array() |
| | | ) { |
| | | $this->_badPassphrases = $badPassphrases; |
| | | $this->_missingPassphrases = $missingPassphrases; |
| | | |
| | | parent::__construct($message, $code); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getBadPassphrases() |
| | | |
| | | /** |
| | | * Gets keys for which the passhprase is incorrect |
| | | * |
| | | * @return array an array of keys for which the passphrase is incorrect. |
| | | * The array contains primary user ids indexed by the sub-key |
| | | * id. |
| | | */ |
| | | public function getBadPassphrases() |
| | | { |
| | | return $this->_badPassphrases; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getMissingPassphrases() |
| | | |
| | | /** |
| | | * Gets keys for which the passhprase is missing |
| | | * |
| | | * @return array an array of keys for which the passphrase is missing. |
| | | * The array contains primary user ids indexed by the sub-key |
| | | * id. |
| | | */ |
| | | public function getMissingPassphrases() |
| | | { |
| | | return $this->_missingPassphrases; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ class Crypt_GPG_DeletePrivateKeyException |
| | | |
| | | /** |
| | | * An exception thrown when an attempt is made to delete public key that has an |
| | | * associated private key on the keyring |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | class Crypt_GPG_DeletePrivateKeyException extends Crypt_GPG_Exception |
| | | { |
| | | // {{{ private class properties |
| | | |
| | | /** |
| | | * The key identifier the deletion attempt was made upon |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_keyId = ''; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new Crypt_GPG_DeletePrivateKeyException |
| | | * |
| | | * @param string $message an error message. |
| | | * @param integer $code a user defined error code. |
| | | * @param string $keyId the key identifier of the public key that was |
| | | * attempted to delete. |
| | | * |
| | | * @see Crypt_GPG::deletePublicKey() |
| | | */ |
| | | public function __construct($message, $code = 0, $keyId = '') |
| | | { |
| | | $this->_keyId = $keyId; |
| | | parent::__construct($message, $code); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getKeyId() |
| | | |
| | | /** |
| | | * Gets the key identifier of the key that was not found |
| | | * |
| | | * @return string the key identifier of the key that was not found. |
| | | */ |
| | | public function getKeyId() |
| | | { |
| | | return $this->_keyId; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Contains a class representing GPG keys |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: Key.php 295621 2010-03-01 04:18:54Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | |
| | | /** |
| | | * Sub-key class definition |
| | | */ |
| | | require_once 'Crypt/GPG/SubKey.php'; |
| | | |
| | | /** |
| | | * User id class definition |
| | | */ |
| | | require_once 'Crypt/GPG/UserId.php'; |
| | | |
| | | // {{{ class Crypt_GPG_Key |
| | | |
| | | /** |
| | | * A data class for GPG key information |
| | | * |
| | | * This class is used to store the results of the {@link Crypt_GPG::getKeys()} |
| | | * method. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @see Crypt_GPG::getKeys() |
| | | */ |
| | | class Crypt_GPG_Key |
| | | { |
| | | // {{{ class properties |
| | | |
| | | /** |
| | | * The user ids associated with this key |
| | | * |
| | | * This is an array of {@link Crypt_GPG_UserId} objects. |
| | | * |
| | | * @var array |
| | | * |
| | | * @see Crypt_GPG_Key::addUserId() |
| | | * @see Crypt_GPG_Key::getUserIds() |
| | | */ |
| | | private $_userIds = array(); |
| | | |
| | | /** |
| | | * The subkeys of this key |
| | | * |
| | | * This is an array of {@link Crypt_GPG_SubKey} objects. |
| | | * |
| | | * @var array |
| | | * |
| | | * @see Crypt_GPG_Key::addSubKey() |
| | | * @see Crypt_GPG_Key::getSubKeys() |
| | | */ |
| | | private $_subKeys = array(); |
| | | |
| | | // }}} |
| | | // {{{ getSubKeys() |
| | | |
| | | /** |
| | | * Gets the sub-keys of this key |
| | | * |
| | | * @return array the sub-keys of this key. |
| | | * |
| | | * @see Crypt_GPG_Key::addSubKey() |
| | | */ |
| | | public function getSubKeys() |
| | | { |
| | | return $this->_subKeys; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getUserIds() |
| | | |
| | | /** |
| | | * Gets the user ids of this key |
| | | * |
| | | * @return array the user ids of this key. |
| | | * |
| | | * @see Crypt_GPG_Key::addUserId() |
| | | */ |
| | | public function getUserIds() |
| | | { |
| | | return $this->_userIds; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getPrimaryKey() |
| | | |
| | | /** |
| | | * Gets the primary sub-key of this key |
| | | * |
| | | * The primary key is the first added sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the primary sub-key of this key. |
| | | */ |
| | | public function getPrimaryKey() |
| | | { |
| | | $primary_key = null; |
| | | if (count($this->_subKeys) > 0) { |
| | | $primary_key = $this->_subKeys[0]; |
| | | } |
| | | return $primary_key; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ canSign() |
| | | |
| | | /** |
| | | * Gets whether or not this key can sign data |
| | | * |
| | | * This key can sign data if any sub-key of this key can sign data. |
| | | * |
| | | * @return boolean true if this key can sign data and false if this key |
| | | * cannot sign data. |
| | | */ |
| | | public function canSign() |
| | | { |
| | | $canSign = false; |
| | | foreach ($this->_subKeys as $subKey) { |
| | | if ($subKey->canSign()) { |
| | | $canSign = true; |
| | | break; |
| | | } |
| | | } |
| | | return $canSign; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ canEncrypt() |
| | | |
| | | /** |
| | | * Gets whether or not this key can encrypt data |
| | | * |
| | | * This key can encrypt data if any sub-key of this key can encrypt data. |
| | | * |
| | | * @return boolean true if this key can encrypt data and false if this |
| | | * key cannot encrypt data. |
| | | */ |
| | | public function canEncrypt() |
| | | { |
| | | $canEncrypt = false; |
| | | foreach ($this->_subKeys as $subKey) { |
| | | if ($subKey->canEncrypt()) { |
| | | $canEncrypt = true; |
| | | break; |
| | | } |
| | | } |
| | | return $canEncrypt; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addSubKey() |
| | | |
| | | /** |
| | | * Adds a sub-key to this key |
| | | * |
| | | * The first added sub-key will be the primary key of this key. |
| | | * |
| | | * @param Crypt_GPG_SubKey $subKey the sub-key to add. |
| | | * |
| | | * @return Crypt_GPG_Key the current object, for fluent interface. |
| | | */ |
| | | public function addSubKey(Crypt_GPG_SubKey $subKey) |
| | | { |
| | | $this->_subKeys[] = $subKey; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ addUserId() |
| | | |
| | | /** |
| | | * Adds a user id to this key |
| | | * |
| | | * @param Crypt_GPG_UserId $userId the user id to add. |
| | | * |
| | | * @return Crypt_GPG_Key the current object, for fluent interface. |
| | | */ |
| | | public function addUserId(Crypt_GPG_UserId $userId) |
| | | { |
| | | $this->_userIds[] = $userId; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * A class representing GPG signatures |
| | | * |
| | | * This file contains a data class representing a GPG signature. |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: Signature.php 302773 2010-08-25 14:16:28Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | |
| | | /** |
| | | * User id class definition |
| | | */ |
| | | require_once 'Crypt/GPG/UserId.php'; |
| | | |
| | | // {{{ class Crypt_GPG_Signature |
| | | |
| | | /** |
| | | * A class for GPG signature information |
| | | * |
| | | * This class is used to store the results of the Crypt_GPG::verify() method. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @see Crypt_GPG::verify() |
| | | */ |
| | | class Crypt_GPG_Signature |
| | | { |
| | | // {{{ class properties |
| | | |
| | | /** |
| | | * A base64-encoded string containing a unique id for this signature if |
| | | * this signature has been verified as ok |
| | | * |
| | | * This id is used to prevent replay attacks and is not present for all |
| | | * types of signatures. |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_id = ''; |
| | | |
| | | /** |
| | | * The fingerprint of the key used to create the signature |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_keyFingerprint = ''; |
| | | |
| | | /** |
| | | * The id of the key used to create the signature |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_keyId = ''; |
| | | |
| | | /** |
| | | * The creation date of this signature |
| | | * |
| | | * This is a Unix timestamp. |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_creationDate = 0; |
| | | |
| | | /** |
| | | * The expiration date of the signature |
| | | * |
| | | * This is a Unix timestamp. If this signature does not expire, this will |
| | | * be zero. |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_expirationDate = 0; |
| | | |
| | | /** |
| | | * The user id associated with this signature |
| | | * |
| | | * @var Crypt_GPG_UserId |
| | | */ |
| | | private $_userId = null; |
| | | |
| | | /** |
| | | * Whether or not this signature is valid |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_isValid = false; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new signature |
| | | * |
| | | * Signatures can be initialized from an array of named values. Available |
| | | * names are: |
| | | * |
| | | * - <kbd>string id</kbd> - the unique id of this signature. |
| | | * - <kbd>string fingerprint</kbd> - the fingerprint of the key used to |
| | | * create the signature. The fingerprint |
| | | * should not contain formatting |
| | | * characters. |
| | | * - <kbd>string keyId</kbd> - the id of the key used to create the |
| | | * the signature. |
| | | * - <kbd>integer creation</kbd> - the date the signature was created. |
| | | * This is a UNIX timestamp. |
| | | * - <kbd>integer expiration</kbd> - the date the signature expired. This |
| | | * is a UNIX timestamp. If the signature |
| | | * does not expire, use 0. |
| | | * - <kbd>boolean valid</kbd> - whether or not the signature is valid. |
| | | * - <kbd>string userId</kbd> - the user id associated with the |
| | | * signature. This may also be a |
| | | * {@link Crypt_GPG_UserId} object. |
| | | * |
| | | * @param Crypt_GPG_Signature|array $signature optional. Either an existing |
| | | * signature object, which is copied; or an array of initial values. |
| | | */ |
| | | public function __construct($signature = null) |
| | | { |
| | | // copy from object |
| | | if ($signature instanceof Crypt_GPG_Signature) { |
| | | $this->_id = $signature->_id; |
| | | $this->_keyFingerprint = $signature->_keyFingerprint; |
| | | $this->_keyId = $signature->_keyId; |
| | | $this->_creationDate = $signature->_creationDate; |
| | | $this->_expirationDate = $signature->_expirationDate; |
| | | $this->_isValid = $signature->_isValid; |
| | | |
| | | if ($signature->_userId instanceof Crypt_GPG_UserId) { |
| | | $this->_userId = clone $signature->_userId; |
| | | } else { |
| | | $this->_userId = $signature->_userId; |
| | | } |
| | | } |
| | | |
| | | // initialize from array |
| | | if (is_array($signature)) { |
| | | if (array_key_exists('id', $signature)) { |
| | | $this->setId($signature['id']); |
| | | } |
| | | |
| | | if (array_key_exists('fingerprint', $signature)) { |
| | | $this->setKeyFingerprint($signature['fingerprint']); |
| | | } |
| | | |
| | | if (array_key_exists('keyId', $signature)) { |
| | | $this->setKeyId($signature['keyId']); |
| | | } |
| | | |
| | | if (array_key_exists('creation', $signature)) { |
| | | $this->setCreationDate($signature['creation']); |
| | | } |
| | | |
| | | if (array_key_exists('expiration', $signature)) { |
| | | $this->setExpirationDate($signature['expiration']); |
| | | } |
| | | |
| | | if (array_key_exists('valid', $signature)) { |
| | | $this->setValid($signature['valid']); |
| | | } |
| | | |
| | | if (array_key_exists('userId', $signature)) { |
| | | $userId = new Crypt_GPG_UserId($signature['userId']); |
| | | $this->setUserId($userId); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getId() |
| | | |
| | | /** |
| | | * Gets the id of this signature |
| | | * |
| | | * @return string a base64-encoded string containing a unique id for this |
| | | * signature. This id is used to prevent replay attacks and |
| | | * is not present for all types of signatures. |
| | | */ |
| | | public function getId() |
| | | { |
| | | return $this->_id; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getKeyFingerprint() |
| | | |
| | | /** |
| | | * Gets the fingerprint of the key used to create this signature |
| | | * |
| | | * @return string the fingerprint of the key used to create this signature. |
| | | */ |
| | | public function getKeyFingerprint() |
| | | { |
| | | return $this->_keyFingerprint; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getKeyId() |
| | | |
| | | /** |
| | | * Gets the id of the key used to create this signature |
| | | * |
| | | * Whereas the fingerprint of the signing key may not always be available |
| | | * (for example if the signature is bad), the id should always be |
| | | * available. |
| | | * |
| | | * @return string the id of the key used to create this signature. |
| | | */ |
| | | public function getKeyId() |
| | | { |
| | | return $this->_keyId; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getCreationDate() |
| | | |
| | | /** |
| | | * Gets the creation date of this signature |
| | | * |
| | | * @return integer the creation date of this signature. This is a Unix |
| | | * timestamp. |
| | | */ |
| | | public function getCreationDate() |
| | | { |
| | | return $this->_creationDate; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getExpirationDate() |
| | | |
| | | /** |
| | | * Gets the expiration date of the signature |
| | | * |
| | | * @return integer the expiration date of this signature. This is a Unix |
| | | * timestamp. If this signature does not expire, this will |
| | | * be zero. |
| | | */ |
| | | public function getExpirationDate() |
| | | { |
| | | return $this->_expirationDate; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getUserId() |
| | | |
| | | /** |
| | | * Gets the user id associated with this signature |
| | | * |
| | | * @return Crypt_GPG_UserId the user id associated with this signature. |
| | | */ |
| | | public function getUserId() |
| | | { |
| | | return $this->_userId; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ isValid() |
| | | |
| | | /** |
| | | * Gets whether or no this signature is valid |
| | | * |
| | | * @return boolean true if this signature is valid and false if it is not. |
| | | */ |
| | | public function isValid() |
| | | { |
| | | return $this->_isValid; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setId() |
| | | |
| | | /** |
| | | * Sets the id of this signature |
| | | * |
| | | * @param string $id a base64-encoded string containing a unique id for |
| | | * this signature. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | * |
| | | * @see Crypt_GPG_Signature::getId() |
| | | */ |
| | | public function setId($id) |
| | | { |
| | | $this->_id = strval($id); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setKeyFingerprint() |
| | | |
| | | /** |
| | | * Sets the key fingerprint of this signature |
| | | * |
| | | * @param string $fingerprint the key fingerprint of this signature. This |
| | | * is the fingerprint of the primary key used to |
| | | * create this signature. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | */ |
| | | public function setKeyFingerprint($fingerprint) |
| | | { |
| | | $this->_keyFingerprint = strval($fingerprint); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setKeyId() |
| | | |
| | | /** |
| | | * Sets the key id of this signature |
| | | * |
| | | * @param string $id the key id of this signature. This is the id of the |
| | | * primary key used to create this signature. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | */ |
| | | public function setKeyId($id) |
| | | { |
| | | $this->_keyId = strval($id); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setCreationDate() |
| | | |
| | | /** |
| | | * Sets the creation date of this signature |
| | | * |
| | | * @param integer $creationDate the creation date of this signature. This |
| | | * is a Unix timestamp. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | */ |
| | | public function setCreationDate($creationDate) |
| | | { |
| | | $this->_creationDate = intval($creationDate); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setExpirationDate() |
| | | |
| | | /** |
| | | * Sets the expiration date of this signature |
| | | * |
| | | * @param integer $expirationDate the expiration date of this signature. |
| | | * This is a Unix timestamp. Specify zero if |
| | | * this signature does not expire. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | */ |
| | | public function setExpirationDate($expirationDate) |
| | | { |
| | | $this->_expirationDate = intval($expirationDate); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setUserId() |
| | | |
| | | /** |
| | | * Sets the user id associated with this signature |
| | | * |
| | | * @param Crypt_GPG_UserId $userId the user id associated with this |
| | | * signature. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | */ |
| | | public function setUserId(Crypt_GPG_UserId $userId) |
| | | { |
| | | $this->_userId = $userId; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setValid() |
| | | |
| | | /** |
| | | * Sets whether or not this signature is valid |
| | | * |
| | | * @param boolean $isValid true if this signature is valid and false if it |
| | | * is not. |
| | | * |
| | | * @return Crypt_GPG_Signature the current object, for fluent interface. |
| | | */ |
| | | public function setValid($isValid) |
| | | { |
| | | $this->_isValid = ($isValid) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Contains a class representing GPG sub-keys and constants for GPG algorithms |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: SubKey.php 302768 2010-08-25 13:45:52Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | |
| | | // {{{ class Crypt_GPG_SubKey |
| | | |
| | | /** |
| | | * A class for GPG sub-key information |
| | | * |
| | | * This class is used to store the results of the {@link Crypt_GPG::getKeys()} |
| | | * method. Sub-key objects are members of a {@link Crypt_GPG_Key} object. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @author Nathan Fredrickson <nathan@silverorange.com> |
| | | * @copyright 2005-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @see Crypt_GPG::getKeys() |
| | | * @see Crypt_GPG_Key::getSubKeys() |
| | | */ |
| | | class Crypt_GPG_SubKey |
| | | { |
| | | // {{{ class constants |
| | | |
| | | /** |
| | | * RSA encryption algorithm. |
| | | */ |
| | | const ALGORITHM_RSA = 1; |
| | | |
| | | /** |
| | | * Elgamal encryption algorithm (encryption only). |
| | | */ |
| | | const ALGORITHM_ELGAMAL_ENC = 16; |
| | | |
| | | /** |
| | | * DSA encryption algorithm (sometimes called DH, sign only). |
| | | */ |
| | | const ALGORITHM_DSA = 17; |
| | | |
| | | /** |
| | | * Elgamal encryption algorithm (signage and encryption - should not be |
| | | * used). |
| | | */ |
| | | const ALGORITHM_ELGAMAL_ENC_SGN = 20; |
| | | |
| | | // }}} |
| | | // {{{ class properties |
| | | |
| | | /** |
| | | * The id of this sub-key |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_id = ''; |
| | | |
| | | /** |
| | | * The algorithm used to create this sub-key |
| | | * |
| | | * The value is one of the Crypt_GPG_SubKey::ALGORITHM_* constants. |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_algorithm = 0; |
| | | |
| | | /** |
| | | * The fingerprint of this sub-key |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_fingerprint = ''; |
| | | |
| | | /** |
| | | * Length of this sub-key in bits |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_length = 0; |
| | | |
| | | /** |
| | | * Date this sub-key was created |
| | | * |
| | | * This is a Unix timestamp. |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_creationDate = 0; |
| | | |
| | | /** |
| | | * Date this sub-key expires |
| | | * |
| | | * This is a Unix timestamp. If this sub-key does not expire, this will be |
| | | * zero. |
| | | * |
| | | * @var integer |
| | | */ |
| | | private $_expirationDate = 0; |
| | | |
| | | /** |
| | | * Whether or not this sub-key can sign data |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_canSign = false; |
| | | |
| | | /** |
| | | * Whether or not this sub-key can encrypt data |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_canEncrypt = false; |
| | | |
| | | /** |
| | | * Whether or not the private key for this sub-key exists in the keyring |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_hasPrivate = false; |
| | | |
| | | /** |
| | | * Whether or not this sub-key is revoked |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_isRevoked = false; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new sub-key object |
| | | * |
| | | * Sub-keys can be initialized from an array of named values. Available |
| | | * names are: |
| | | * |
| | | * - <kbd>string id</kbd> - the key id of the sub-key. |
| | | * - <kbd>integer algorithm</kbd> - the encryption algorithm of the |
| | | * sub-key. |
| | | * - <kbd>string fingerprint</kbd> - the fingerprint of the sub-key. The |
| | | * fingerprint should not contain |
| | | * formatting characters. |
| | | * - <kbd>integer length</kbd> - the length of the sub-key in bits. |
| | | * - <kbd>integer creation</kbd> - the date the sub-key was created. |
| | | * This is a UNIX timestamp. |
| | | * - <kbd>integer expiration</kbd> - the date the sub-key expires. This |
| | | * is a UNIX timestamp. If the sub-key |
| | | * does not expire, use 0. |
| | | * - <kbd>boolean canSign</kbd> - whether or not the sub-key can be |
| | | * used to sign data. |
| | | * - <kbd>boolean canEncrypt</kbd> - whether or not the sub-key can be |
| | | * used to encrypt data. |
| | | * - <kbd>boolean hasPrivate</kbd> - whether or not the private key for |
| | | * the sub-key exists in the keyring. |
| | | * - <kbd>boolean isRevoked</kbd> - whether or not this sub-key is |
| | | * revoked. |
| | | * |
| | | * @param Crypt_GPG_SubKey|string|array $key optional. Either an existing |
| | | * sub-key object, which is copied; a sub-key string, which is |
| | | * parsed; or an array of initial values. |
| | | */ |
| | | public function __construct($key = null) |
| | | { |
| | | // parse from string |
| | | if (is_string($key)) { |
| | | $key = self::parse($key); |
| | | } |
| | | |
| | | // copy from object |
| | | if ($key instanceof Crypt_GPG_SubKey) { |
| | | $this->_id = $key->_id; |
| | | $this->_algorithm = $key->_algorithm; |
| | | $this->_fingerprint = $key->_fingerprint; |
| | | $this->_length = $key->_length; |
| | | $this->_creationDate = $key->_creationDate; |
| | | $this->_expirationDate = $key->_expirationDate; |
| | | $this->_canSign = $key->_canSign; |
| | | $this->_canEncrypt = $key->_canEncrypt; |
| | | $this->_hasPrivate = $key->_hasPrivate; |
| | | $this->_isRevoked = $key->_isRevoked; |
| | | } |
| | | |
| | | // initialize from array |
| | | if (is_array($key)) { |
| | | if (array_key_exists('id', $key)) { |
| | | $this->setId($key['id']); |
| | | } |
| | | |
| | | if (array_key_exists('algorithm', $key)) { |
| | | $this->setAlgorithm($key['algorithm']); |
| | | } |
| | | |
| | | if (array_key_exists('fingerprint', $key)) { |
| | | $this->setFingerprint($key['fingerprint']); |
| | | } |
| | | |
| | | if (array_key_exists('length', $key)) { |
| | | $this->setLength($key['length']); |
| | | } |
| | | |
| | | if (array_key_exists('creation', $key)) { |
| | | $this->setCreationDate($key['creation']); |
| | | } |
| | | |
| | | if (array_key_exists('expiration', $key)) { |
| | | $this->setExpirationDate($key['expiration']); |
| | | } |
| | | |
| | | if (array_key_exists('canSign', $key)) { |
| | | $this->setCanSign($key['canSign']); |
| | | } |
| | | |
| | | if (array_key_exists('canEncrypt', $key)) { |
| | | $this->setCanEncrypt($key['canEncrypt']); |
| | | } |
| | | |
| | | if (array_key_exists('hasPrivate', $key)) { |
| | | $this->setHasPrivate($key['hasPrivate']); |
| | | } |
| | | |
| | | if (array_key_exists('isRevoked', $key)) { |
| | | $this->setRevoked($key['isRevoked']); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getId() |
| | | |
| | | /** |
| | | * Gets the id of this sub-key |
| | | * |
| | | * @return string the id of this sub-key. |
| | | */ |
| | | public function getId() |
| | | { |
| | | return $this->_id; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getAlgorithm() |
| | | |
| | | /** |
| | | * Gets the algorithm used by this sub-key |
| | | * |
| | | * The algorithm should be one of the Crypt_GPG_SubKey::ALGORITHM_* |
| | | * constants. |
| | | * |
| | | * @return integer the algorithm used by this sub-key. |
| | | */ |
| | | public function getAlgorithm() |
| | | { |
| | | return $this->_algorithm; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getCreationDate() |
| | | |
| | | /** |
| | | * Gets the creation date of this sub-key |
| | | * |
| | | * This is a Unix timestamp. |
| | | * |
| | | * @return integer the creation date of this sub-key. |
| | | */ |
| | | public function getCreationDate() |
| | | { |
| | | return $this->_creationDate; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getExpirationDate() |
| | | |
| | | /** |
| | | * Gets the date this sub-key expires |
| | | * |
| | | * This is a Unix timestamp. If this sub-key does not expire, this will be |
| | | * zero. |
| | | * |
| | | * @return integer the date this sub-key expires. |
| | | */ |
| | | public function getExpirationDate() |
| | | { |
| | | return $this->_expirationDate; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getFingerprint() |
| | | |
| | | /** |
| | | * Gets the fingerprint of this sub-key |
| | | * |
| | | * @return string the fingerprint of this sub-key. |
| | | */ |
| | | public function getFingerprint() |
| | | { |
| | | return $this->_fingerprint; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getLength() |
| | | |
| | | /** |
| | | * Gets the length of this sub-key in bits |
| | | * |
| | | * @return integer the length of this sub-key in bits. |
| | | */ |
| | | public function getLength() |
| | | { |
| | | return $this->_length; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ canSign() |
| | | |
| | | /** |
| | | * Gets whether or not this sub-key can sign data |
| | | * |
| | | * @return boolean true if this sub-key can sign data and false if this |
| | | * sub-key can not sign data. |
| | | */ |
| | | public function canSign() |
| | | { |
| | | return $this->_canSign; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ canEncrypt() |
| | | |
| | | /** |
| | | * Gets whether or not this sub-key can encrypt data |
| | | * |
| | | * @return boolean true if this sub-key can encrypt data and false if this |
| | | * sub-key can not encrypt data. |
| | | */ |
| | | public function canEncrypt() |
| | | { |
| | | return $this->_canEncrypt; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ hasPrivate() |
| | | |
| | | /** |
| | | * Gets whether or not the private key for this sub-key exists in the |
| | | * keyring |
| | | * |
| | | * @return boolean true the private key for this sub-key exists in the |
| | | * keyring and false if it does not. |
| | | */ |
| | | public function hasPrivate() |
| | | { |
| | | return $this->_hasPrivate; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ isRevoked() |
| | | |
| | | /** |
| | | * Gets whether or not this sub-key is revoked |
| | | * |
| | | * @return boolean true if this sub-key is revoked and false if it is not. |
| | | */ |
| | | public function isRevoked() |
| | | { |
| | | return $this->_isRevoked; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setCreationDate() |
| | | |
| | | /** |
| | | * Sets the creation date of this sub-key |
| | | * |
| | | * The creation date is a Unix timestamp. |
| | | * |
| | | * @param integer $creationDate the creation date of this sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setCreationDate($creationDate) |
| | | { |
| | | $this->_creationDate = intval($creationDate); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setExpirationDate() |
| | | |
| | | /** |
| | | * Sets the expiration date of this sub-key |
| | | * |
| | | * The expiration date is a Unix timestamp. Specify zero if this sub-key |
| | | * does not expire. |
| | | * |
| | | * @param integer $expirationDate the expiration date of this sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setExpirationDate($expirationDate) |
| | | { |
| | | $this->_expirationDate = intval($expirationDate); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setId() |
| | | |
| | | /** |
| | | * Sets the id of this sub-key |
| | | * |
| | | * @param string $id the id of this sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setId($id) |
| | | { |
| | | $this->_id = strval($id); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setAlgorithm() |
| | | |
| | | /** |
| | | * Sets the algorithm used by this sub-key |
| | | * |
| | | * @param integer $algorithm the algorithm used by this sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setAlgorithm($algorithm) |
| | | { |
| | | $this->_algorithm = intval($algorithm); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setFingerprint() |
| | | |
| | | /** |
| | | * Sets the fingerprint of this sub-key |
| | | * |
| | | * @param string $fingerprint the fingerprint of this sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setFingerprint($fingerprint) |
| | | { |
| | | $this->_fingerprint = strval($fingerprint); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setLength() |
| | | |
| | | /** |
| | | * Sets the length of this sub-key in bits |
| | | * |
| | | * @param integer $length the length of this sub-key in bits. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setLength($length) |
| | | { |
| | | $this->_length = intval($length); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setCanSign() |
| | | |
| | | /** |
| | | * Sets whether of not this sub-key can sign data |
| | | * |
| | | * @param boolean $canSign true if this sub-key can sign data and false if |
| | | * it can not. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setCanSign($canSign) |
| | | { |
| | | $this->_canSign = ($canSign) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setCanEncrypt() |
| | | |
| | | /** |
| | | * Sets whether of not this sub-key can encrypt data |
| | | * |
| | | * @param boolean $canEncrypt true if this sub-key can encrypt data and |
| | | * false if it can not. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setCanEncrypt($canEncrypt) |
| | | { |
| | | $this->_canEncrypt = ($canEncrypt) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setHasPrivate() |
| | | |
| | | /** |
| | | * Sets whether of not the private key for this sub-key exists in the |
| | | * keyring |
| | | * |
| | | * @param boolean $hasPrivate true if the private key for this sub-key |
| | | * exists in the keyring and false if it does |
| | | * not. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setHasPrivate($hasPrivate) |
| | | { |
| | | $this->_hasPrivate = ($hasPrivate) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setRevoked() |
| | | |
| | | /** |
| | | * Sets whether or not this sub-key is revoked |
| | | * |
| | | * @param boolean $isRevoked whether or not this sub-key is revoked. |
| | | * |
| | | * @return Crypt_GPG_SubKey the current object, for fluent interface. |
| | | */ |
| | | public function setRevoked($isRevoked) |
| | | { |
| | | $this->_isRevoked = ($isRevoked) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ parse() |
| | | |
| | | /** |
| | | * Parses a sub-key object from a sub-key string |
| | | * |
| | | * See <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG distribution} for information |
| | | * on how the sub-key string is parsed. |
| | | * |
| | | * @param string $string the string containing the sub-key. |
| | | * |
| | | * @return Crypt_GPG_SubKey the sub-key object parsed from the string. |
| | | */ |
| | | public static function parse($string) |
| | | { |
| | | $tokens = explode(':', $string); |
| | | |
| | | $subKey = new Crypt_GPG_SubKey(); |
| | | |
| | | $subKey->setId($tokens[4]); |
| | | $subKey->setLength($tokens[2]); |
| | | $subKey->setAlgorithm($tokens[3]); |
| | | $subKey->setCreationDate(self::_parseDate($tokens[5])); |
| | | $subKey->setExpirationDate(self::_parseDate($tokens[6])); |
| | | |
| | | if ($tokens[1] == 'r') { |
| | | $subKey->setRevoked(true); |
| | | } |
| | | |
| | | if (strpos($tokens[11], 's') !== false) { |
| | | $subKey->setCanSign(true); |
| | | } |
| | | |
| | | if (strpos($tokens[11], 'e') !== false) { |
| | | $subKey->setCanEncrypt(true); |
| | | } |
| | | |
| | | return $subKey; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ _parseDate() |
| | | |
| | | /** |
| | | * Parses a date string as provided by GPG into a UNIX timestamp |
| | | * |
| | | * @param string $string the date string. |
| | | * |
| | | * @return integer the UNIX timestamp corresponding to the provided date |
| | | * string. |
| | | */ |
| | | private static function _parseDate($string) |
| | | { |
| | | if ($string == '') { |
| | | $timestamp = 0; |
| | | } else { |
| | | // all times are in UTC according to GPG documentation |
| | | $timeZone = new DateTimeZone('UTC'); |
| | | |
| | | if (strpos($string, 'T') === false) { |
| | | // interpret as UNIX timestamp |
| | | $string = '@' . $string; |
| | | } |
| | | |
| | | $date = new DateTime($string, $timeZone); |
| | | |
| | | // convert to UNIX timestamp |
| | | $timestamp = intval($date->format('U')); |
| | | } |
| | | |
| | | return $timestamp; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Contains a data class representing a GPG user id |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: UserId.php 295621 2010-03-01 04:18:54Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | */ |
| | | |
| | | // {{{ class Crypt_GPG_UserId |
| | | |
| | | /** |
| | | * A class for GPG user id information |
| | | * |
| | | * This class is used to store the results of the {@link Crypt_GPG::getKeys()} |
| | | * method. User id objects are members of a {@link Crypt_GPG_Key} object. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008-2010 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @see Crypt_GPG::getKeys() |
| | | * @see Crypt_GPG_Key::getUserIds() |
| | | */ |
| | | class Crypt_GPG_UserId |
| | | { |
| | | // {{{ class properties |
| | | |
| | | /** |
| | | * The name field of this user id |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_name = ''; |
| | | |
| | | /** |
| | | * The comment field of this user id |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_comment = ''; |
| | | |
| | | /** |
| | | * The email field of this user id |
| | | * |
| | | * @var string |
| | | */ |
| | | private $_email = ''; |
| | | |
| | | /** |
| | | * Whether or not this user id is revoked |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_isRevoked = false; |
| | | |
| | | /** |
| | | * Whether or not this user id is valid |
| | | * |
| | | * @var boolean |
| | | */ |
| | | private $_isValid = true; |
| | | |
| | | // }}} |
| | | // {{{ __construct() |
| | | |
| | | /** |
| | | * Creates a new user id |
| | | * |
| | | * User ids can be initialized from an array of named values. Available |
| | | * names are: |
| | | * |
| | | * - <kbd>string name</kbd> - the name field of the user id. |
| | | * - <kbd>string comment</kbd> - the comment field of the user id. |
| | | * - <kbd>string email</kbd> - the email field of the user id. |
| | | * - <kbd>boolean valid</kbd> - whether or not the user id is valid. |
| | | * - <kbd>boolean revoked</kbd> - whether or not the user id is revoked. |
| | | * |
| | | * @param Crypt_GPG_UserId|string|array $userId optional. Either an |
| | | * existing user id object, which is copied; a user id string, which |
| | | * is parsed; or an array of initial values. |
| | | */ |
| | | public function __construct($userId = null) |
| | | { |
| | | // parse from string |
| | | if (is_string($userId)) { |
| | | $userId = self::parse($userId); |
| | | } |
| | | |
| | | // copy from object |
| | | if ($userId instanceof Crypt_GPG_UserId) { |
| | | $this->_name = $userId->_name; |
| | | $this->_comment = $userId->_comment; |
| | | $this->_email = $userId->_email; |
| | | $this->_isRevoked = $userId->_isRevoked; |
| | | $this->_isValid = $userId->_isValid; |
| | | } |
| | | |
| | | // initialize from array |
| | | if (is_array($userId)) { |
| | | if (array_key_exists('name', $userId)) { |
| | | $this->setName($userId['name']); |
| | | } |
| | | |
| | | if (array_key_exists('comment', $userId)) { |
| | | $this->setComment($userId['comment']); |
| | | } |
| | | |
| | | if (array_key_exists('email', $userId)) { |
| | | $this->setEmail($userId['email']); |
| | | } |
| | | |
| | | if (array_key_exists('revoked', $userId)) { |
| | | $this->setRevoked($userId['revoked']); |
| | | } |
| | | |
| | | if (array_key_exists('valid', $userId)) { |
| | | $this->setValid($userId['valid']); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getName() |
| | | |
| | | /** |
| | | * Gets the name field of this user id |
| | | * |
| | | * @return string the name field of this user id. |
| | | */ |
| | | public function getName() |
| | | { |
| | | return $this->_name; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getComment() |
| | | |
| | | /** |
| | | * Gets the comments field of this user id |
| | | * |
| | | * @return string the comments field of this user id. |
| | | */ |
| | | public function getComment() |
| | | { |
| | | return $this->_comment; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getEmail() |
| | | |
| | | /** |
| | | * Gets the email field of this user id |
| | | * |
| | | * @return string the email field of this user id. |
| | | */ |
| | | public function getEmail() |
| | | { |
| | | return $this->_email; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ isRevoked() |
| | | |
| | | /** |
| | | * Gets whether or not this user id is revoked |
| | | * |
| | | * @return boolean true if this user id is revoked and false if it is not. |
| | | */ |
| | | public function isRevoked() |
| | | { |
| | | return $this->_isRevoked; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ isValid() |
| | | |
| | | /** |
| | | * Gets whether or not this user id is valid |
| | | * |
| | | * @return boolean true if this user id is valid and false if it is not. |
| | | */ |
| | | public function isValid() |
| | | { |
| | | return $this->_isValid; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ __toString() |
| | | |
| | | /** |
| | | * Gets a string representation of this user id |
| | | * |
| | | * The string is formatted as: |
| | | * <b><kbd>name (comment) <email-address></kbd></b>. |
| | | * |
| | | * @return string a string representation of this user id. |
| | | */ |
| | | public function __toString() |
| | | { |
| | | $components = array(); |
| | | |
| | | if (strlen($this->_name) > 0) { |
| | | $components[] = $this->_name; |
| | | } |
| | | |
| | | if (strlen($this->_comment) > 0) { |
| | | $components[] = '(' . $this->_comment . ')'; |
| | | } |
| | | |
| | | if (strlen($this->_email) > 0) { |
| | | $components[] = '<' . $this->_email. '>'; |
| | | } |
| | | |
| | | return implode(' ', $components); |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setName() |
| | | |
| | | /** |
| | | * Sets the name field of this user id |
| | | * |
| | | * @param string $name the name field of this user id. |
| | | * |
| | | * @return Crypt_GPG_UserId the current object, for fluent interface. |
| | | */ |
| | | public function setName($name) |
| | | { |
| | | $this->_name = strval($name); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setComment() |
| | | |
| | | /** |
| | | * Sets the comment field of this user id |
| | | * |
| | | * @param string $comment the comment field of this user id. |
| | | * |
| | | * @return Crypt_GPG_UserId the current object, for fluent interface. |
| | | */ |
| | | public function setComment($comment) |
| | | { |
| | | $this->_comment = strval($comment); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setEmail() |
| | | |
| | | /** |
| | | * Sets the email field of this user id |
| | | * |
| | | * @param string $email the email field of this user id. |
| | | * |
| | | * @return Crypt_GPG_UserId the current object, for fluent interface. |
| | | */ |
| | | public function setEmail($email) |
| | | { |
| | | $this->_email = strval($email); |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setRevoked() |
| | | |
| | | /** |
| | | * Sets whether or not this user id is revoked |
| | | * |
| | | * @param boolean $isRevoked whether or not this user id is revoked. |
| | | * |
| | | * @return Crypt_GPG_UserId the current object, for fluent interface. |
| | | */ |
| | | public function setRevoked($isRevoked) |
| | | { |
| | | $this->_isRevoked = ($isRevoked) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ setValid() |
| | | |
| | | /** |
| | | * Sets whether or not this user id is valid |
| | | * |
| | | * @param boolean $isValid whether or not this user id is valid. |
| | | * |
| | | * @return Crypt_GPG_UserId the current object, for fluent interface. |
| | | */ |
| | | public function setValid($isValid) |
| | | { |
| | | $this->_isValid = ($isValid) ? true : false; |
| | | return $this; |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ parse() |
| | | |
| | | /** |
| | | * Parses a user id object from a user id string |
| | | * |
| | | * A user id string is of the form: |
| | | * <b><kbd>name (comment) <email-address></kbd></b> with the <i>comment</i> |
| | | * and <i>email-address</i> fields being optional. |
| | | * |
| | | * @param string $string the user id string to parse. |
| | | * |
| | | * @return Crypt_GPG_UserId the user id object parsed from the string. |
| | | */ |
| | | public static function parse($string) |
| | | { |
| | | $userId = new Crypt_GPG_UserId(); |
| | | $email = ''; |
| | | $comment = ''; |
| | | |
| | | // get email address from end of string if it exists |
| | | $matches = array(); |
| | | if (preg_match('/^(.+?) <([^>]+)>$/', $string, $matches) === 1) { |
| | | $string = $matches[1]; |
| | | $email = $matches[2]; |
| | | } |
| | | |
| | | // get comment from end of string if it exists |
| | | $matches = array(); |
| | | if (preg_match('/^(.+?) \(([^\)]+)\)$/', $string, $matches) === 1) { |
| | | $string = $matches[1]; |
| | | $comment = $matches[2]; |
| | | } |
| | | |
| | | $name = $string; |
| | | |
| | | $userId->setName($name); |
| | | $userId->setComment($comment); |
| | | $userId->setEmail($email); |
| | | |
| | | return $userId; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | // }}} |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ |
| | | |
| | | /** |
| | | * Crypt_GPG is a package to use GPG from PHP |
| | | * |
| | | * This file contains an object that handles GPG's status output for the verify |
| | | * operation. |
| | | * |
| | | * PHP version 5 |
| | | * |
| | | * LICENSE: |
| | | * |
| | | * This library is free software; you can redistribute it and/or modify |
| | | * it under the terms of the GNU Lesser General Public License as |
| | | * published by the Free Software Foundation; either version 2.1 of the |
| | | * License, or (at your option) any later version. |
| | | * |
| | | * This library 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 |
| | | * Lesser General Public License for more details. |
| | | * |
| | | * You should have received a copy of the GNU Lesser General Public |
| | | * License along with this library; if not, write to the Free Software |
| | | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @version CVS: $Id: VerifyStatusHandler.php 302908 2010-08-31 03:56:54Z gauthierm $ |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | |
| | | /** |
| | | * Signature object class definition |
| | | */ |
| | | require_once 'Crypt/GPG/Signature.php'; |
| | | |
| | | /** |
| | | * Status line handler for the verify operation |
| | | * |
| | | * This class is used internally by Crypt_GPG and does not need be used |
| | | * directly. See the {@link Crypt_GPG} class for end-user API. |
| | | * |
| | | * This class is responsible for building signature objects that are returned |
| | | * by the {@link Crypt_GPG::verify()} method. See <b>doc/DETAILS</b> in the |
| | | * {@link http://www.gnupg.org/download/ GPG distribution} for detailed |
| | | * information on GPG's status output for the verify operation. |
| | | * |
| | | * @category Encryption |
| | | * @package Crypt_GPG |
| | | * @author Michael Gauthier <mike@silverorange.com> |
| | | * @copyright 2008 silverorange |
| | | * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 |
| | | * @link http://pear.php.net/package/Crypt_GPG |
| | | * @link http://www.gnupg.org/ |
| | | */ |
| | | class Crypt_GPG_VerifyStatusHandler |
| | | { |
| | | // {{{ protected properties |
| | | |
| | | /** |
| | | * The current signature id |
| | | * |
| | | * Ths signature id is emitted by GPG before the new signature line so we |
| | | * must remember it temporarily. |
| | | * |
| | | * @var string |
| | | */ |
| | | protected $signatureId = ''; |
| | | |
| | | /** |
| | | * List of parsed {@link Crypt_GPG_Signature} objects |
| | | * |
| | | * @var array |
| | | */ |
| | | protected $signatures = array(); |
| | | |
| | | /** |
| | | * Array index of the current signature |
| | | * |
| | | * @var integer |
| | | */ |
| | | protected $index = -1; |
| | | |
| | | // }}} |
| | | // {{{ handle() |
| | | |
| | | /** |
| | | * Handles a status line |
| | | * |
| | | * @param string $line the status line to handle. |
| | | * |
| | | * @return void |
| | | */ |
| | | public function handle($line) |
| | | { |
| | | $tokens = explode(' ', $line); |
| | | switch ($tokens[0]) { |
| | | case 'GOODSIG': |
| | | case 'EXPSIG': |
| | | case 'EXPKEYSIG': |
| | | case 'REVKEYSIG': |
| | | case 'BADSIG': |
| | | $signature = new Crypt_GPG_Signature(); |
| | | |
| | | // if there was a signature id, set it on the new signature |
| | | if ($this->signatureId != '') { |
| | | $signature->setId($this->signatureId); |
| | | $this->signatureId = ''; |
| | | } |
| | | |
| | | // Detect whether fingerprint or key id was returned and set |
| | | // signature values appropriately. Key ids are strings of either |
| | | // 16 or 8 hexadecimal characters. Fingerprints are strings of 40 |
| | | // hexadecimal characters. The key id is the last 16 characters of |
| | | // the key fingerprint. |
| | | if (strlen($tokens[1]) > 16) { |
| | | $signature->setKeyFingerprint($tokens[1]); |
| | | $signature->setKeyId(substr($tokens[1], -16)); |
| | | } else { |
| | | $signature->setKeyId($tokens[1]); |
| | | } |
| | | |
| | | // get user id string |
| | | $string = implode(' ', array_splice($tokens, 2)); |
| | | $string = rawurldecode($string); |
| | | |
| | | $signature->setUserId(Crypt_GPG_UserId::parse($string)); |
| | | |
| | | $this->index++; |
| | | $this->signatures[$this->index] = $signature; |
| | | break; |
| | | |
| | | case 'ERRSIG': |
| | | $signature = new Crypt_GPG_Signature(); |
| | | |
| | | // if there was a signature id, set it on the new signature |
| | | if ($this->signatureId != '') { |
| | | $signature->setId($this->signatureId); |
| | | $this->signatureId = ''; |
| | | } |
| | | |
| | | // Detect whether fingerprint or key id was returned and set |
| | | // signature values appropriately. Key ids are strings of either |
| | | // 16 or 8 hexadecimal characters. Fingerprints are strings of 40 |
| | | // hexadecimal characters. The key id is the last 16 characters of |
| | | // the key fingerprint. |
| | | if (strlen($tokens[1]) > 16) { |
| | | $signature->setKeyFingerprint($tokens[1]); |
| | | $signature->setKeyId(substr($tokens[1], -16)); |
| | | } else { |
| | | $signature->setKeyId($tokens[1]); |
| | | } |
| | | |
| | | $this->index++; |
| | | $this->signatures[$this->index] = $signature; |
| | | |
| | | break; |
| | | |
| | | case 'VALIDSIG': |
| | | if (!array_key_exists($this->index, $this->signatures)) { |
| | | break; |
| | | } |
| | | |
| | | $signature = $this->signatures[$this->index]; |
| | | |
| | | $signature->setValid(true); |
| | | $signature->setKeyFingerprint($tokens[1]); |
| | | |
| | | if (strpos($tokens[3], 'T') === false) { |
| | | $signature->setCreationDate($tokens[3]); |
| | | } else { |
| | | $signature->setCreationDate(strtotime($tokens[3])); |
| | | } |
| | | |
| | | if (array_key_exists(4, $tokens)) { |
| | | if (strpos($tokens[4], 'T') === false) { |
| | | $signature->setExpirationDate($tokens[4]); |
| | | } else { |
| | | $signature->setExpirationDate(strtotime($tokens[4])); |
| | | } |
| | | } |
| | | |
| | | break; |
| | | |
| | | case 'SIG_ID': |
| | | // note: signature id comes before new signature line and may not |
| | | // exist for some signature types |
| | | $this->signatureId = $tokens[1]; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // }}} |
| | | // {{{ getSignatures() |
| | | |
| | | /** |
| | | * Gets the {@link Crypt_GPG_Signature} objects parsed by this handler |
| | | * |
| | | * @return array the signature objects parsed by this handler. |
| | | */ |
| | | public function getSignatures() |
| | | { |
| | | return $this->signatures; |
| | | } |
| | | |
| | | // }}} |
| | | } |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Abstract driver for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | abstract class enigma_driver |
| | | { |
| | | /** |
| | | * Class constructor. |
| | | * |
| | | * @param string User name (email address) |
| | | */ |
| | | abstract function __construct($user); |
| | | |
| | | /** |
| | | * Driver initialization. |
| | | * |
| | | * @return mixed NULL on success, enigma_error on failure |
| | | */ |
| | | abstract function init(); |
| | | |
| | | /** |
| | | * Encryption. |
| | | */ |
| | | abstract function encrypt($text, $keys); |
| | | |
| | | /** |
| | | * Decryption.. |
| | | */ |
| | | abstract function decrypt($text, $key, $passwd); |
| | | |
| | | /** |
| | | * Signing. |
| | | */ |
| | | abstract function sign($text, $key, $passwd); |
| | | |
| | | /** |
| | | * Signature verification. |
| | | * |
| | | * @param string Message body |
| | | * @param string Signature, if message is of type PGP/MIME and body doesn't contain it |
| | | * |
| | | * @return mixed Signature information (enigma_signature) or enigma_error |
| | | */ |
| | | abstract function verify($text, $signature); |
| | | |
| | | /** |
| | | * Key/Cert file import. |
| | | * |
| | | * @param string File name or file content |
| | | * @param bollean True if first argument is a filename |
| | | * |
| | | * @return mixed Import status array or enigma_error |
| | | */ |
| | | abstract function import($content, $isfile=false); |
| | | |
| | | /** |
| | | * Keys listing. |
| | | * |
| | | * @param string Optional pattern for key ID, user ID or fingerprint |
| | | * |
| | | * @return mixed Array of enigma_key objects or enigma_error |
| | | */ |
| | | abstract function list_keys($pattern=''); |
| | | |
| | | /** |
| | | * Single key information. |
| | | * |
| | | * @param string Key ID, user ID or fingerprint |
| | | * |
| | | * @return mixed Key (enigma_key) object or enigma_error |
| | | */ |
| | | abstract function get_key($keyid); |
| | | |
| | | /** |
| | | * Key pair generation. |
| | | * |
| | | * @param array Key/User data |
| | | * |
| | | * @return mixed Key (enigma_key) object or enigma_error |
| | | */ |
| | | abstract function gen_key($data); |
| | | |
| | | /** |
| | | * Key deletion. |
| | | */ |
| | | abstract function del_key($keyid); |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | GnuPG (PGP) driver for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | require_once 'Crypt/GPG.php'; |
| | | |
| | | class enigma_driver_gnupg extends enigma_driver |
| | | { |
| | | private $rc; |
| | | private $gpg; |
| | | private $homedir; |
| | | private $user; |
| | | |
| | | function __construct($user) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | $this->rc = $rcmail; |
| | | $this->user = $user; |
| | | } |
| | | |
| | | /** |
| | | * Driver initialization and environment checking. |
| | | * Should only return critical errors. |
| | | * |
| | | * @return mixed NULL on success, enigma_error on failure |
| | | */ |
| | | function init() |
| | | { |
| | | $homedir = $this->rc->config->get('enigma_pgp_homedir', INSTALL_PATH . '/plugins/enigma/home'); |
| | | |
| | | if (!$homedir) |
| | | return new enigma_error(enigma_error::E_INTERNAL, |
| | | "Option 'enigma_pgp_homedir' not specified"); |
| | | |
| | | // check if homedir exists (create it if not) and is readable |
| | | if (!file_exists($homedir)) |
| | | return new enigma_error(enigma_error::E_INTERNAL, |
| | | "Keys directory doesn't exists: $homedir"); |
| | | if (!is_writable($homedir)) |
| | | return new enigma_error(enigma_error::E_INTERNAL, |
| | | "Keys directory isn't writeable: $homedir"); |
| | | |
| | | $homedir = $homedir . '/' . $this->user; |
| | | |
| | | // check if user's homedir exists (create it if not) and is readable |
| | | if (!file_exists($homedir)) |
| | | mkdir($homedir, 0700); |
| | | |
| | | if (!file_exists($homedir)) |
| | | return new enigma_error(enigma_error::E_INTERNAL, |
| | | "Unable to create keys directory: $homedir"); |
| | | if (!is_writable($homedir)) |
| | | return new enigma_error(enigma_error::E_INTERNAL, |
| | | "Unable to write to keys directory: $homedir"); |
| | | |
| | | $this->homedir = $homedir; |
| | | |
| | | // Create Crypt_GPG object |
| | | try { |
| | | $this->gpg = new Crypt_GPG(array( |
| | | 'homedir' => $this->homedir, |
| | | // 'debug' => true, |
| | | )); |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | function encrypt($text, $keys) |
| | | { |
| | | /* |
| | | foreach ($keys as $key) { |
| | | $this->gpg->addEncryptKey($key); |
| | | } |
| | | $enc = $this->gpg->encrypt($text); |
| | | return $enc; |
| | | */ |
| | | } |
| | | |
| | | function decrypt($text, $key, $passwd) |
| | | { |
| | | // $this->gpg->addDecryptKey($key, $passwd); |
| | | try { |
| | | $dec = $this->gpg->decrypt($text); |
| | | return $dec; |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | function sign($text, $key, $passwd) |
| | | { |
| | | /* |
| | | $this->gpg->addSignKey($key, $passwd); |
| | | $signed = $this->gpg->sign($text, Crypt_GPG::SIGN_MODE_DETACHED); |
| | | return $signed; |
| | | */ |
| | | } |
| | | |
| | | function verify($text, $signature) |
| | | { |
| | | try { |
| | | $verified = $this->gpg->verify($text, $signature); |
| | | return $this->parse_signature($verified[0]); |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | public function import($content, $isfile=false) |
| | | { |
| | | try { |
| | | if ($isfile) |
| | | return $this->gpg->importKeyFile($content); |
| | | else |
| | | return $this->gpg->importKey($content); |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | public function list_keys($pattern='') |
| | | { |
| | | try { |
| | | $keys = $this->gpg->getKeys($pattern); |
| | | $result = array(); |
| | | //print_r($keys); |
| | | foreach ($keys as $idx => $key) { |
| | | $result[] = $this->parse_key($key); |
| | | unset($keys[$idx]); |
| | | } |
| | | //print_r($result); |
| | | return $result; |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | public function get_key($keyid) |
| | | { |
| | | $list = $this->list_keys($keyid); |
| | | |
| | | if (is_array($list)) |
| | | return array_shift($list); |
| | | |
| | | // error |
| | | return $list; |
| | | } |
| | | |
| | | public function gen_key($data) |
| | | { |
| | | } |
| | | |
| | | public function del_key($keyid) |
| | | { |
| | | // $this->get_key($keyid); |
| | | |
| | | |
| | | } |
| | | |
| | | public function del_privkey($keyid) |
| | | { |
| | | try { |
| | | $this->gpg->deletePrivateKey($keyid); |
| | | return true; |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | public function del_pubkey($keyid) |
| | | { |
| | | try { |
| | | $this->gpg->deletePublicKey($keyid); |
| | | return true; |
| | | } |
| | | catch (Exception $e) { |
| | | return $this->get_error_from_exception($e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Converts Crypt_GPG exception into Enigma's error object |
| | | * |
| | | * @param mixed Exception object |
| | | * |
| | | * @return enigma_error Error object |
| | | */ |
| | | private function get_error_from_exception($e) |
| | | { |
| | | $data = array(); |
| | | |
| | | if ($e instanceof Crypt_GPG_KeyNotFoundException) { |
| | | $error = enigma_error::E_KEYNOTFOUND; |
| | | $data['id'] = $e->getKeyId(); |
| | | } |
| | | else if ($e instanceof Crypt_GPG_BadPassphraseException) { |
| | | $error = enigma_error::E_BADPASS; |
| | | $data['bad'] = $e->getBadPassphrases(); |
| | | $data['missing'] = $e->getMissingPassphrases(); |
| | | } |
| | | else if ($e instanceof Crypt_GPG_NoDataException) |
| | | $error = enigma_error::E_NODATA; |
| | | else if ($e instanceof Crypt_GPG_DeletePrivateKeyException) |
| | | $error = enigma_error::E_DELKEY; |
| | | else |
| | | $error = enigma_error::E_INTERNAL; |
| | | |
| | | $msg = $e->getMessage(); |
| | | |
| | | return new enigma_error($error, $msg, $data); |
| | | } |
| | | |
| | | /** |
| | | * Converts Crypt_GPG_Signature object into Enigma's signature object |
| | | * |
| | | * @param Crypt_GPG_Signature Signature object |
| | | * |
| | | * @return enigma_signature Signature object |
| | | */ |
| | | private function parse_signature($sig) |
| | | { |
| | | $user = $sig->getUserId(); |
| | | |
| | | $data = new enigma_signature(); |
| | | $data->id = $sig->getId(); |
| | | $data->valid = $sig->isValid(); |
| | | $data->fingerprint = $sig->getKeyFingerprint(); |
| | | $data->created = $sig->getCreationDate(); |
| | | $data->expires = $sig->getExpirationDate(); |
| | | $data->name = $user->getName(); |
| | | $data->comment = $user->getComment(); |
| | | $data->email = $user->getEmail(); |
| | | |
| | | return $data; |
| | | } |
| | | |
| | | /** |
| | | * Converts Crypt_GPG_Key object into Enigma's key object |
| | | * |
| | | * @param Crypt_GPG_Key Key object |
| | | * |
| | | * @return enigma_key Key object |
| | | */ |
| | | private function parse_key($key) |
| | | { |
| | | $ekey = new enigma_key(); |
| | | |
| | | foreach ($key->getUserIds() as $idx => $user) { |
| | | $id = new enigma_userid(); |
| | | $id->name = $user->getName(); |
| | | $id->comment = $user->getComment(); |
| | | $id->email = $user->getEmail(); |
| | | $id->valid = $user->isValid(); |
| | | $id->revoked = $user->isRevoked(); |
| | | |
| | | $ekey->users[$idx] = $id; |
| | | } |
| | | |
| | | $ekey->name = trim($ekey->users[0]->name . ' <' . $ekey->users[0]->email . '>'); |
| | | |
| | | foreach ($key->getSubKeys() as $idx => $subkey) { |
| | | $skey = new enigma_subkey(); |
| | | $skey->id = $subkey->getId(); |
| | | $skey->revoked = $subkey->isRevoked(); |
| | | $skey->created = $subkey->getCreationDate(); |
| | | $skey->expires = $subkey->getExpirationDate(); |
| | | $skey->fingerprint = $subkey->getFingerprint(); |
| | | $skey->has_private = $subkey->hasPrivate(); |
| | | $skey->can_sign = $subkey->canSign(); |
| | | $skey->can_encrypt = $subkey->canEncrypt(); |
| | | |
| | | $ekey->subkeys[$idx] = $skey; |
| | | }; |
| | | |
| | | $ekey->id = $ekey->subkeys[0]->id; |
| | | |
| | | return $ekey; |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Engine of the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | |
| | | */ |
| | | |
| | | /* |
| | | RFC2440: OpenPGP Message Format |
| | | RFC3156: MIME Security with OpenPGP |
| | | RFC3851: S/MIME |
| | | */ |
| | | |
| | | class enigma_engine |
| | | { |
| | | private $rc; |
| | | private $enigma; |
| | | private $pgp_driver; |
| | | private $smime_driver; |
| | | |
| | | public $decryptions = array(); |
| | | public $signatures = array(); |
| | | public $signed_parts = array(); |
| | | |
| | | |
| | | /** |
| | | * Plugin initialization. |
| | | */ |
| | | function __construct($enigma) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | $this->rc = $rcmail; |
| | | $this->enigma = $enigma; |
| | | } |
| | | |
| | | /** |
| | | * PGP driver initialization. |
| | | */ |
| | | function load_pgp_driver() |
| | | { |
| | | if ($this->pgp_driver) |
| | | return; |
| | | |
| | | $driver = 'enigma_driver_' . $this->rc->config->get('enigma_pgp_driver', 'gnupg'); |
| | | $username = $this->rc->user->get_username(); |
| | | |
| | | // Load driver |
| | | $this->pgp_driver = new $driver($username); |
| | | |
| | | if (!$this->pgp_driver) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: Unable to load PGP driver: $driver" |
| | | ), true, true); |
| | | } |
| | | |
| | | // Initialise driver |
| | | $result = $this->pgp_driver->init(); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: ".$result->getMessage() |
| | | ), true, true); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * S/MIME driver initialization. |
| | | */ |
| | | function load_smime_driver() |
| | | { |
| | | if ($this->smime_driver) |
| | | return; |
| | | |
| | | // NOT IMPLEMENTED! |
| | | return; |
| | | |
| | | $driver = 'enigma_driver_' . $this->rc->config->get('enigma_smime_driver', 'phpssl'); |
| | | $username = $this->rc->user->get_username(); |
| | | |
| | | // Load driver |
| | | $this->smime_driver = new $driver($username); |
| | | |
| | | if (!$this->smime_driver) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: Unable to load S/MIME driver: $driver" |
| | | ), true, true); |
| | | } |
| | | |
| | | // Initialise driver |
| | | $result = $this->smime_driver->init(); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: ".$result->getMessage() |
| | | ), true, true); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for plain/text message. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | function parse_plain(&$p) |
| | | { |
| | | $part = $p['structure']; |
| | | |
| | | // Get message body from IMAP server |
| | | $this->set_part_body($part, $p['object']->uid); |
| | | |
| | | // @TODO: big message body can be a file resource |
| | | // PGP signed message |
| | | if (preg_match('/^-----BEGIN PGP SIGNED MESSAGE-----/', $part->body)) { |
| | | $this->parse_plain_signed($p); |
| | | } |
| | | // PGP encrypted message |
| | | else if (preg_match('/^-----BEGIN PGP MESSAGE-----/', $part->body)) { |
| | | $this->parse_plain_encrypted($p); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for multipart/signed message. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | function parse_signed(&$p) |
| | | { |
| | | $struct = $p['structure']; |
| | | |
| | | // S/MIME |
| | | if ($struct->parts[1] && $struct->parts[1]->mimetype == 'application/pkcs7-signature') { |
| | | $this->parse_smime_signed($p); |
| | | } |
| | | // PGP/MIME: |
| | | // The multipart/signed body MUST consist of exactly two parts. |
| | | // The first part contains the signed data in MIME canonical format, |
| | | // including a set of appropriate content headers describing the data. |
| | | // The second body MUST contain the PGP digital signature. It MUST be |
| | | // labeled with a content type of "application/pgp-signature". |
| | | else if ($struct->parts[1] && $struct->parts[1]->mimetype == 'application/pgp-signature') { |
| | | $this->parse_pgp_signed($p); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for multipart/encrypted message. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | function parse_encrypted(&$p) |
| | | { |
| | | $struct = $p['structure']; |
| | | |
| | | // S/MIME |
| | | if ($struct->mimetype == 'application/pkcs7-mime') { |
| | | $this->parse_smime_encrypted($p); |
| | | } |
| | | // PGP/MIME: |
| | | // The multipart/encrypted MUST consist of exactly two parts. The first |
| | | // MIME body part must have a content type of "application/pgp-encrypted". |
| | | // This body contains the control information. |
| | | // The second MIME body part MUST contain the actual encrypted data. It |
| | | // must be labeled with a content type of "application/octet-stream". |
| | | else if ($struct->parts[0] && $struct->parts[0]->mimetype == 'application/pgp-encrypted' && |
| | | $struct->parts[1] && $struct->parts[1]->mimetype == 'application/octet-stream' |
| | | ) { |
| | | $this->parse_pgp_encrypted($p); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for plain signed message. |
| | | * Excludes message and signature bodies and verifies signature. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | private function parse_plain_signed(&$p) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $part = $p['structure']; |
| | | |
| | | // Verify signature |
| | | if ($this->rc->action == 'show' || $this->rc->action == 'preview') { |
| | | $sig = $this->pgp_verify($part->body); |
| | | } |
| | | |
| | | // @TODO: Handle big bodies using (temp) files |
| | | |
| | | // In this way we can use fgets on string as on file handle |
| | | $fh = fopen('php://memory', 'br+'); |
| | | // @TODO: fopen/fwrite errors handling |
| | | if ($fh) { |
| | | fwrite($fh, $part->body); |
| | | rewind($fh); |
| | | } |
| | | $part->body = null; |
| | | |
| | | // Extract body (and signature?) |
| | | while (!feof($fh)) { |
| | | $line = fgets($fh, 1024); |
| | | |
| | | if ($part->body === null) |
| | | $part->body = ''; |
| | | else if (preg_match('/^-----BEGIN PGP SIGNATURE-----/', $line)) |
| | | break; |
| | | else |
| | | $part->body .= $line; |
| | | } |
| | | |
| | | // Remove "Hash" Armor Headers |
| | | $part->body = preg_replace('/^.*\r*\n\r*\n/', '', $part->body); |
| | | // de-Dash-Escape (RFC2440) |
| | | $part->body = preg_replace('/(^|\n)- -/', '\\1-', $part->body); |
| | | |
| | | // Store signature data for display |
| | | if (!empty($sig)) { |
| | | $this->signed_parts[$part->mime_id] = $part->mime_id; |
| | | $this->signatures[$part->mime_id] = $sig; |
| | | } |
| | | |
| | | fclose($fh); |
| | | } |
| | | |
| | | /** |
| | | * Handler for PGP/MIME signed message. |
| | | * Verifies signature. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | private function parse_pgp_signed(&$p) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $struct = $p['structure']; |
| | | |
| | | // Verify signature |
| | | if ($this->rc->action == 'show' || $this->rc->action == 'preview') { |
| | | $msg_part = $struct->parts[0]; |
| | | $sig_part = $struct->parts[1]; |
| | | |
| | | // Get bodies |
| | | $this->set_part_body($msg_part, $p['object']->uid); |
| | | $this->set_part_body($sig_part, $p['object']->uid); |
| | | |
| | | // Verify |
| | | $sig = $this->pgp_verify($msg_part->body, $sig_part->body); |
| | | |
| | | // Store signature data for display |
| | | $this->signatures[$struct->mime_id] = $sig; |
| | | |
| | | // Message can be multipart (assign signature to each subpart) |
| | | if (!empty($msg_part->parts)) { |
| | | foreach ($msg_part->parts as $part) |
| | | $this->signed_parts[$part->mime_id] = $struct->mime_id; |
| | | } |
| | | else |
| | | $this->signed_parts[$msg_part->mime_id] = $struct->mime_id; |
| | | |
| | | // Remove signature file from attachments list |
| | | unset($struct->parts[1]); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for S/MIME signed message. |
| | | * Verifies signature. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | private function parse_smime_signed(&$p) |
| | | { |
| | | $this->load_smime_driver(); |
| | | } |
| | | |
| | | /** |
| | | * Handler for plain encrypted message. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | private function parse_plain_encrypted(&$p) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $part = $p['structure']; |
| | | |
| | | // Get body |
| | | $this->set_part_body($part, $p['object']->uid); |
| | | |
| | | // Decrypt |
| | | $result = $this->pgp_decrypt($part->body); |
| | | |
| | | // Store decryption status |
| | | $this->decryptions[$part->mime_id] = $result; |
| | | |
| | | // Parse decrypted message |
| | | if ($result === true) { |
| | | // @TODO |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for PGP/MIME encrypted message. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | private function parse_pgp_encrypted(&$p) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $struct = $p['structure']; |
| | | $part = $struct->parts[1]; |
| | | |
| | | // Get body |
| | | $this->set_part_body($part, $p['object']->uid); |
| | | |
| | | // Decrypt |
| | | $result = $this->pgp_decrypt($part->body); |
| | | |
| | | $this->decryptions[$part->mime_id] = $result; |
| | | //print_r($part); |
| | | // Parse decrypted message |
| | | if ($result === true) { |
| | | // @TODO |
| | | } |
| | | else { |
| | | // Make sure decryption status message will be displayed |
| | | $part->type = 'content'; |
| | | $p['object']->parts[] = $part; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Handler for S/MIME encrypted message. |
| | | * |
| | | * @param array Reference to hook's parameters |
| | | */ |
| | | private function parse_smime_encrypted(&$p) |
| | | { |
| | | $this->load_smime_driver(); |
| | | } |
| | | |
| | | /** |
| | | * PGP signature verification. |
| | | * |
| | | * @param mixed Message body |
| | | * @param mixed Signature body (for MIME messages) |
| | | * |
| | | * @return mixed enigma_signature or enigma_error |
| | | */ |
| | | private function pgp_verify(&$msg_body, $sig_body=null) |
| | | { |
| | | // @TODO: Handle big bodies using (temp) files |
| | | // @TODO: caching of verification result |
| | | |
| | | $sig = $this->pgp_driver->verify($msg_body, $sig_body); |
| | | |
| | | if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $error->getMessage() |
| | | ), true, false); |
| | | |
| | | //print_r($sig); |
| | | return $sig; |
| | | } |
| | | |
| | | /** |
| | | * PGP message decryption. |
| | | * |
| | | * @param mixed Message body |
| | | * |
| | | * @return mixed True or enigma_error |
| | | */ |
| | | private function pgp_decrypt(&$msg_body) |
| | | { |
| | | // @TODO: Handle big bodies using (temp) files |
| | | // @TODO: caching of verification result |
| | | |
| | | $result = $this->pgp_driver->decrypt($msg_body, $key, $pass); |
| | | |
| | | //print_r($result); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | $err_code = $result->getCode(); |
| | | if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS))) |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | return $result; |
| | | } |
| | | |
| | | // $msg_body = $result; |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * PGP keys listing. |
| | | * |
| | | * @param mixed Key ID/Name pattern |
| | | * |
| | | * @return mixed Array of keys or enigma_error |
| | | */ |
| | | function list_keys($pattern='') |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $result = $this->pgp_driver->list_keys($pattern); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | /** |
| | | * PGP key details. |
| | | * |
| | | * @param mixed Key ID |
| | | * |
| | | * @return mixed enigma_key or enigma_error |
| | | */ |
| | | function get_key($keyid) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $result = $this->pgp_driver->get_key($keyid); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | /** |
| | | * PGP keys/certs importing. |
| | | * |
| | | * @param mixed Import file name or content |
| | | * @param boolean True if first argument is a filename |
| | | * |
| | | * @return mixed Import status data array or enigma_error |
| | | */ |
| | | function import_key($content, $isfile=false) |
| | | { |
| | | $this->load_pgp_driver(); |
| | | $result = $this->pgp_driver->import($content, $isfile); |
| | | |
| | | if ($result instanceof enigma_error) { |
| | | raise_error(array( |
| | | 'code' => 600, 'type' => 'php', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Enigma plugin: " . $result->getMessage() |
| | | ), true, false); |
| | | } |
| | | else { |
| | | $result['imported'] = $result['public_imported'] + $result['private_imported']; |
| | | $result['unchanged'] = $result['public_unchanged'] + $result['private_unchanged']; |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | /** |
| | | * Handler for keys/certs import request action |
| | | */ |
| | | function import_file() |
| | | { |
| | | $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); |
| | | |
| | | if ($uid && $mime_id) { |
| | | $part = $this->rc->imap->get_message_part($uid, $mime_id); |
| | | } |
| | | |
| | | if ($part && is_array($result = $this->import_key($part))) { |
| | | $this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation', |
| | | array('new' => $result['imported'], 'old' => $result['unchanged'])); |
| | | } |
| | | else |
| | | $this->rc->output->show_message('enigma.keysimportfailed', 'error'); |
| | | |
| | | $this->rc->output->send(); |
| | | } |
| | | |
| | | /** |
| | | * Checks if specified message part contains body data. |
| | | * If body is not set it will be fetched from IMAP server. |
| | | * |
| | | * @param rcube_message_part Message part object |
| | | * @param integer Message UID |
| | | */ |
| | | private function set_part_body($part, $uid) |
| | | { |
| | | // @TODO: Create such function in core |
| | | // @TODO: Handle big bodies using file handles |
| | | if (!isset($part->body)) { |
| | | $part->body = $this->rc->imap->get_message_part( |
| | | $uid, $part->mime_id, $part); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Adds CSS style file to the page header. |
| | | */ |
| | | private function add_css() |
| | | { |
| | | $skin = $this->rc->config->get('skin'); |
| | | if (!file_exists($this->home . "/skins/$skin/enigma.css")) |
| | | $skin = 'default'; |
| | | |
| | | $this->include_stylesheet("skins/$skin/enigma.css"); |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Error class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_error |
| | | { |
| | | private $code; |
| | | private $message; |
| | | private $data = array(); |
| | | |
| | | // error codes |
| | | const E_OK = 0; |
| | | const E_INTERNAL = 1; |
| | | const E_NODATA = 2; |
| | | const E_KEYNOTFOUND = 3; |
| | | const E_DELKEY = 4; |
| | | const E_BADPASS = 5; |
| | | |
| | | function __construct($code = null, $message = '', $data = array()) |
| | | { |
| | | $this->code = $code; |
| | | $this->message = $message; |
| | | $this->data = $data; |
| | | } |
| | | |
| | | function getCode() |
| | | { |
| | | return $this->code; |
| | | } |
| | | |
| | | function getMessage() |
| | | { |
| | | return $this->message; |
| | | } |
| | | |
| | | function getData($name) |
| | | { |
| | | if ($name) |
| | | return $this->data[$name]; |
| | | else |
| | | return $this->data; |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Key class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_key |
| | | { |
| | | public $id; |
| | | public $name; |
| | | public $users = array(); |
| | | public $subkeys = array(); |
| | | |
| | | const TYPE_UNKNOWN = 0; |
| | | const TYPE_KEYPAIR = 1; |
| | | const TYPE_PUBLIC = 2; |
| | | |
| | | /** |
| | | * Keys list sorting callback for usort() |
| | | */ |
| | | static function cmp($a, $b) |
| | | { |
| | | return strcmp($a->name, $b->name); |
| | | } |
| | | |
| | | /** |
| | | * Returns key type |
| | | */ |
| | | function get_type() |
| | | { |
| | | if ($this->subkeys[0]->has_private) |
| | | return enigma_key::TYPE_KEYPAIR; |
| | | else if (!empty($this->subkeys[0])) |
| | | return enigma_key::TYPE_PUBLIC; |
| | | |
| | | return enigma_key::TYPE_UNKNOWN; |
| | | } |
| | | |
| | | /** |
| | | * Returns true if all user IDs are revoked |
| | | */ |
| | | function is_revoked() |
| | | { |
| | | foreach ($this->subkeys as $subkey) |
| | | if (!$subkey->revoked) |
| | | return false; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Returns true if any user ID is valid |
| | | */ |
| | | function is_valid() |
| | | { |
| | | foreach ($this->users as $user) |
| | | if ($user->valid) |
| | | return true; |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Returns true if any of subkeys is not expired |
| | | */ |
| | | function is_expired() |
| | | { |
| | | $now = time(); |
| | | |
| | | foreach ($this->subkeys as $subkey) |
| | | if (!$subkey->expires || $subkey->expires > $now) |
| | | return true; |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Converts long ID or Fingerprint to short ID |
| | | * Crypt_GPG uses internal, but e.g. Thunderbird's Enigmail displays short ID |
| | | * |
| | | * @param string Key ID or fingerprint |
| | | * @return string Key short ID |
| | | */ |
| | | static function format_id($id) |
| | | { |
| | | // E.g. 04622F2089E037A5 => 89E037A5 |
| | | |
| | | return substr($id, -8); |
| | | } |
| | | |
| | | /** |
| | | * Formats fingerprint string |
| | | * |
| | | * @param string Key fingerprint |
| | | * |
| | | * @return string Formatted fingerprint (with spaces) |
| | | */ |
| | | static function format_fingerprint($fingerprint) |
| | | { |
| | | if (!$fingerprint) |
| | | return ''; |
| | | |
| | | $result = ''; |
| | | for ($i=0; $i<40; $i++) { |
| | | if ($i % 4 == 0) |
| | | $result .= ' '; |
| | | $result .= $fingerprint[$i]; |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | Signature class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_signature |
| | | { |
| | | public $id; |
| | | public $valid; |
| | | public $fingerprint; |
| | | public $created; |
| | | public $expires; |
| | | public $name; |
| | | public $comment; |
| | | public $email; |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | SubKey class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_subkey |
| | | { |
| | | public $id; |
| | | public $fingerprint; |
| | | public $expires; |
| | | public $created; |
| | | public $revoked; |
| | | public $has_private; |
| | | public $can_sign; |
| | | public $can_encrypt; |
| | | |
| | | /** |
| | | * Converts internal ID to short ID |
| | | * Crypt_GPG uses internal, but e.g. Thunderbird's Enigmail displays short ID |
| | | * |
| | | * @return string Key ID |
| | | */ |
| | | function get_short_id() |
| | | { |
| | | // E.g. 04622F2089E037A5 => 89E037A5 |
| | | return enigma_key::format_id($this->id); |
| | | } |
| | | |
| | | /** |
| | | * Getter for formatted fingerprint |
| | | * |
| | | * @return string Formatted fingerprint |
| | | */ |
| | | function get_fingerprint() |
| | | { |
| | | return enigma_key::format_fingerprint($this->fingerprint); |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | User Interface for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_ui |
| | | { |
| | | private $rc; |
| | | private $enigma; |
| | | private $home; |
| | | private $css_added; |
| | | private $data; |
| | | |
| | | |
| | | function __construct($enigma_plugin, $home='') |
| | | { |
| | | $this->enigma = $enigma_plugin; |
| | | $this->rc = $enigma_plugin->rc; |
| | | // we cannot use $enigma_plugin->home here |
| | | $this->home = $home; |
| | | } |
| | | |
| | | /** |
| | | * UI initialization and requests handlers. |
| | | * |
| | | * @param string Preferences section |
| | | */ |
| | | function init($section='') |
| | | { |
| | | $this->enigma->include_script('enigma.js'); |
| | | |
| | | // Enigma actions |
| | | if ($this->rc->action == 'plugin.enigma') { |
| | | $action = get_input_value('_a', RCUBE_INPUT_GPC); |
| | | |
| | | switch ($action) { |
| | | case 'keyedit': |
| | | $this->key_edit(); |
| | | break; |
| | | case 'keyimport': |
| | | $this->key_import(); |
| | | break; |
| | | case 'keysearch': |
| | | case 'keylist': |
| | | $this->key_list(); |
| | | break; |
| | | case 'keyinfo': |
| | | default: |
| | | $this->key_info(); |
| | | } |
| | | } |
| | | // Message composing UI |
| | | else if ($this->rc->action == 'compose') { |
| | | $this->compose_ui(); |
| | | } |
| | | // Preferences UI |
| | | else { // if ($this->rc->action == 'edit-prefs') { |
| | | if ($section == 'enigmacerts') { |
| | | $this->rc->output->add_handlers(array( |
| | | 'keyslist' => array($this, 'tpl_certs_list'), |
| | | 'keyframe' => array($this, 'tpl_cert_frame'), |
| | | 'countdisplay' => array($this, 'tpl_certs_rowcount'), |
| | | 'searchform' => array($this->rc->output, 'search_form'), |
| | | )); |
| | | $this->rc->output->set_pagetitle($this->enigma->gettext('enigmacerts')); |
| | | $this->rc->output->send('enigma.certs'); |
| | | } |
| | | else { |
| | | $this->rc->output->add_handlers(array( |
| | | 'keyslist' => array($this, 'tpl_keys_list'), |
| | | 'keyframe' => array($this, 'tpl_key_frame'), |
| | | 'countdisplay' => array($this, 'tpl_keys_rowcount'), |
| | | 'searchform' => array($this->rc->output, 'search_form'), |
| | | )); |
| | | $this->rc->output->set_pagetitle($this->enigma->gettext('enigmakeys')); |
| | | $this->rc->output->send('enigma.keys'); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Adds CSS style file to the page header. |
| | | */ |
| | | function add_css() |
| | | { |
| | | if ($this->css_loaded) |
| | | return; |
| | | |
| | | $skin = $this->rc->config->get('skin'); |
| | | if (!file_exists($this->home . "/skins/$skin/enigma.css")) |
| | | $skin = 'default'; |
| | | |
| | | $this->enigma->include_stylesheet("skins/$skin/enigma.css"); |
| | | $this->css_added = true; |
| | | } |
| | | |
| | | /** |
| | | * Template object for key info/edit frame. |
| | | * |
| | | * @param array Object attributes |
| | | * |
| | | * @return string HTML output |
| | | */ |
| | | function tpl_key_frame($attrib) |
| | | { |
| | | if (!$attrib['id']) { |
| | | $attrib['id'] = 'rcmkeysframe'; |
| | | } |
| | | |
| | | $attrib['name'] = $attrib['id']; |
| | | |
| | | $this->rc->output->set_env('contentframe', $attrib['name']); |
| | | $this->rc->output->set_env('blankpage', $attrib['src'] ? |
| | | $this->rc->output->abs_url($attrib['src']) : 'program/blank.gif'); |
| | | |
| | | return html::tag('iframe', $attrib); |
| | | } |
| | | |
| | | /** |
| | | * Template object for list of keys. |
| | | * |
| | | * @param array Object attributes |
| | | * |
| | | * @return string HTML content |
| | | */ |
| | | function tpl_keys_list($attrib) |
| | | { |
| | | // add id to message list table if not specified |
| | | if (!strlen($attrib['id'])) { |
| | | $attrib['id'] = 'rcmenigmakeyslist'; |
| | | } |
| | | |
| | | // define list of cols to be displayed |
| | | $a_show_cols = array('name'); |
| | | |
| | | // create XHTML table |
| | | $out = rcube_table_output($attrib, array(), $a_show_cols, 'id'); |
| | | |
| | | // set client env |
| | | $this->rc->output->add_gui_object('keyslist', $attrib['id']); |
| | | $this->rc->output->include_script('list.js'); |
| | | |
| | | // add some labels to client |
| | | $this->rc->output->add_label('enigma.keyconfirmdelete'); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Key listing (and searching) request handler |
| | | */ |
| | | private function key_list() |
| | | { |
| | | $this->enigma->load_engine(); |
| | | |
| | | $pagesize = $this->rc->config->get('pagesize', 100); |
| | | $page = max(intval(get_input_value('_p', RCUBE_INPUT_GPC)), 1); |
| | | $search = get_input_value('_q', RCUBE_INPUT_GPC); |
| | | |
| | | // define list of cols to be displayed |
| | | $a_show_cols = array('name'); |
| | | $result = array(); |
| | | |
| | | // Get the list |
| | | $list = $this->enigma->engine->list_keys($search); |
| | | |
| | | if ($list && ($list instanceof enigma_error)) |
| | | $this->rc->output->show_message('enigma.keylisterror', 'error'); |
| | | else if (empty($list)) |
| | | $this->rc->output->show_message('enigma.nokeysfound', 'notice'); |
| | | else { |
| | | if (is_array($list)) { |
| | | // Save the size |
| | | $listsize = count($list); |
| | | |
| | | // Sort the list by key (user) name |
| | | usort($list, array('enigma_key', 'cmp')); |
| | | |
| | | // Slice current page |
| | | $list = array_slice($list, ($page - 1) * $pagesize, $pagesize); |
| | | |
| | | $size = count($list); |
| | | |
| | | // Add rows |
| | | foreach($list as $idx => $key) { |
| | | $this->rc->output->command('enigma_add_list_row', |
| | | array('name' => Q($key->name), 'id' => $key->id)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | $this->rc->output->set_env('search_request', $search); |
| | | $this->rc->output->set_env('pagecount', ceil($listsize/$pagesize)); |
| | | $this->rc->output->set_env('current_page', $page); |
| | | $this->rc->output->command('set_rowcount', |
| | | $this->get_rowcount_text($listsize, $size, $page)); |
| | | |
| | | $this->rc->output->send(); |
| | | } |
| | | |
| | | /** |
| | | * Template object for list records counter. |
| | | * |
| | | * @param array Object attributes |
| | | * |
| | | * @return string HTML output |
| | | */ |
| | | function tpl_keys_rowcount($attrib) |
| | | { |
| | | if (!$attrib['id']) |
| | | $attrib['id'] = 'rcmcountdisplay'; |
| | | |
| | | $this->rc->output->add_gui_object('countdisplay', $attrib['id']); |
| | | |
| | | return html::span($attrib, $this->get_rowcount_text()); |
| | | } |
| | | |
| | | /** |
| | | * Returns text representation of list records counter |
| | | */ |
| | | private function get_rowcount_text($all=0, $curr_count=0, $page=1) |
| | | { |
| | | if (!$curr_count) |
| | | $out = $this->enigma->gettext('nokeysfound'); |
| | | else { |
| | | $pagesize = $this->rc->config->get('pagesize', 100); |
| | | $first = ($page - 1) * $pagesize; |
| | | |
| | | $out = $this->enigma->gettext(array( |
| | | 'name' => 'keysfromto', |
| | | 'vars' => array( |
| | | 'from' => $first + 1, |
| | | 'to' => $first + $curr_count, |
| | | 'count' => $all) |
| | | )); |
| | | } |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Key information page handler |
| | | */ |
| | | private function key_info() |
| | | { |
| | | $id = get_input_value('_id', RCUBE_INPUT_GET); |
| | | |
| | | $this->enigma->load_engine(); |
| | | $res = $this->enigma->engine->get_key($id); |
| | | |
| | | if ($res instanceof enigma_key) |
| | | $this->data = $res; |
| | | else { // error |
| | | $this->rc->output->show_message('enigma.keyopenerror', 'error'); |
| | | $this->rc->output->command('parent.enigma_loadframe'); |
| | | $this->rc->output->send('iframe'); |
| | | } |
| | | |
| | | $this->rc->output->add_handlers(array( |
| | | 'keyname' => array($this, 'tpl_key_name'), |
| | | 'keydata' => array($this, 'tpl_key_data'), |
| | | )); |
| | | |
| | | $this->rc->output->set_pagetitle($this->enigma->gettext('keyinfo')); |
| | | $this->rc->output->send('enigma.keyinfo'); |
| | | } |
| | | |
| | | /** |
| | | * Template object for key name |
| | | */ |
| | | function tpl_key_name($attrib) |
| | | { |
| | | return Q($this->data->name); |
| | | } |
| | | |
| | | /** |
| | | * Template object for key information page content |
| | | */ |
| | | function tpl_key_data($attrib) |
| | | { |
| | | $out = ''; |
| | | $table = new html_table(array('cols' => 2)); |
| | | |
| | | // Key user ID |
| | | $table->add('title', $this->enigma->gettext('keyuserid')); |
| | | $table->add(null, Q($this->data->name)); |
| | | // Key ID |
| | | $table->add('title', $this->enigma->gettext('keyid')); |
| | | $table->add(null, $this->data->subkeys[0]->get_short_id()); |
| | | // Key type |
| | | $keytype = $this->data->get_type(); |
| | | if ($keytype == enigma_key::TYPE_KEYPAIR) |
| | | $type = $this->enigma->gettext('typekeypair'); |
| | | else if ($keytype == enigma_key::TYPE_PUBLIC) |
| | | $type = $this->enigma->gettext('typepublickey'); |
| | | $table->add('title', $this->enigma->gettext('keytype')); |
| | | $table->add(null, $type); |
| | | // Key fingerprint |
| | | $table->add('title', $this->enigma->gettext('fingerprint')); |
| | | $table->add(null, $this->data->subkeys[0]->get_fingerprint()); |
| | | |
| | | $out .= html::tag('fieldset', null, |
| | | html::tag('legend', null, |
| | | $this->enigma->gettext('basicinfo')) . $table->show($attrib)); |
| | | |
| | | // Subkeys |
| | | $table = new html_table(array('cols' => 6)); |
| | | // Columns: Type, ID, Algorithm, Size, Created, Expires |
| | | |
| | | $out .= html::tag('fieldset', null, |
| | | html::tag('legend', null, |
| | | $this->enigma->gettext('subkeys')) . $table->show($attrib)); |
| | | |
| | | // Additional user IDs |
| | | $table = new html_table(array('cols' => 2)); |
| | | // Columns: User ID, Validity |
| | | |
| | | $out .= html::tag('fieldset', null, |
| | | html::tag('legend', null, |
| | | $this->enigma->gettext('userids')) . $table->show($attrib)); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | /** |
| | | * Key import page handler |
| | | */ |
| | | private function key_import() |
| | | { |
| | | // Import process |
| | | if ($_FILES['_file']['tmp_name'] && is_uploaded_file($_FILES['_file']['tmp_name'])) { |
| | | $this->enigma->load_engine(); |
| | | $result = $this->enigma->engine->import_key($_FILES['_file']['tmp_name'], true); |
| | | |
| | | if (is_array($result)) { |
| | | // reload list if any keys has been added |
| | | if ($result['imported']) { |
| | | $this->rc->output->command('parent.enigma_list', 1); |
| | | } |
| | | else |
| | | $this->rc->output->command('parent.enigma_loadframe'); |
| | | |
| | | $this->rc->output->show_message('enigma.keysimportsuccess', 'confirmation', |
| | | array('new' => $result['imported'], 'old' => $result['unchanged'])); |
| | | |
| | | $this->rc->output->send('iframe'); |
| | | } |
| | | else |
| | | $this->rc->output->show_message('enigma.keysimportfailed', 'error'); |
| | | } |
| | | else if ($err = $_FILES['_file']['error']) { |
| | | if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) { |
| | | $this->rc->output->show_message('filesizeerror', 'error', |
| | | array('size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))); |
| | | } else { |
| | | $this->rc->output->show_message('fileuploaderror', 'error'); |
| | | } |
| | | } |
| | | |
| | | $this->rc->output->add_handlers(array( |
| | | 'importform' => array($this, 'tpl_key_import_form'), |
| | | )); |
| | | |
| | | $this->rc->output->set_pagetitle($this->enigma->gettext('keyimport')); |
| | | $this->rc->output->send('enigma.keyimport'); |
| | | } |
| | | |
| | | /** |
| | | * Template object for key import (upload) form |
| | | */ |
| | | function tpl_key_import_form($attrib) |
| | | { |
| | | $attrib += array('id' => 'rcmKeyImportForm'); |
| | | |
| | | $upload = new html_inputfield(array('type' => 'file', 'name' => '_file', |
| | | 'id' => 'rcmimportfile', 'size' => 30)); |
| | | |
| | | $form = html::p(null, |
| | | Q($this->enigma->gettext('keyimporttext'), 'show') |
| | | . html::br() . html::br() . $upload->show() |
| | | ); |
| | | |
| | | $this->rc->output->add_label('selectimportfile', 'importwait'); |
| | | $this->rc->output->add_gui_object('importform', $attrib['id']); |
| | | |
| | | $out = $this->rc->output->form_tag(array( |
| | | 'action' => $this->rc->url(array('action' => 'plugin.enigma', 'a' => 'keyimport')), |
| | | 'method' => 'post', |
| | | 'enctype' => 'multipart/form-data') + $attrib, |
| | | $form); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | private function compose_ui() |
| | | { |
| | | if (!is_array($_SESSION['compose']) || $_SESSION['compose']['id'] != get_input_value('_id', RCUBE_INPUT_GET)) |
| | | return; |
| | | |
| | | // Options menu button |
| | | // @TODO: make this work with non-default skins |
| | | $this->enigma->add_button(array( |
| | | 'name' => 'enigmamenu', |
| | | 'imagepas' => 'skins/default/enigma.png', |
| | | 'imageact' => 'skins/default/enigma.png', |
| | | 'onclick' => "rcmail_ui.show_popup('enigmamenu', true); return false", |
| | | 'title' => 'securityoptions', |
| | | 'domain' => 'enigma', |
| | | ), 'toolbar'); |
| | | |
| | | // Options menu contents |
| | | $this->enigma->add_hook('render_page', array($this, 'compose_menu')); |
| | | } |
| | | |
| | | function compose_menu($p) |
| | | { |
| | | $menu = new html_table(array('cols' => 2)); |
| | | $chbox = new html_checkbox(array('value' => 1)); |
| | | |
| | | $menu->add(null, html::label(array('for' => 'enigmadefaultopt'), |
| | | Q($this->enigma->gettext('identdefault')))); |
| | | $menu->add(null, $chbox->show(1, array('name' => '_enigma_default', 'id' => 'enigmadefaultopt'))); |
| | | |
| | | $menu->add(null, html::label(array('for' => 'enigmasignopt'), |
| | | Q($this->enigma->gettext('signmsg')))); |
| | | $menu->add(null, $chbox->show(1, array('name' => '_enigma_sign', 'id' => 'enigmasignopt'))); |
| | | |
| | | $menu->add(null, html::label(array('for' => 'enigmacryptopt'), |
| | | Q($this->enigma->gettext('encryptmsg')))); |
| | | $menu->add(null, $chbox->show(1, array('name' => '_enigma_crypt', 'id' => 'enigmacryptopt'))); |
| | | |
| | | $menu = html::div(array('id' => 'enigmamenu', 'class' => 'popupmenu'), |
| | | $menu->show()); |
| | | |
| | | $p['content'] = preg_replace('/(<form name="form"[^>]+>)/i', '\\1'."\n$menu", $p['content']); |
| | | |
| | | return $p; |
| | | |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | /* |
| | | +-------------------------------------------------------------------------+ |
| | | | User ID class for the Enigma Plugin | |
| | | | | |
| | | | This program is free software; you can redistribute it and/or modify | |
| | | | it under the terms of the GNU General Public License version 2 | |
| | | | as published by the Free Software Foundation. | |
| | | | | |
| | | | This program 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 this program; if not, write to the Free Software Foundation, Inc., | |
| | | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| | | | | |
| | | +-------------------------------------------------------------------------+ |
| | | | Author: Aleksander Machniak <alec@alec.pl> | |
| | | +-------------------------------------------------------------------------+ |
| | | */ |
| | | |
| | | class enigma_userid |
| | | { |
| | | public $revoked; |
| | | public $valid; |
| | | public $name; |
| | | public $comment; |
| | | public $email; |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['enigmasettings'] = 'Enigma: Settings'; |
| | | $labels['enigmacerts'] = 'Enigma: Certificates (S/MIME)'; |
| | | $labels['enigmakeys'] = 'Enigma: Keys (PGP)'; |
| | | $labels['keysfromto'] = 'Keys $from to $to of $count'; |
| | | $labels['keyname'] = 'Name'; |
| | | $labels['keyid'] = 'Key ID'; |
| | | $labels['keyuserid'] = 'User ID'; |
| | | $labels['keytype'] = 'Key type'; |
| | | $labels['fingerprint'] = 'Fingerprint'; |
| | | $labels['subkeys'] = 'Subkeys'; |
| | | $labels['basicinfo'] = 'Basic Information'; |
| | | $labels['userids'] = 'Additional User IDs'; |
| | | $labels['typepublickey'] = 'public key'; |
| | | $labels['typekeypair'] = 'key pair'; |
| | | $labels['keyattfound'] = 'This message contains attached PGP key(s).'; |
| | | $labels['keyattimport'] = 'Import key(s)'; |
| | | |
| | | $labels['createkeys'] = 'Create a new key pair'; |
| | | $labels['importkeys'] = 'Import key(s)'; |
| | | $labels['exportkeys'] = 'Export key(s)'; |
| | | $labels['deletekeys'] = 'Delete key(s)'; |
| | | $labels['keyactions'] = 'Key actions...'; |
| | | $labels['keydisable'] = 'Disable key'; |
| | | $labels['keyrevoke'] = 'Revoke key'; |
| | | $labels['keysend'] = 'Send public key in a message'; |
| | | $labels['keychpass'] = 'Change password'; |
| | | |
| | | $labels['securityoptions'] = 'Message security options...'; |
| | | $labels['identdefault'] = 'Use settings of selected identity'; |
| | | $labels['encryptmsg'] = 'Encrypt this message'; |
| | | $labels['signmsg'] = 'Digitally sign this message'; |
| | | |
| | | $messages = array(); |
| | | $messages['sigvalid'] = 'Verified signature from $sender.'; |
| | | $messages['siginvalid'] = 'Invalid signature from $sender.'; |
| | | $messages['signokey'] = 'Unverified signature. Public key not found. Key ID: $keyid.'; |
| | | $messages['sigerror'] = 'Unverified signature. Internal error.'; |
| | | $messages['decryptok'] = 'Message decrypted.'; |
| | | $messages['decrypterror'] = 'Decryption failed.'; |
| | | $messages['decryptnokey'] = 'Decryption failed. Private key not found. Key ID: $keyid.'; |
| | | $messages['decryptbadpass'] = 'Decryption failed. Bad password.'; |
| | | $messages['nokeysfound'] = 'No keys found'; |
| | | $messages['keyopenerror'] = 'Unable to get key information! Internal error.'; |
| | | $messages['keylisterror'] = 'Unable to list keys! Internal error.'; |
| | | $messages['keysimportfailed'] = 'Unable to import key(s)! Internal error.'; |
| | | $messages['keysimportsuccess'] = 'Key(s) imported successfully. Imported: $new, unchanged: $old.'; |
| | | $messages['keyconfirmdelete'] = 'Are you sure, you want to delete selected key(s)?'; |
| | | $messages['keyimporttext'] = 'You can import private and public key(s) or revocation signatures in ASCII-Armor format.'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // EN-Revision: 4203 |
| | | |
| | | $labels = array(); |
| | | $labels['enigmasettings'] = 'Enigma: 設定'; |
| | | $labels['enigmacerts'] = 'Enigma: 証明書 (S/MIME)'; |
| | | $labels['enigmakeys'] = 'Enigma: 鍵 (PGP)'; |
| | | $labels['keysfromto'] = '鍵の一覧 $from ~ $to (合計: $count )'; |
| | | $labels['keyname'] = '名前'; |
| | | $labels['keyid'] = '鍵 ID'; |
| | | $labels['keyuserid'] = 'ユーザー ID'; |
| | | $labels['keytype'] = '鍵の種類'; |
| | | $labels['fingerprint'] = '指紋'; |
| | | $labels['subkeys'] = 'Subkeys'; |
| | | $labels['basicinfo'] = '基本情報'; |
| | | $labels['userids'] = '追加のユーザー ID'; |
| | | $labels['typepublickey'] = '公開鍵'; |
| | | $labels['typekeypair'] = '鍵のペア'; |
| | | $labels['keyattfound'] = 'このメールは PGP 鍵の添付があります。'; |
| | | $labels['keyattimport'] = '鍵のインポート'; |
| | | |
| | | $labels['createkeys'] = '新しい鍵のペアを作成する'; |
| | | $labels['importkeys'] = '鍵のインポート'; |
| | | $labels['exportkeys'] = '鍵のエクスポート'; |
| | | $labels['deletekeys'] = '鍵の削除'; |
| | | $labels['keyactions'] = '鍵の操作...'; |
| | | $labels['keydisable'] = '鍵を無効にする'; |
| | | $labels['keyrevoke'] = '鍵を取り消す'; |
| | | $labels['keysend'] = 'メッセージに公開鍵を含んで送信する'; |
| | | $labels['keychpass'] = 'パスワードの変更'; |
| | | |
| | | $labels['securityoptions'] = 'メールのセキュリティ オプション...'; |
| | | $labels['identdefault'] = '選択した識別子の設定を使う'; |
| | | $labels['encryptmsg'] = 'このメールの暗号化'; |
| | | $labels['signmsg'] = 'このメールのデジタル署名'; |
| | | |
| | | $messages = array(); |
| | | $messages['sigvalid'] = '$sender からの署名を検証しました。'; |
| | | $messages['siginvalid'] = '$sender からの署名が正しくありません。'; |
| | | $messages['signokey'] = '署名は未検証です。公開鍵が見つかりません。鍵 ID: $keyid'; |
| | | $messages['sigerror'] = '署名は未検証です。内部エラーです。'; |
| | | $messages['decryptok'] = 'メールを復号しました。'; |
| | | $messages['decrypterror'] = '復号に失敗しました。'; |
| | | $messages['decryptnokey'] = '復号に失敗しました。秘密鍵が見つかりません。鍵 ID: $keyid.'; |
| | | $messages['decryptbadpass'] = '復号に失敗しました。パスワードが正しくありません。'; |
| | | $messages['nokeysfound'] = '鍵が見つかりません。'; |
| | | $messages['keyopenerror'] = '鍵情報の取得に失敗しました! 内部エラーです。'; |
| | | $messages['keylisterror'] = '鍵情報のリストに失敗しました! 内部エラーです。'; |
| | | $messages['keysimportfailed'] = '鍵のインポートに失敗しました! 内部エラーです。'; |
| | | $messages['keysimportsuccess'] = '鍵をインポートしました。インポート: $new, 未変更: $old'; |
| | | $messages['keyconfirmdelete'] = '選択した鍵を本当に削除しますか?'; |
| | | $messages['keyimporttext'] = '秘密鍵と公開鍵のインポート、または ASCII 形式の署名を無効にできます。'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | /* |
| | | |
| | | +-----------------------------------------------------------------------+ |
| | | | plugins/enigma/localization/ru_RU.inc | |
| | | | | |
| | | | Russian translation for roundcube/enigma plugin | |
| | | | Copyright (C) 2010 | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Sergey Dukachev <iam@dukess.ru> | |
| | | | Updates: | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | @version 2010-12-23 |
| | | |
| | | */ |
| | | |
| | | $labels = array(); |
| | | $labels['enigmasettings'] = 'Enigma: Настройки'; |
| | | $labels['enigmacerts'] = 'Enigma: Сертификаты (S/MIME)'; |
| | | $labels['enigmakeys'] = 'Enigma: Ключи (PGP)'; |
| | | $labels['keysfromto'] = 'Ключи от $from к $to в количестве $count'; |
| | | $labels['keyname'] = 'Имя'; |
| | | $labels['keyid'] = 'Идентификатор ключа'; |
| | | $labels['keyuserid'] = 'Идентификатор пользователя'; |
| | | $labels['keytype'] = 'Тип ключа'; |
| | | $labels['fingerprint'] = 'Отпечаток (хэш) ключа'; |
| | | $labels['subkeys'] = 'Подразделы'; |
| | | $labels['basicinfo'] = 'Основные сведения'; |
| | | $labels['userids'] = 'Дополнительные идентификаторы пользователя'; |
| | | $labels['typepublickey'] = 'Открытый ключ'; |
| | | $labels['typekeypair'] = 'пара ключей'; |
| | | $labels['keyattfound'] = 'Это сообщение содержит один или несколько ключей PGP.'; |
| | | $labels['keyattimport'] = 'Импортировать ключи'; |
| | | |
| | | $labels['createkeys'] = 'Создать новую пару ключей'; |
| | | $labels['importkeys'] = 'Импортировать ключ(и)'; |
| | | $labels['exportkeys'] = 'Экспортировать ключ(и)'; |
| | | $labels['deletekeys'] = 'Удалить ключ(и)'; |
| | | $labels['keyactions'] = 'Действия с ключами...'; |
| | | $labels['keydisable'] = 'Отключить ключ'; |
| | | $labels['keyrevoke'] = 'Отозвать ключ'; |
| | | $labels['keysend'] = 'Отправить публичный ключ в собщении'; |
| | | $labels['keychpass'] = 'Изменить пароль'; |
| | | |
| | | $messages = array(); |
| | | $messages['sigvalid'] = 'Проверенная подпись у $sender.'; |
| | | $messages['siginvalid'] = 'Неверная подпись у $sender.'; |
| | | $messages['signokey'] = 'Непроверяемая подпись. Открытый ключ не найден. Идентификатор ключа: $keyid.'; |
| | | $messages['sigerror'] = 'Непроверяемая подпись. Внутренняя ошибка.'; |
| | | $messages['decryptok'] = 'Сообщение расшифровано.'; |
| | | $messages['decrypterror'] = 'Расшифровка не удалась.'; |
| | | $messages['decryptnokey'] = 'Расшифровка не удалась. Секретный ключ не найден. Идентификатор ключа: $keyid.'; |
| | | $messages['decryptbadpass'] = 'Расшифровка не удалась. Неправильный пароль.'; |
| | | $messages['nokeysfound'] = 'Ключи не найдены'; |
| | | $messages['keyopenerror'] = 'Невозможно получить информацию о ключе! Внутренняя ошибка.'; |
| | | $messages['keylisterror'] = 'Невозможно сделать список ключей! Внутренняя ошибка.'; |
| | | $messages['keysimportfailed'] = 'Невозможно импортировать ключ(и)! Внутренняя ошибка.'; |
| | | $messages['keysimportsuccess'] = 'Ключи успешно импортированы. Импортировано: $new, без изменений: $old.'; |
| | | $messages['keyconfirmdelete'] = 'Вы точно хотите удалить выбранные ключи?'; |
| | | $messages['keyimporttext'] = 'Вы можете импортировать открытые и секретные ключи или сообщения об отзыве ключей в формате ASCII-Armor.'; |
| | | |
| | | ?> |
New file |
| | |
| | | /*** Style for Enigma plugin ***/ |
| | | |
| | | /***** Messages displaying *****/ |
| | | |
| | | #enigma-message, |
| | | /* fixes border-top */ |
| | | #messagebody div #enigma-message |
| | | { |
| | | margin: 0; |
| | | margin-bottom: 5px; |
| | | min-height: 20px; |
| | | padding: 10px 10px 6px 46px; |
| | | } |
| | | |
| | | div.enigmaerror, |
| | | /* fixes border-top */ |
| | | #messagebody div.enigmaerror |
| | | { |
| | | background: url(enigma_error.png) 6px 1px no-repeat; |
| | | background-color: #EF9398; |
| | | border: 1px solid #DC5757; |
| | | } |
| | | |
| | | div.enigmanotice, |
| | | /* fixes border-top */ |
| | | #messagebody div.enigmanotice |
| | | { |
| | | background: url(enigma.png) 6px 1px no-repeat; |
| | | background-color: #A6EF7B; |
| | | border: 1px solid #76C83F; |
| | | } |
| | | |
| | | div.enigmawarning, |
| | | /* fixes border-top */ |
| | | #messagebody div.enigmawarning |
| | | { |
| | | background: url(enigma.png) 6px 1px no-repeat; |
| | | background-color: #F7FDCB; |
| | | border: 1px solid #C2D071; |
| | | } |
| | | |
| | | #enigma-message a |
| | | { |
| | | color: #666666; |
| | | padding-left: 10px; |
| | | } |
| | | |
| | | #enigma-message a:hover |
| | | { |
| | | color: #333333; |
| | | } |
| | | |
| | | /***** Keys/Certs Management *****/ |
| | | |
| | | div.enigmascreen |
| | | { |
| | | position: absolute; |
| | | top: 65px; |
| | | right: 10px; |
| | | bottom: 10px; |
| | | left: 10px; |
| | | } |
| | | |
| | | #enigmacontent-box |
| | | { |
| | | position: absolute; |
| | | top: 0px; |
| | | left: 290px; |
| | | right: 0px; |
| | | bottom: 0px; |
| | | border: 1px solid #999999; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | #enigmakeyslist |
| | | { |
| | | position: absolute; |
| | | top: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | border: 1px solid #999999; |
| | | background-color: #F9F9F9; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | #keylistcountbar |
| | | { |
| | | margin-top: 4px; |
| | | margin-left: 4px; |
| | | } |
| | | |
| | | #keys-table |
| | | { |
| | | width: 100%; |
| | | table-layout: fixed; |
| | | } |
| | | |
| | | #keys-table td |
| | | { |
| | | cursor: default; |
| | | text-overflow: ellipsis; |
| | | -o-text-overflow: ellipsis; |
| | | } |
| | | |
| | | #key-details table td.title |
| | | { |
| | | font-weight: bold; |
| | | text-align: right; |
| | | } |
| | | |
| | | #keystoolbar |
| | | { |
| | | position: absolute; |
| | | top: 30px; |
| | | left: 10px; |
| | | height: 35px; |
| | | } |
| | | |
| | | #keystoolbar a |
| | | { |
| | | padding-right: 10px; |
| | | } |
| | | |
| | | #keystoolbar a.button, |
| | | #keystoolbar a.buttonPas, |
| | | #keystoolbar span.separator { |
| | | display: block; |
| | | float: left; |
| | | width: 32px; |
| | | height: 32px; |
| | | padding: 0; |
| | | margin-right: 10px; |
| | | overflow: hidden; |
| | | background: url(keys_toolbar.png) 0 0 no-repeat transparent; |
| | | opacity: 0.99; /* this is needed to make buttons appear correctly in Chrome */ |
| | | } |
| | | |
| | | #keystoolbar a.buttonPas { |
| | | opacity: 0.35; |
| | | } |
| | | |
| | | #keystoolbar a.createSel { |
| | | background-position: 0 -32px; |
| | | } |
| | | |
| | | #keystoolbar a.create { |
| | | background-position: 0 0; |
| | | } |
| | | |
| | | #keystoolbar a.deleteSel { |
| | | background-position: -32px -32px; |
| | | } |
| | | |
| | | #keystoolbar a.delete { |
| | | background-position: -32px 0; |
| | | } |
| | | |
| | | #keystoolbar a.importSel { |
| | | background-position: -64px -32px; |
| | | } |
| | | |
| | | #keystoolbar a.import { |
| | | background-position: -64px 0; |
| | | } |
| | | |
| | | #keystoolbar a.exportSel { |
| | | background-position: -96px -32px; |
| | | } |
| | | |
| | | #keystoolbar a.export { |
| | | background-position: -96px 0; |
| | | } |
| | | |
| | | #keystoolbar a.keymenu { |
| | | background-position: -128px 0; |
| | | width: 36px; |
| | | } |
| | | |
| | | #keystoolbar span.separator { |
| | | width: 5px; |
| | | background-position: -166px 0; |
| | | } |
New file |
| | |
| | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| | | <html xmlns="http://www.w3.org/1999/xhtml"> |
| | | <head> |
| | | <title><roundcube:object name="pagetitle" /></title> |
| | | <roundcube:include file="/includes/links.html" /> |
| | | <link rel="stylesheet" type="text/css" href="/this/enigma.css" /> |
| | | </head> |
| | | <body class="iframe"> |
| | | |
| | | <div id="keyimport-title" class="boxtitle"><roundcube:label name="enigma.importkeys" /></div> |
| | | |
| | | <div id="import-form" class="boxcontent"> |
| | | <roundcube:object name="importform" /> |
| | | <p> |
| | | <br /><roundcube:button command="plugin.enigma-import" type="input" class="button mainaction" label="import" /> |
| | | </p> |
| | | </div> |
| | | |
| | | </body> |
| | | </html> |
New file |
| | |
| | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| | | <html xmlns="http://www.w3.org/1999/xhtml"> |
| | | <head> |
| | | <title><roundcube:object name="pagetitle" /></title> |
| | | <roundcube:include file="/includes/links.html" /> |
| | | <link rel="stylesheet" type="text/css" href="/this/enigma.css" /> |
| | | </head> |
| | | <body class="iframe"> |
| | | |
| | | <div id="keyinfo-title" class="boxtitle"><roundcube:object name="keyname" part="name" /></div> |
| | | |
| | | <div id="key-details" class="boxcontent"> |
| | | <roundcube:object name="keydata" /> |
| | | </div> |
| | | |
| | | </body> |
| | | </html> |
New file |
| | |
| | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| | | <html xmlns="http://www.w3.org/1999/xhtml"> |
| | | <head> |
| | | <title><roundcube:object name="pagetitle" /></title> |
| | | <roundcube:include file="/includes/links.html" /> |
| | | <link rel="stylesheet" type="text/css" href="/this/enigma.css" /> |
| | | <script type="text/javascript" src="/functions.js"></script> |
| | | <script type="text/javascript" src="/splitter.js"></script> |
| | | <style type="text/css"> |
| | | #enigmakeyslist { width: <roundcube:exp expression="!empty(cookie:enigmaviewsplitter) ? cookie:enigmaviewsplitter-5 : 210" />px; } |
| | | #enigmacontent-box { left: <roundcube:exp expression="!empty(cookie:enigmaviewsplitter) ? cookie:enigmaviewsplitter+5 : 220" />px; |
| | | <roundcube:exp expression="browser:ie ? ('width:expression((parseInt(this.parentNode.offsetWidth)-'.(!empty(cookie:enigmaeviewsplitter) ? cookie:enigmaviewsplitter+5 : 220).')+\\'px\\');') : ''" /> |
| | | } |
| | | </style> |
| | | </head> |
| | | <body class="iframe" onload="rcube_init_mail_ui()"> |
| | | |
| | | <div id="prefs-title" class="boxtitle"><roundcube:label name="enigma.enigmakeys" /></div> |
| | | <div id="prefs-details" class="boxcontent"> |
| | | |
| | | <div id="keystoolbar"> |
| | | <roundcube:button command="plugin.enigma-key-create" type="link" class="buttonPas create" classAct="button create" classSel="button createSel" title="enigma.createkeys" content=" " /> |
| | | <roundcube:button command="plugin.enigma-key-delete" type="link" class="buttonPas delete" classAct="button delete" classSel="button deleteSel" title="enigma.deletekeys" content=" " /> |
| | | <span class="separator"> </span> |
| | | <roundcube:button command="plugin.enigma-key-import" type="link" class="buttonPas import" classAct="button import" classSel="button importSel" title="enigma.importkeys" content=" " /> |
| | | <roundcube:button command="plugin.enigma-key-export" type="link" class="buttonPas export" classAct="button export" classSel="button exportSel" title="enigma.exportkeys" content=" " /> |
| | | <roundcube:button name="messagemenulink" id="messagemenulink" type="link" class="button keymenu" title="enigma.keyactions" onclick="rcmail_ui.show_popup('messagemenu');return false" content=" " /> |
| | | </div> |
| | | |
| | | <div id="quicksearchbar" style="top: 35px; right: 10px;"> |
| | | <roundcube:button name="searchmenulink" id="searchmenulink" image="/images/icons/glass.png" /> |
| | | <roundcube:object name="searchform" id="quicksearchbox" /> |
| | | <roundcube:button command="reset-search" id="searchreset" image="/images/icons/reset.gif" title="resetsearch" /> |
| | | </div> |
| | | |
| | | <div class="enigmascreen"> |
| | | |
| | | <div id="enigmakeyslist"> |
| | | <div class="boxtitle"><roundcube:label name="enigma.keyname" /></div> |
| | | <div class="boxlistcontent"> |
| | | <roundcube:object name="keyslist" id="keys-table" class="records-table" cellspacing="0" noheader="true" /> |
| | | </div> |
| | | <div class="boxfooter"> |
| | | <div id="keylistcountbar" class="pagenav"> |
| | | <roundcube:button command="firstpage" type="link" class="buttonPas firstpage" classAct="button firstpage" classSel="button firstpageSel" title="firstpage" content=" " /> |
| | | <roundcube:button command="previouspage" type="link" class="buttonPas prevpage" classAct="button prevpage" classSel="button prevpageSel" title="previouspage" content=" " /> |
| | | <roundcube:object name="countdisplay" style="padding:0 .5em; float:left" /> |
| | | <roundcube:button command="nextpage" type="link" class="buttonPas nextpage" classAct="button nextpage" classSel="button nextpageSel" title="nextpage" content=" " /> |
| | | <roundcube:button command="lastpage" type="link" class="buttonPas lastpage" classAct="button lastpage" classSel="button lastpageSel" title="lastpage" content=" " /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <script type="text/javascript"> |
| | | var enigmaviewsplit = new rcube_splitter({id:'enigmaviewsplitter', p1: 'enigmakeyslist', p2: 'enigmacontent-box', orientation: 'v', relative: true, start: 215}); |
| | | rcmail.add_onload('enigmaviewsplit.init()'); |
| | | </script> |
| | | |
| | | <div id="enigmacontent-box"> |
| | | <roundcube:object name="keyframe" id="keyframe" width="100%" height="100%" frameborder="0" src="/watermark.html" /> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | |
| | | <div id="messagemenu" class="popupmenu"> |
| | | <ul class="toolbarmenu"> |
| | | <li><roundcube:button class="disablelink" command="enigma.key-disable" label="enigma.keydisable" target="_blank" classAct="disablelink active" /></li> |
| | | <li><roundcube:button class="revokelink" command="enigma.key-revoke" label="enigma.keyrevoke" classAct="revokelink active" /></li> |
| | | <li class="separator_below"><roundcube:button class="sendlink" command="enigma.key-send" label="enigma.keysend" classAct="sendlink active" /></li> |
| | | <li><roundcube:button class="chpasslink" command="enigma.key-chpass" label="enigma.keychpass" classAct="chpasslink active" /></li> |
| | | </ul> |
| | | </div> |
| | | |
| | | </body> |
| | | </html> |
New file |
| | |
| | | <?php |
| | | |
| | | require_once(dirname(__FILE__) . '/example_addressbook_backend.php'); |
| | | |
| | | /** |
| | | * Sample plugin to add a new address book |
| | | * with just a static list of contacts |
| | | */ |
| | | class example_addressbook extends rcube_plugin |
| | | { |
| | | private $abook_id = 'static'; |
| | | private $abook_name = 'Static List'; |
| | | |
| | | public function init() |
| | | { |
| | | $this->add_hook('addressbooks_list', array($this, 'address_sources')); |
| | | $this->add_hook('addressbook_get', array($this, 'get_address_book')); |
| | | |
| | | // use this address book for autocompletion queries |
| | | // (maybe this should be configurable by the user?) |
| | | $config = rcmail::get_instance()->config; |
| | | $sources = (array) $config->get('autocomplete_addressbooks', array('sql')); |
| | | if (!in_array($this->abook_id, $sources)) { |
| | | $sources[] = $this->abook_id; |
| | | $config->set('autocomplete_addressbooks', $sources); |
| | | } |
| | | } |
| | | |
| | | public function address_sources($p) |
| | | { |
| | | $abook = new example_addressbook_backend($this->abook_name); |
| | | $p['sources'][$this->abook_id] = array( |
| | | 'id' => $this->abook_id, |
| | | 'name' => $this->abook_name, |
| | | 'readonly' => $abook->readonly, |
| | | 'groups' => $abook->groups, |
| | | ); |
| | | return $p; |
| | | } |
| | | |
| | | public function get_address_book($p) |
| | | { |
| | | if ($p['id'] === $this->abook_id) { |
| | | $p['instance'] = new example_addressbook_backend($this->abook_name); |
| | | } |
| | | |
| | | return $p; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Example backend class for a custom address book |
| | | * |
| | | * This one just holds a static list of address records |
| | | * |
| | | * @author Thomas Bruederli |
| | | */ |
| | | class example_addressbook_backend extends rcube_addressbook |
| | | { |
| | | public $primary_key = 'ID'; |
| | | public $readonly = true; |
| | | public $groups = true; |
| | | |
| | | private $filter; |
| | | private $result; |
| | | private $name; |
| | | |
| | | public function __construct($name) |
| | | { |
| | | $this->ready = true; |
| | | $this->name = $name; |
| | | } |
| | | |
| | | public function get_name() |
| | | { |
| | | return $this->name; |
| | | } |
| | | |
| | | public function set_search_set($filter) |
| | | { |
| | | $this->filter = $filter; |
| | | } |
| | | |
| | | public function get_search_set() |
| | | { |
| | | return $this->filter; |
| | | } |
| | | |
| | | public function reset() |
| | | { |
| | | $this->result = null; |
| | | $this->filter = null; |
| | | } |
| | | |
| | | function list_groups($search = null) |
| | | { |
| | | return array( |
| | | array('ID' => 'testgroup1', 'name' => "Testgroup"), |
| | | array('ID' => 'testgroup2', 'name' => "Sample Group"), |
| | | ); |
| | | } |
| | | |
| | | public function list_records($cols=null, $subset=0) |
| | | { |
| | | $this->result = $this->count(); |
| | | $this->result->add(array('ID' => '111', 'name' => "Example Contact", 'firstname' => "Example", 'surname' => "Contact", 'email' => "example@roundcube.net")); |
| | | |
| | | return $this->result; |
| | | } |
| | | |
| | | public function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) |
| | | { |
| | | // no search implemented, just list all records |
| | | return $this->list_records(); |
| | | } |
| | | |
| | | public function count() |
| | | { |
| | | return new rcube_result_set(1, ($this->list_page-1) * $this->page_size); |
| | | } |
| | | |
| | | public function get_result() |
| | | { |
| | | return $this->result; |
| | | } |
| | | |
| | | public function get_record($id, $assoc=false) |
| | | { |
| | | $this->list_records(); |
| | | $first = $this->result->first(); |
| | | $sql_arr = $first['ID'] == $id ? $first : null; |
| | | |
| | | return $assoc && $sql_arr ? $sql_arr : $this->result; |
| | | } |
| | | |
| | | |
| | | function create_group($name) |
| | | { |
| | | $result = false; |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | function delete_group($gid) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | function rename_group($gid, $newname) |
| | | { |
| | | return $newname; |
| | | } |
| | | |
| | | function add_to_group($group_id, $ids) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | function remove_from_group($group_id, $ids) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | /** |
| | | * Filesystem Attachments |
| | | * |
| | | * This is a core plugin which provides basic, filesystem based |
| | | * attachment temporary file handling. This includes storing |
| | | * attachments of messages currently being composed, writing attachments |
| | | * to disk when drafts with attachments are re-opened and writing |
| | | * attachments to disk for inline display in current html compositions. |
| | | * |
| | | * Developers may wish to extend this class when creating attachment |
| | | * handler plugins: |
| | | * require_once('plugins/filesystem_attachments/filesystem_attachments.php'); |
| | | * class myCustom_attachments extends filesystem_attachments |
| | | * |
| | | * @author Ziba Scott <ziba@umich.edu> |
| | | * @author Thomas Bruederli <roundcube@gmail.com> |
| | | * |
| | | */ |
| | | class filesystem_attachments extends rcube_plugin |
| | | { |
| | | public $task = '?(?!login).*'; |
| | | |
| | | function init() |
| | | { |
| | | // Save a newly uploaded attachment |
| | | $this->add_hook('attachment_upload', array($this, 'upload')); |
| | | |
| | | // Save an attachment from a non-upload source (draft or forward) |
| | | $this->add_hook('attachment_save', array($this, 'save')); |
| | | |
| | | // Remove an attachment from storage |
| | | $this->add_hook('attachment_delete', array($this, 'remove')); |
| | | |
| | | // When composing an html message, image attachments may be shown |
| | | $this->add_hook('attachment_display', array($this, 'display')); |
| | | |
| | | // Get the attachment from storage and place it on disk to be sent |
| | | $this->add_hook('attachment_get', array($this, 'get')); |
| | | |
| | | // Delete all temp files associated with this user |
| | | $this->add_hook('attachments_cleanup', array($this, 'cleanup')); |
| | | $this->add_hook('session_destroy', array($this, 'cleanup')); |
| | | } |
| | | |
| | | /** |
| | | * Save a newly uploaded attachment |
| | | */ |
| | | function upload($args) |
| | | { |
| | | $args['status'] = false; |
| | | $group = $args['group']; |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | // use common temp dir for file uploads |
| | | $temp_dir = $rcmail->config->get('temp_dir'); |
| | | $tmpfname = tempnam($temp_dir, 'rcmAttmnt'); |
| | | |
| | | if (move_uploaded_file($args['path'], $tmpfname) && file_exists($tmpfname)) { |
| | | $args['id'] = $this->file_id(); |
| | | $args['path'] = $tmpfname; |
| | | $args['status'] = true; |
| | | |
| | | // Note the file for later cleanup |
| | | $_SESSION['plugins']['filesystem_attachments'][$group][] = $tmpfname; |
| | | } |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Save an attachment from a non-upload source (draft or forward) |
| | | */ |
| | | function save($args) |
| | | { |
| | | $group = $args['group']; |
| | | $args['status'] = false; |
| | | |
| | | if (!$args['path']) { |
| | | $rcmail = rcmail::get_instance(); |
| | | $temp_dir = $rcmail->config->get('temp_dir'); |
| | | $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); |
| | | |
| | | if ($fp = fopen($tmp_path, 'w')) { |
| | | fwrite($fp, $args['data']); |
| | | fclose($fp); |
| | | $args['path'] = $tmp_path; |
| | | } else |
| | | return $args; |
| | | } |
| | | |
| | | $args['id'] = $this->file_id(); |
| | | $args['status'] = true; |
| | | |
| | | // Note the file for later cleanup |
| | | $_SESSION['plugins']['filesystem_attachments'][$group][] = $args['path']; |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Remove an attachment from storage |
| | | * This is triggered by the remove attachment button on the compose screen |
| | | */ |
| | | function remove($args) |
| | | { |
| | | $args['status'] = @unlink($args['path']); |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * When composing an html message, image attachments may be shown |
| | | * For this plugin, the file is already in place, just check for |
| | | * the existance of the proper metadata |
| | | */ |
| | | function display($args) |
| | | { |
| | | $args['status'] = file_exists($args['path']); |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * This attachment plugin doesn't require any steps to put the file |
| | | * on disk for use. This stub function is kept here to make this |
| | | * class handy as a parent class for other plugins which may need it. |
| | | */ |
| | | function get($args) |
| | | { |
| | | return $args; |
| | | } |
| | | |
| | | /** |
| | | * Delete all temp files associated with this user |
| | | */ |
| | | function cleanup($args) |
| | | { |
| | | // $_SESSION['compose']['attachments'] is not a complete record of |
| | | // temporary files because loading a draft or starting a forward copies |
| | | // the file to disk, but does not make an entry in that array |
| | | if (is_array($_SESSION['plugins']['filesystem_attachments'])){ |
| | | foreach ($_SESSION['plugins']['filesystem_attachments'] as $group => $files) { |
| | | if ($args['group'] && $args['group'] != $group) |
| | | continue; |
| | | foreach ((array)$files as $filename){ |
| | | if(file_exists($filename)){ |
| | | unlink($filename); |
| | | } |
| | | } |
| | | unset($_SESSION['plugins']['filesystem_attachments'][$group]); |
| | | } |
| | | } |
| | | return $args; |
| | | } |
| | | |
| | | function file_id() |
| | | { |
| | | $userid = rcmail::get_instance()->user->ID; |
| | | list($usec, $sec) = explode(' ', microtime()); |
| | | return preg_replace('/[^0-9]/', '', $userid . $sec . $usec); |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | // Help content iframe source |
| | | // $rcmail_config['help_source'] = 'http://trac.roundcube.net/wiki'; |
| | | $rcmail_config['help_source'] = ''; |
New file |
| | |
| | | <div id="helpabout"> |
| | | <h3 align="center">Copyright © 2005-2010, The Roundcube Dev Team</h3> |
| | | |
| | | <p>This program is free software; you can redistribute it and/or modify |
| | | it under the terms of the GNU General Public License version 2 |
| | | as published by the Free Software Foundation. |
| | | </p> |
| | | <p> |
| | | This program 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. |
| | | </p> |
| | | <p> |
| | | You should have received a copy of the GNU General Public License along |
| | | with this program; if not, write to the Free Software Foundation, Inc., |
| | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| | | </p> |
| | | |
| | | <div align="center"> |
| | | <h3>Project management and administration</h3> |
| | | <b>Thomas Bruederli (thomasb)</b> - Project leader and head developer<br /> |
| | | <b>Till Klampäckel (till)</b> - Co-leader<br /> |
| | | <b>Brett Patterson</b> - Forum administrator<br /> |
| | | <b>Adam Grelck</b> - Trac administrator<br /> |
| | | <b>Jason Fesler</b> - Mailing list administrator<br /> |
| | | <b>Brennan Stehling</b> - Mentor, Coordinator |
| | | |
| | | <h3>Developers</h3> |
| | | <b>Eric Stadtherr (estadtherr)</b><br /> |
| | | <b>Robin Elfrink (robin, wobin)</b><br /> |
| | | <b>Rich Sandberg (richs)</b><br /> |
| | | <b>Tomasz Pajor (tomekp)</b><br /> |
| | | <b>Fourat Zouari (fourat.zouari)</b><br /> |
| | | <b>Aleksander Machniak (alec)</b> |
| | | |
| | | <p><br/>Website: <a href="http://roundcube.net">roundcube.net</a></p> |
| | | </div> |
| | | </div> |
New file |
| | |
| | | <div id="helplicense"> |
| | | <h3>GNU GENERAL PUBLIC LICENSE</h3> |
| | | <p> |
| | | Version 2, June 1991 |
| | | </p> |
| | | |
| | | <pre> |
| | | Copyright (C) 1989, 1991 Free Software Foundation, Inc. |
| | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| | | |
| | | Everyone is permitted to copy and distribute verbatim copies |
| | | of this license document, but changing it is not allowed. |
| | | </pre> |
| | | |
| | | <h3>Preamble</h3> |
| | | |
| | | <p> |
| | | The licenses for most software are designed to take away your |
| | | freedom to share and change it. By contrast, the GNU General Public |
| | | License is intended to guarantee your freedom to share and change free |
| | | software--to make sure the software is free for all its users. This |
| | | General Public License applies to most of the Free Software |
| | | Foundation's software and to any other program whose authors commit to |
| | | using it. (Some other Free Software Foundation software is covered by |
| | | the GNU Lesser General Public License instead.) You can apply it to |
| | | your programs, too. |
| | | </p> |
| | | |
| | | <p> |
| | | When we speak of free software, we are referring to freedom, not |
| | | price. Our General Public Licenses are designed to make sure that you |
| | | have the freedom to distribute copies of free software (and charge for |
| | | this service if you wish), that you receive source code or can get it |
| | | if you want it, that you can change the software or use pieces of it |
| | | in new free programs; and that you know you can do these things. |
| | | </p> |
| | | |
| | | <p> |
| | | To protect your rights, we need to make restrictions that forbid |
| | | anyone to deny you these rights or to ask you to surrender the rights. |
| | | These restrictions translate to certain responsibilities for you if you |
| | | distribute copies of the software, or if you modify it. |
| | | </p> |
| | | |
| | | <p> |
| | | For example, if you distribute copies of such a program, whether |
| | | gratis or for a fee, you must give the recipients all the rights that |
| | | you have. You must make sure that they, too, receive or can get the |
| | | source code. And you must show them these terms so they know their |
| | | rights. |
| | | </p> |
| | | |
| | | <p> |
| | | We protect your rights with two steps: (1) copyright the software, and |
| | | (2) offer you this license which gives you legal permission to copy, |
| | | distribute and/or modify the software. |
| | | </p> |
| | | |
| | | <p> |
| | | Also, for each author's protection and ours, we want to make certain |
| | | that everyone understands that there is no warranty for this free |
| | | software. If the software is modified by someone else and passed on, we |
| | | want its recipients to know that what they have is not the original, so |
| | | that any problems introduced by others will not reflect on the original |
| | | authors' reputations. |
| | | </p> |
| | | |
| | | <p> |
| | | Finally, any free program is threatened constantly by software |
| | | patents. We wish to avoid the danger that redistributors of a free |
| | | program will individually obtain patent licenses, in effect making the |
| | | program proprietary. To prevent this, we have made it clear that any |
| | | patent must be licensed for everyone's free use or not licensed at all. |
| | | </p> |
| | | |
| | | <p> |
| | | The precise terms and conditions for copying, distribution and |
| | | modification follow. |
| | | </p> |
| | | |
| | | |
| | | <h3>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</h3> |
| | | |
| | | |
| | | <p> |
| | | <strong>0.</strong> |
| | | This License applies to any program or other work which contains |
| | | a notice placed by the copyright holder saying it may be distributed |
| | | under the terms of this General Public License. The "Program", below, |
| | | refers to any such program or work, and a "work based on the Program" |
| | | means either the Program or any derivative work under copyright law: |
| | | that is to say, a work containing the Program or a portion of it, |
| | | either verbatim or with modifications and/or translated into another |
| | | language. (Hereinafter, translation is included without limitation in |
| | | the term "modification".) Each licensee is addressed as "you". |
| | | </p> |
| | | |
| | | <p> |
| | | Activities other than copying, distribution and modification are not |
| | | covered by this License; they are outside its scope. The act of |
| | | running the Program is not restricted, and the output from the Program |
| | | is covered only if its contents constitute a work based on the |
| | | Program (independent of having been made by running the Program). |
| | | Whether that is true depends on what the Program does. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>1.</strong> |
| | | You may copy and distribute verbatim copies of the Program's |
| | | source code as you receive it, in any medium, provided that you |
| | | conspicuously and appropriately publish on each copy an appropriate |
| | | copyright notice and disclaimer of warranty; keep intact all the |
| | | notices that refer to this License and to the absence of any warranty; |
| | | and give any other recipients of the Program a copy of this License |
| | | along with the Program. |
| | | </p> |
| | | |
| | | <p> |
| | | You may charge a fee for the physical act of transferring a copy, and |
| | | you may at your option offer warranty protection in exchange for a fee. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>2.</strong> |
| | | You may modify your copy or copies of the Program or any portion |
| | | of it, thus forming a work based on the Program, and copy and |
| | | distribute such modifications or work under the terms of Section 1 |
| | | above, provided that you also meet all of these conditions: |
| | | </p> |
| | | |
| | | <dl> |
| | | <dt></dt> |
| | | <dd> |
| | | <strong>a)</strong> |
| | | You must cause the modified files to carry prominent notices |
| | | stating that you changed the files and the date of any change. |
| | | </dd> |
| | | <dt></dt> |
| | | <dd> |
| | | <strong>b)</strong> |
| | | You must cause any work that you distribute or publish, that in |
| | | whole or in part contains or is derived from the Program or any |
| | | part thereof, to be licensed as a whole at no charge to all third |
| | | parties under the terms of this License. |
| | | </dd> |
| | | <dt></dt> |
| | | <dd> |
| | | <strong>c)</strong> |
| | | If the modified program normally reads commands interactively |
| | | when run, you must cause it, when started running for such |
| | | interactive use in the most ordinary way, to print or display an |
| | | announcement including an appropriate copyright notice and a |
| | | notice that there is no warranty (or else, saying that you provide |
| | | a warranty) and that users may redistribute the program under |
| | | these conditions, and telling the user how to view a copy of this |
| | | License. (Exception: if the Program itself is interactive but |
| | | does not normally print such an announcement, your work based on |
| | | the Program is not required to print an announcement.) |
| | | </dd> |
| | | </dl> |
| | | |
| | | <p> |
| | | These requirements apply to the modified work as a whole. If |
| | | identifiable sections of that work are not derived from the Program, |
| | | and can be reasonably considered independent and separate works in |
| | | themselves, then this License, and its terms, do not apply to those |
| | | sections when you distribute them as separate works. But when you |
| | | distribute the same sections as part of a whole which is a work based |
| | | on the Program, the distribution of the whole must be on the terms of |
| | | this License, whose permissions for other licensees extend to the |
| | | entire whole, and thus to each and every part regardless of who wrote it. |
| | | </p> |
| | | |
| | | <p> |
| | | Thus, it is not the intent of this section to claim rights or contest |
| | | your rights to work written entirely by you; rather, the intent is to |
| | | exercise the right to control the distribution of derivative or |
| | | collective works based on the Program. |
| | | </p> |
| | | |
| | | <p> |
| | | In addition, mere aggregation of another work not based on the Program |
| | | with the Program (or with a work based on the Program) on a volume of |
| | | a storage or distribution medium does not bring the other work under |
| | | the scope of this License. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>3.</strong> |
| | | You may copy and distribute the Program (or a work based on it, |
| | | under Section 2) in object code or executable form under the terms of |
| | | Sections 1 and 2 above provided that you also do one of the following: |
| | | </p> |
| | | |
| | | <dl> |
| | | <dt></dt> |
| | | <dd> |
| | | <strong>a)</strong> |
| | | Accompany it with the complete corresponding machine-readable |
| | | source code, which must be distributed under the terms of Sections |
| | | 1 and 2 above on a medium customarily used for software interchange; or, |
| | | </dd> |
| | | <dt></dt> |
| | | <dd> |
| | | <strong>b)</strong> |
| | | Accompany it with a written offer, valid for at least three |
| | | years, to give any third party, for a charge no more than your |
| | | cost of physically performing source distribution, a complete |
| | | machine-readable copy of the corresponding source code, to be |
| | | distributed under the terms of Sections 1 and 2 above on a medium |
| | | customarily used for software interchange; or, |
| | | </dd> |
| | | <dt></dt> |
| | | <dd> |
| | | <strong>c)</strong> |
| | | Accompany it with the information you received as to the offer |
| | | to distribute corresponding source code. (This alternative is |
| | | allowed only for noncommercial distribution and only if you |
| | | received the program in object code or executable form with such |
| | | an offer, in accord with Subsection b above.) |
| | | </dd> |
| | | </dl> |
| | | |
| | | <p> |
| | | The source code for a work means the preferred form of the work for |
| | | making modifications to it. For an executable work, complete source |
| | | code means all the source code for all modules it contains, plus any |
| | | associated interface definition files, plus the scripts used to |
| | | control compilation and installation of the executable. However, as a |
| | | special exception, the source code distributed need not include |
| | | anything that is normally distributed (in either source or binary |
| | | form) with the major components (compiler, kernel, and so on) of the |
| | | operating system on which the executable runs, unless that component |
| | | itself accompanies the executable. |
| | | </p> |
| | | |
| | | <p> |
| | | If distribution of executable or object code is made by offering |
| | | access to copy from a designated place, then offering equivalent |
| | | access to copy the source code from the same place counts as |
| | | distribution of the source code, even though third parties are not |
| | | compelled to copy the source along with the object code. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>4.</strong> |
| | | You may not copy, modify, sublicense, or distribute the Program |
| | | except as expressly provided under this License. Any attempt |
| | | otherwise to copy, modify, sublicense or distribute the Program is |
| | | void, and will automatically terminate your rights under this License. |
| | | However, parties who have received copies, or rights, from you under |
| | | this License will not have their licenses terminated so long as such |
| | | parties remain in full compliance. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>5.</strong> |
| | | You are not required to accept this License, since you have not |
| | | signed it. However, nothing else grants you permission to modify or |
| | | distribute the Program or its derivative works. These actions are |
| | | prohibited by law if you do not accept this License. Therefore, by |
| | | modifying or distributing the Program (or any work based on the |
| | | Program), you indicate your acceptance of this License to do so, and |
| | | all its terms and conditions for copying, distributing or modifying |
| | | the Program or works based on it. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>6.</strong> |
| | | Each time you redistribute the Program (or any work based on the |
| | | Program), the recipient automatically receives a license from the |
| | | original licensor to copy, distribute or modify the Program subject to |
| | | these terms and conditions. You may not impose any further |
| | | restrictions on the recipients' exercise of the rights granted herein. |
| | | You are not responsible for enforcing compliance by third parties to |
| | | this License. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>7.</strong> |
| | | If, as a consequence of a court judgment or allegation of patent |
| | | infringement or for any other reason (not limited to patent issues), |
| | | conditions are imposed on you (whether by court order, agreement or |
| | | otherwise) that contradict the conditions of this License, they do not |
| | | excuse you from the conditions of this License. If you cannot |
| | | distribute so as to satisfy simultaneously your obligations under this |
| | | License and any other pertinent obligations, then as a consequence you |
| | | may not distribute the Program at all. For example, if a patent |
| | | license would not permit royalty-free redistribution of the Program by |
| | | all those who receive copies directly or indirectly through you, then |
| | | the only way you could satisfy both it and this License would be to |
| | | refrain entirely from distribution of the Program. |
| | | </p> |
| | | |
| | | <p> |
| | | If any portion of this section is held invalid or unenforceable under |
| | | any particular circumstance, the balance of the section is intended to |
| | | apply and the section as a whole is intended to apply in other |
| | | circumstances. |
| | | </p> |
| | | |
| | | <p> |
| | | It is not the purpose of this section to induce you to infringe any |
| | | patents or other property right claims or to contest validity of any |
| | | such claims; this section has the sole purpose of protecting the |
| | | integrity of the free software distribution system, which is |
| | | implemented by public license practices. Many people have made |
| | | generous contributions to the wide range of software distributed |
| | | through that system in reliance on consistent application of that |
| | | system; it is up to the author/donor to decide if he or she is willing |
| | | to distribute software through any other system and a licensee cannot |
| | | impose that choice. |
| | | </p> |
| | | |
| | | <p> |
| | | This section is intended to make thoroughly clear what is believed to |
| | | be a consequence of the rest of this License. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>8.</strong> |
| | | If the distribution and/or use of the Program is restricted in |
| | | certain countries either by patents or by copyrighted interfaces, the |
| | | original copyright holder who places the Program under this License |
| | | may add an explicit geographical distribution limitation excluding |
| | | those countries, so that distribution is permitted only in or among |
| | | countries not thus excluded. In such case, this License incorporates |
| | | the limitation as if written in the body of this License. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>9.</strong> |
| | | The Free Software Foundation may publish revised and/or new versions |
| | | of the General Public License from time to time. Such new versions will |
| | | be similar in spirit to the present version, but may differ in detail to |
| | | address new problems or concerns. |
| | | </p> |
| | | |
| | | <p> |
| | | Each version is given a distinguishing version number. If the Program |
| | | specifies a version number of this License which applies to it and "any |
| | | later version", you have the option of following the terms and conditions |
| | | either of that version or of any later version published by the Free |
| | | Software Foundation. If the Program does not specify a version number of |
| | | this License, you may choose any version ever published by the Free Software |
| | | Foundation. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>10.</strong> |
| | | If you wish to incorporate parts of the Program into other free |
| | | programs whose distribution conditions are different, write to the author |
| | | to ask for permission. For software which is copyrighted by the Free |
| | | Software Foundation, write to the Free Software Foundation; we sometimes |
| | | make exceptions for this. Our decision will be guided by the two goals |
| | | of preserving the free status of all derivatives of our free software and |
| | | of promoting the sharing and reuse of software generally. |
| | | </p> |
| | | |
| | | <p><strong>NO WARRANTY</strong></p> |
| | | |
| | | <p> |
| | | <strong>11.</strong> |
| | | BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
| | | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
| | | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
| | | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
| | | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| | | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
| | | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
| | | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
| | | REPAIR OR CORRECTION. |
| | | </p> |
| | | |
| | | <p> |
| | | <strong>12.</strong> |
| | | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
| | | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
| | | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
| | | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
| | | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
| | | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
| | | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
| | | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
| | | POSSIBILITY OF SUCH DAMAGES. |
| | | </p> |
| | | </div> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * Help Plugin |
| | | * |
| | | * @author Aleksander 'A.L.E.C' Machniak |
| | | * @licence GNU GPL |
| | | * |
| | | * Configuration (see config.inc.php.dist) |
| | | * |
| | | **/ |
| | | |
| | | class help extends rcube_plugin |
| | | { |
| | | // all task excluding 'login' and 'logout' |
| | | public $task = '?(?!login|logout).*'; |
| | | // we've got no ajax handlers |
| | | public $noajax = true; |
| | | // skip frames |
| | | public $noframe = true; |
| | | |
| | | function init() |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | $this->add_texts('localization/', false); |
| | | |
| | | // register task |
| | | $this->register_task('help'); |
| | | |
| | | // register actions |
| | | $this->register_action('index', array($this, 'action')); |
| | | $this->register_action('about', array($this, 'action')); |
| | | $this->register_action('license', array($this, 'action')); |
| | | |
| | | // add taskbar button |
| | | $this->add_button(array( |
| | | 'name' => 'helptask', |
| | | 'class' => 'button-help', |
| | | 'label' => 'help.help', |
| | | 'href' => './?_task=help', |
| | | 'onclick' => sprintf("return %s.command('help')", JS_OBJECT_NAME) |
| | | ), 'taskbar'); |
| | | |
| | | $rcmail->output->add_script( |
| | | JS_OBJECT_NAME . ".enable_command('help', true);\n" . |
| | | JS_OBJECT_NAME . ".help = function () { location.href = './?_task=help'; }", |
| | | 'head'); |
| | | |
| | | $skin = $rcmail->config->get('skin'); |
| | | if (!file_exists($this->home."/skins/$skin/help.css")) |
| | | $skin = 'default'; |
| | | |
| | | // add style for taskbar button (must be here) and Help UI |
| | | $this->include_stylesheet("skins/$skin/help.css"); |
| | | } |
| | | |
| | | function action() |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | $this->load_config(); |
| | | |
| | | // register UI objects |
| | | $rcmail->output->add_handlers(array( |
| | | 'helpcontent' => array($this, 'content'), |
| | | )); |
| | | |
| | | if ($rcmail->action == 'about') |
| | | $rcmail->output->set_pagetitle($this->gettext('about')); |
| | | else if ($rcmail->action == 'license') |
| | | $rcmail->output->set_pagetitle($this->gettext('license')); |
| | | else |
| | | $rcmail->output->set_pagetitle($this->gettext('help')); |
| | | |
| | | $rcmail->output->send('help.help'); |
| | | } |
| | | |
| | | function content($attrib) |
| | | { |
| | | $rcmail = rcmail::get_instance(); |
| | | |
| | | if ($rcmail->action == 'about') { |
| | | return @file_get_contents($this->home.'/content/about.html'); |
| | | } |
| | | else if ($rcmail->action == 'license') { |
| | | return @file_get_contents($this->home.'/content/license.html'); |
| | | } |
| | | |
| | | // default content: iframe |
| | | |
| | | if ($src = $rcmail->config->get('help_source')) |
| | | $attrib['src'] = $src; |
| | | |
| | | if (empty($attrib['id'])) |
| | | $attrib['id'] = 'rcmailhelpcontent'; |
| | | |
| | | // allow the following attributes to be added to the <iframe> tag |
| | | $attrib_str = create_attrib_string($attrib, array( |
| | | 'id', 'class', 'style', 'src', 'width', 'height', 'frameborder')); |
| | | |
| | | $out = sprintf('<iframe name="%s"%s></iframe>'."\n", $attrib['id'], $attrib_str); |
| | | |
| | | return $out; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /* |
| | | |
| | | +-----------------------------------------------------------------------+ |
| | | | language/cs_CZ/labels.inc | |
| | | | | |
| | | | Language file of the Roundcube help plugin | |
| | | | Copyright (C) 2005-2009, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Milan Kozak <hodza@hodza.net> | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | @version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ |
| | | |
| | | */ |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Nápověda'; |
| | | $labels['about'] = 'O aplikaci'; |
| | | $labels['license'] = 'Licence'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Hjælp'; |
| | | $labels['about'] = 'Om'; |
| | | $labels['license'] = 'Licens'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | // translation done by Ulli Heist - http://heist.hobby-site.org/ |
| | | $labels = array(); |
| | | $labels['help'] = 'Hilfe'; |
| | | $labels['about'] = 'Über'; |
| | | $labels['license'] = 'Lizenz'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Help'; |
| | | $labels['about'] = 'About'; |
| | | $labels['license'] = 'License'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Help'; |
| | | $labels['about'] = 'About'; |
| | | $labels['license'] = 'License'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Ayuda'; |
| | | $labels['about'] = 'Acerca de'; |
| | | $labels['license'] = 'Licencia'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Abi'; |
| | | $labels['about'] = 'Roundcube info'; |
| | | $labels['license'] = 'Litsents'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Axuda'; |
| | | $labels['about'] = 'Acerca de'; |
| | | $labels['license'] = 'Licencia'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Segítség'; |
| | | $labels['about'] = 'Névjegy'; |
| | | $labels['license'] = 'Licenc'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | // EN-Revision: 3891 |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'ヘルプ'; |
| | | $labels['about'] = '紹介'; |
| | | $labels['license'] = 'ライセンス'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Pomoc'; |
| | | $labels['about'] = 'O programie'; |
| | | $labels['license'] = 'Licencja'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Ajuda'; |
| | | $labels['about'] = 'Sobre'; |
| | | $labels['license'] = 'Licença'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /* |
| | | |
| | | +-----------------------------------------------------------------------+ |
| | | | plugins/help/localization/ru_RU.inc | |
| | | | | |
| | | | Language file of the Roundcube help plugin | |
| | | | Copyright (C) 2005-2010, The Roundcube Dev Team | |
| | | | Licensed under the GNU GPL | |
| | | | | |
| | | +-----------------------------------------------------------------------+ |
| | | | Author: Sergey Dukachev <iam@dukess.ru> | |
| | | +-----------------------------------------------------------------------+ |
| | | |
| | | */ |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Помощь'; |
| | | $labels['about'] = 'О программе'; |
| | | $labels['license'] = 'Лицензия'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = 'Hjälp'; |
| | | $labels['about'] = 'Om'; |
| | | $labels['license'] = 'Licens'; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | $labels = array(); |
| | | $labels['help'] = '說明'; |
| | | $labels['about'] = '關於'; |
| | | $labels['license'] = '許可證'; |
| | | |
| | | ?> |
New file |
| | |
| | | /***** Roundcube|Mail Help task styles *****/ |
| | | |
| | | #taskbar a.button-help |
| | | { |
| | | background-image: url('help.gif'); |
| | | } |
| | | |
| | | .help-box |
| | | { |
| | | overflow: auto; |
| | | background-color: #F2F2F2; |
| | | } |
| | | |
| | | #helplicense, #helpabout |
| | | { |
| | | width: 46em; |
| | | padding: 1em 2em; |
| | | } |
| | | |
| | | #helplicense a, #helpabout a |
| | | { |
| | | color: #900; |
| | | } |
| | | |
| | | #helpabout |
| | | { |
| | | margin: 0 auto; |
| | | } |
| | | |
New file |
| | |
| | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| | | <html xmlns="http://www.w3.org/1999/xhtml"> |
| | | <head> |
| | | <title><roundcube:object name="pagetitle" /></title> |
| | | <roundcube:include file="/includes/links.html" /> |
| | | <link rel="stylesheet" type="text/css" href="/this/help.css" /> |
| | | <link rel="stylesheet" type="text/css" href="/settings.css" /> |
| | | <script type="text/javascript"> |
| | | function help_init_settings_tabs() |
| | | { |
| | | var action, tab = '#helptabdefault'; |
| | | if (window.rcmail && (action = rcmail.env.action)) { |
| | | tab = '#helptab' + (action ? action : 'default'); |
| | | } |
| | | $(tab).addClass('tablink-selected'); |
| | | } |
| | | </script> |
| | | </head> |
| | | <body> |
| | | |
| | | <roundcube:include file="/includes/taskbar.html" /> |
| | | <roundcube:include file="/includes/header.html" /> |
| | | |
| | | <div id="tabsbar"> |
| | | <span id="helptabdefault" class="tablink"><roundcube:button name="helpdefault" href="?_task=help" type="link" label="help.help" title="help.help" /></span> |
| | | <span id="helptababout" class="tablink"><roundcube:button name="helpabout" href="?_task=help&_action=about" type="link" label="help.about" title="help.about" class="tablink" /></span> |
| | | <span id="helptablicense" class="tablink"><roundcube:button name="helplicense" href="?_task=help&_action=license" type="link" label="help.license" title="help.license" class="tablink" /></span> |
| | | <roundcube:container name="helptabs" id="helptabsbar" /> |
| | | <script type="text/javascript"> if (window.rcmail) rcmail.add_onload(help_init_settings_tabs);</script> |
| | | </div> |
| | | |
| | | <div id="mainscreen" class="box help-box"> |
| | | <roundcube:object name="helpcontent" id="helpcontentframe" width="100%" height="100%" frameborder="0" src="/watermark.html" /> |
| | | </div> |
| | | |
| | | </body> |
| | | </html> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * HTTP Basic Authentication |
| | | * |
| | | * Make use of an existing HTTP authentication and perform login with the existing user credentials |
| | | * |
| | | * @version 1.2 |
| | | * @author Thomas Bruederli |
| | | */ |
| | | class http_authentication extends rcube_plugin |
| | | { |
| | | public $task = 'login'; |
| | | |
| | | function init() |
| | | { |
| | | $this->add_hook('startup', array($this, 'startup')); |
| | | $this->add_hook('authenticate', array($this, 'authenticate')); |
| | | } |
| | | |
| | | function startup($args) |
| | | { |
| | | // change action to login |
| | | if (empty($args['action']) && empty($_SESSION['user_id']) |
| | | && !empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) |
| | | $args['action'] = 'login'; |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | function authenticate($args) |
| | | { |
| | | if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW'])) { |
| | | $args['user'] = $_SERVER['PHP_AUTH_USER']; |
| | | $args['pass'] = $_SERVER['PHP_AUTH_PW']; |
| | | } |
| | | |
| | | $args['cookiecheck'] = false; |
| | | $args['valid'] = true; |
| | | |
| | | return $args; |
| | | } |
| | | |
| | | } |
| | | |
New file |
| | |
| | | +-------------------------------------------------------------------------+ |
| | | | |
| | | | Author: Cor Bosman (roundcube@wa.ter.net) |
| | | | Plugin: jqueryui |
| | | | Version: 1.8.14 |
| | | | Purpose: Add jquery-ui to roundcube for every plugin to use |
| | | | |
| | | +-------------------------------------------------------------------------+ |
| | | |
| | | jqueryui adds the complete jquery-ui library including the smoothness |
| | | theme to roundcube. This allows other plugins to use jquery-ui without |
| | | having to load their own version. The benefit of using 1 central jquery-ui |
| | | is that we wont run into problems of conflicting jquery libraries being |
| | | loaded. All plugins that want to use jquery-ui should use this plugin as |
| | | a requirement. |
| | | |
| | | It is possible for plugin authors to override the default smoothness theme. |
| | | To do this, go to the jquery-ui website, and use the download feature to |
| | | download your own theme. In the advanced settings, provide a scope class to |
| | | your theme and add that class to all your UI elements. Finally, load the |
| | | downloaded css files in your own plugin. |
| | | |
| | | Some jquery-ui modules provide localization. One example is the datepicker module. |
| | | If you want to load localization for a specific module, then set up config.inc.php. |
| | | Check the config.inc.php.dist file on how to set this up for the datepicker module. |
| | | |
| | | As of version 1.8.6 this plugin also supports other themes. If you're a theme |
| | | developer and would like a different default theme to be used for your RC theme |
| | | then let me know and we can set things up. |
New file |
| | |
| | | <?php |
| | | |
| | | // if you want to load localization strings for specific sub-libraries of jquery-ui, configure them here |
| | | $rcmail_config['jquery_ui_i18n'] = array('datepicker'); |
| | | |
| | | // map Roundcube skins with jquery-ui themes here |
| | | $rcmail_config['jquery_ui_skin_map'] = array( |
| | | 'groupvice4' => 'redmond', |
| | | ); |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | * jQuery UI |
| | | * |
| | | * Provide the jQuery UI library with according themes. |
| | | * |
| | | * @version 1.8.14 |
| | | * @author Cor Bosman <roundcube@wa.ter.net> |
| | | * @author Thomas Bruederli <roundcube@gmail.com> |
| | | */ |
| | | class jqueryui extends rcube_plugin |
| | | { |
| | | public $noajax = true; |
| | | |
| | | public function init() |
| | | { |
| | | $version = '1.8.14'; |
| | | |
| | | $rcmail = rcmail::get_instance(); |
| | | $this->load_config(); |
| | | |
| | | // include UI scripts |
| | | $this->include_script("js/jquery-ui-$version.custom.min.js"); |
| | | |
| | | // include UI stylesheet |
| | | $skin = $rcmail->config->get('skin', 'default'); |
| | | $ui_map = $rcmail->config->get('jquery_ui_skin_map', array()); |
| | | $ui_theme = $ui_map[$skin] ? $ui_map[$skin] : 'default'; |
| | | |
| | | if (file_exists($this->home . "/themes/$ui_theme/jquery-ui-$version.custom.css")) { |
| | | $this->include_stylesheet("themes/$ui_theme/jquery-ui-$version.custom.css"); |
| | | } |
| | | else { |
| | | $this->include_stylesheet("themes/default/jquery-ui-$version.custom.css"); |
| | | } |
| | | |
| | | // jquery UI localization |
| | | $jquery_ui_i18n = $rcmail->config->get('jquery_ui_i18n', array()); |
| | | if (count($jquery_ui_i18n) > 0) { |
| | | $lang_l = str_replace('_', '-', substr($_SESSION['language'], 0, 5)); |
| | | $lang_s = substr($_SESSION['language'], 0, 2); |
| | | foreach($jquery_ui_i18n as $package) { |
| | | if (file_exists($this->home . "/js/i18n/jquery.ui.$package-$lang_l.js")) { |
| | | $this->include_script("js/i18n/jquery.ui.$package-$lang_l.js"); |
| | | } |
| | | else if (file_exists($this->home . "/js/i18n/jquery.ui.$package-$lang_s.js")) { |
| | | $this->include_script("js/i18n/jquery.ui.$package-$lang_s.js"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | /* Afrikaans initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Renier Pretorius. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['af'] = { |
| | | closeText: 'Selekteer', |
| | | prevText: 'Vorige', |
| | | nextText: 'Volgende', |
| | | currentText: 'Vandag', |
| | | monthNames: ['Januarie','Februarie','Maart','April','Mei','Junie', |
| | | 'Julie','Augustus','September','Oktober','November','Desember'], |
| | | monthNamesShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', |
| | | 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'], |
| | | dayNames: ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'], |
| | | dayNamesShort: ['Son', 'Maa', 'Din', 'Woe', 'Don', 'Vry', 'Sat'], |
| | | dayNamesMin: ['So','Ma','Di','Wo','Do','Vr','Sa'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['af']); |
| | | }); |
| | | /* Arabic Translation for jQuery UI date picker plugin. */ |
| | | /* Khaled Al Horani -- koko.dw@gmail.com */ |
| | | /* خالد الحوراني -- koko.dw@gmail.com */ |
| | | /* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ar'] = { |
| | | closeText: 'إغلاق', |
| | | prevText: '<السابق', |
| | | nextText: 'التالي>', |
| | | currentText: 'اليوم', |
| | | monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران', |
| | | 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], |
| | | monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], |
| | | dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'], |
| | | dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], |
| | | dayNamesMin: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], |
| | | weekHeader: 'أسبوع', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: true, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ar']); |
| | | });/* Azerbaijani (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jamil Najafov (necefov33@gmail.com). */ |
| | | jQuery(function($) { |
| | | $.datepicker.regional['az'] = { |
| | | closeText: 'Bağla', |
| | | prevText: '<Geri', |
| | | nextText: 'İrəli>', |
| | | currentText: 'Bugün', |
| | | monthNames: ['Yanvar','Fevral','Mart','Aprel','May','İyun', |
| | | 'İyul','Avqust','Sentyabr','Oktyabr','Noyabr','Dekabr'], |
| | | monthNamesShort: ['Yan','Fev','Mar','Apr','May','İyun', |
| | | 'İyul','Avq','Sen','Okt','Noy','Dek'], |
| | | dayNames: ['Bazar','Bazar ertəsi','Çərşənbə axşamı','Çərşənbə','Cümə axşamı','Cümə','Şənbə'], |
| | | dayNamesShort: ['B','Be','Ça','Ç','Ca','C','Ş'], |
| | | dayNamesMin: ['B','B','Ç','С','Ç','C','Ş'], |
| | | weekHeader: 'Hf', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['az']); |
| | | });/* Bulgarian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Stoyan Kyosev (http://svest.org). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['bg'] = { |
| | | closeText: 'затвори', |
| | | prevText: '<назад', |
| | | nextText: 'напред>', |
| | | nextBigText: '>>', |
| | | currentText: 'днес', |
| | | monthNames: ['Януари','Февруари','Март','Април','Май','Юни', |
| | | 'Юли','Август','Септември','Октомври','Ноември','Декември'], |
| | | monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни', |
| | | 'Юли','Авг','Сеп','Окт','Нов','Дек'], |
| | | dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'], |
| | | dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'], |
| | | dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['bg']); |
| | | }); |
| | | /* Bosnian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Kenan Konjo. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['bs'] = { |
| | | closeText: 'Zatvori', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Danas', |
| | | monthNames: ['Januar','Februar','Mart','April','Maj','Juni', |
| | | 'Juli','August','Septembar','Oktobar','Novembar','Decembar'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedelja','Ponedeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], |
| | | dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['bs']); |
| | | });/* Inicialització en català per a l'extenció 'calendar' per jQuery. */ |
| | | /* Writers: (joan.leon@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ca'] = { |
| | | closeText: 'Tancar', |
| | | prevText: '<Ant', |
| | | nextText: 'Seg>', |
| | | currentText: 'Avui', |
| | | monthNames: ['Gener','Febrer','Març','Abril','Maig','Juny', |
| | | 'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'], |
| | | monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun', |
| | | 'Jul','Ago','Set','Oct','Nov','Des'], |
| | | dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'], |
| | | dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'], |
| | | dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ca']); |
| | | });/* Czech initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Tomas Muller (tomas@tomas-muller.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['cs'] = { |
| | | closeText: 'Zavřít', |
| | | prevText: '<Dříve', |
| | | nextText: 'Později>', |
| | | currentText: 'Nyní', |
| | | monthNames: ['leden','únor','březen','duben','květen','červen', |
| | | 'červenec','srpen','září','říjen','listopad','prosinec'], |
| | | monthNamesShort: ['led','úno','bře','dub','kvě','čer', |
| | | 'čvc','srp','zář','říj','lis','pro'], |
| | | dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], |
| | | dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], |
| | | dayNamesMin: ['ne','po','út','st','čt','pá','so'], |
| | | weekHeader: 'Týd', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['cs']); |
| | | }); |
| | | /* Danish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jan Christensen ( deletestuff@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['da'] = { |
| | | closeText: 'Luk', |
| | | prevText: '<Forrige', |
| | | nextText: 'Næste>', |
| | | currentText: 'Idag', |
| | | monthNames: ['Januar','Februar','Marts','April','Maj','Juni', |
| | | 'Juli','August','September','Oktober','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], |
| | | dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], |
| | | dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], |
| | | weekHeader: 'Uge', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['da']); |
| | | }); |
| | | /* German initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Milian Wolff (mail@milianw.de). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['de'] = { |
| | | closeText: 'schließen', |
| | | prevText: '<zurück', |
| | | nextText: 'Vor>', |
| | | currentText: 'heute', |
| | | monthNames: ['Januar','Februar','März','April','Mai','Juni', |
| | | 'Juli','August','September','Oktober','November','Dezember'], |
| | | monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dez'], |
| | | dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], |
| | | dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], |
| | | dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], |
| | | weekHeader: 'Wo', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['de']); |
| | | }); |
| | | /* Greek (el) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Alex Cicovic (http://www.alexcicovic.com) */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['el'] = { |
| | | closeText: 'Κλείσιμο', |
| | | prevText: 'Προηγούμενος', |
| | | nextText: 'Επόμενος', |
| | | currentText: 'Τρέχων Μήνας', |
| | | monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος', |
| | | 'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'], |
| | | monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν', |
| | | 'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'], |
| | | dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'], |
| | | dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'], |
| | | dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'], |
| | | weekHeader: 'Εβδ', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['el']); |
| | | });/* English/UK initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Stuart. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['en-GB'] = { |
| | | closeText: 'Done', |
| | | prevText: 'Prev', |
| | | nextText: 'Next', |
| | | currentText: 'Today', |
| | | monthNames: ['January','February','March','April','May','June', |
| | | 'July','August','September','October','November','December'], |
| | | monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', |
| | | 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
| | | dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], |
| | | dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], |
| | | dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['en-GB']); |
| | | }); |
| | | /* Esperanto initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Olivier M. (olivierweb@ifrance.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['eo'] = { |
| | | closeText: 'Fermi', |
| | | prevText: '<Anta', |
| | | nextText: 'Sekv>', |
| | | currentText: 'Nuna', |
| | | monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio', |
| | | 'Julio','Aŭgusto','Septembro','Oktobro','Novembro','Decembro'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aŭg','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ĵaŭdo','Vendredo','Sabato'], |
| | | dayNamesShort: ['Dim','Lun','Mar','Mer','Ĵaŭ','Ven','Sab'], |
| | | dayNamesMin: ['Di','Lu','Ma','Me','Ĵa','Ve','Sa'], |
| | | weekHeader: 'Sb', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['eo']); |
| | | }); |
| | | /* Inicialización en español para la extensión 'UI date picker' para jQuery. */ |
| | | /* Traducido por Vester (xvester@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['es'] = { |
| | | closeText: 'Cerrar', |
| | | prevText: '<Ant', |
| | | nextText: 'Sig>', |
| | | currentText: 'Hoy', |
| | | monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', |
| | | 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], |
| | | monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', |
| | | 'Jul','Ago','Sep','Oct','Nov','Dic'], |
| | | dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], |
| | | dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], |
| | | dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['es']); |
| | | });/* Estonian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mart Sõmermaa (mrts.pydev at gmail com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['et'] = { |
| | | closeText: 'Sulge', |
| | | prevText: 'Eelnev', |
| | | nextText: 'Järgnev', |
| | | currentText: 'Täna', |
| | | monthNames: ['Jaanuar','Veebruar','Märts','Aprill','Mai','Juuni', |
| | | 'Juuli','August','September','Oktoober','November','Detsember'], |
| | | monthNamesShort: ['Jaan', 'Veebr', 'Märts', 'Apr', 'Mai', 'Juuni', |
| | | 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'], |
| | | dayNames: ['Pühapäev', 'Esmaspäev', 'Teisipäev', 'Kolmapäev', 'Neljapäev', 'Reede', 'Laupäev'], |
| | | dayNamesShort: ['Pühap', 'Esmasp', 'Teisip', 'Kolmap', 'Neljap', 'Reede', 'Laup'], |
| | | dayNamesMin: ['P','E','T','K','N','R','L'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['et']); |
| | | }); /* Euskarako oinarria 'UI date picker' jquery-ko extentsioarentzat */ |
| | | /* Karrikas-ek itzulia (karrikas@karrikas.com) */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['eu'] = { |
| | | closeText: 'Egina', |
| | | prevText: '<Aur', |
| | | nextText: 'Hur>', |
| | | currentText: 'Gaur', |
| | | monthNames: ['Urtarrila','Otsaila','Martxoa','Apirila','Maiatza','Ekaina', |
| | | 'Uztaila','Abuztua','Iraila','Urria','Azaroa','Abendua'], |
| | | monthNamesShort: ['Urt','Ots','Mar','Api','Mai','Eka', |
| | | 'Uzt','Abu','Ira','Urr','Aza','Abe'], |
| | | dayNames: ['Igandea','Astelehena','Asteartea','Asteazkena','Osteguna','Ostirala','Larunbata'], |
| | | dayNamesShort: ['Iga','Ast','Ast','Ast','Ost','Ost','Lar'], |
| | | dayNamesMin: ['Ig','As','As','As','Os','Os','La'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['eu']); |
| | | });/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */ |
| | | /* Javad Mowlanezhad -- jmowla@gmail.com */ |
| | | /* Jalali calendar should supported soon! (Its implemented but I have to test it) */ |
| | | jQuery(function($) { |
| | | $.datepicker.regional['fa'] = { |
| | | closeText: 'بستن', |
| | | prevText: '<قبلي', |
| | | nextText: 'بعدي>', |
| | | currentText: 'امروز', |
| | | monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور', |
| | | 'مهر','آبان','آذر','دي','بهمن','اسفند'], |
| | | monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], |
| | | dayNames: ['يکشنبه','دوشنبه','سهشنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'], |
| | | dayNamesShort: ['ي','د','س','چ','پ','ج', 'ش'], |
| | | dayNamesMin: ['ي','د','س','چ','پ','ج', 'ش'], |
| | | weekHeader: 'هف', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 6, |
| | | isRTL: true, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fa']); |
| | | });/* Finnish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Harri Kilpi� (harrikilpio@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fi'] = { |
| | | closeText: 'Sulje', |
| | | prevText: '«Edellinen', |
| | | nextText: 'Seuraava»', |
| | | currentText: 'Tänään', |
| | | monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', |
| | | 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], |
| | | monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kesä', |
| | | 'Heinä','Elo','Syys','Loka','Marras','Joulu'], |
| | | dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','Su'], |
| | | dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'], |
| | | dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'], |
| | | weekHeader: 'Vk', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fi']); |
| | | }); |
| | | /* Faroese initialisation for the jQuery UI date picker plugin */ |
| | | /* Written by Sverri Mohr Olsen, sverrimo@gmail.com */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fo'] = { |
| | | closeText: 'Lat aftur', |
| | | prevText: '<Fyrra', |
| | | nextText: 'Næsta>', |
| | | currentText: 'Í dag', |
| | | monthNames: ['Januar','Februar','Mars','Apríl','Mei','Juni', |
| | | 'Juli','August','September','Oktober','November','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Des'], |
| | | dayNames: ['Sunnudagur','Mánadagur','Týsdagur','Mikudagur','Hósdagur','Fríggjadagur','Leyardagur'], |
| | | dayNamesShort: ['Sun','Mán','Týs','Mik','Hós','Frí','Ley'], |
| | | dayNamesMin: ['Su','Má','Tý','Mi','Hó','Fr','Le'], |
| | | weekHeader: 'Vk', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fo']); |
| | | }); |
| | | /* Swiss-French initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written Martin Voelkle (martin.voelkle@e-tc.ch). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fr-CH'] = { |
| | | closeText: 'Fermer', |
| | | prevText: '<Préc', |
| | | nextText: 'Suiv>', |
| | | currentText: 'Courant', |
| | | monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', |
| | | 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], |
| | | monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', |
| | | 'Jul','Aoû','Sep','Oct','Nov','Déc'], |
| | | dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], |
| | | dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], |
| | | dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fr-CH']); |
| | | });/* French initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Keith Wood (kbwood{at}iinet.com.au) and Stéphane Nahmani (sholby@sholby.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fr'] = { |
| | | closeText: 'Fermer', |
| | | prevText: '<Préc', |
| | | nextText: 'Suiv>', |
| | | currentText: 'Courant', |
| | | monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', |
| | | 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], |
| | | monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', |
| | | 'Jul','Aoû','Sep','Oct','Nov','Déc'], |
| | | dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], |
| | | dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], |
| | | dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fr']); |
| | | });/* Galician localization for 'UI date picker' jQuery extension. */ |
| | | /* Translated by Jorge Barreiro <yortx.barry@gmail.com>. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['gl'] = { |
| | | closeText: 'Pechar', |
| | | prevText: '<Ant', |
| | | nextText: 'Seg>', |
| | | currentText: 'Hoxe', |
| | | monthNames: ['Xaneiro','Febreiro','Marzo','Abril','Maio','Xuño', |
| | | 'Xullo','Agosto','Setembro','Outubro','Novembro','Decembro'], |
| | | monthNamesShort: ['Xan','Feb','Mar','Abr','Mai','Xuñ', |
| | | 'Xul','Ago','Set','Out','Nov','Dec'], |
| | | dayNames: ['Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado'], |
| | | dayNamesShort: ['Dom','Lun','Mar','Mér','Xov','Ven','Sáb'], |
| | | dayNamesMin: ['Do','Lu','Ma','Mé','Xo','Ve','Sá'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['gl']); |
| | | });/* Hebrew initialisation for the UI Datepicker extension. */ |
| | | /* Written by Amir Hardon (ahardon at gmail dot com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['he'] = { |
| | | closeText: 'סגור', |
| | | prevText: '<הקודם', |
| | | nextText: 'הבא>', |
| | | currentText: 'היום', |
| | | monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', |
| | | 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], |
| | | monthNamesShort: ['1','2','3','4','5','6', |
| | | '7','8','9','10','11','12'], |
| | | dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], |
| | | dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], |
| | | dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: true, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['he']); |
| | | }); |
| | | /* Croatian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Vjekoslav Nesek. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['hr'] = { |
| | | closeText: 'Zatvori', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Danas', |
| | | monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipanj', |
| | | 'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'], |
| | | monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip', |
| | | 'Srp','Kol','Ruj','Lis','Stu','Pro'], |
| | | dayNames: ['Nedjelja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], |
| | | dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], |
| | | weekHeader: 'Tje', |
| | | dateFormat: 'dd.mm.yy.', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['hr']); |
| | | });/* Hungarian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Istvan Karaszi (jquery@spam.raszi.hu). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['hu'] = { |
| | | closeText: 'bezárás', |
| | | prevText: '« vissza', |
| | | nextText: 'előre »', |
| | | currentText: 'ma', |
| | | monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', |
| | | 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], |
| | | monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', |
| | | 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], |
| | | dayNames: ['Vasárnap', 'Hétfö', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], |
| | | dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'], |
| | | dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], |
| | | weekHeader: 'Hé', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['hu']); |
| | | }); |
| | | /* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['hy'] = { |
| | | closeText: 'Փակել', |
| | | prevText: '<Նախ.', |
| | | nextText: 'Հաջ.>', |
| | | currentText: 'Այսօր', |
| | | monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս', |
| | | 'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'], |
| | | monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս', |
| | | 'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Դեկ'], |
| | | dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','հինգշաբթի','ուրբաթ','շաբաթ'], |
| | | dayNamesShort: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'], |
| | | dayNamesMin: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'], |
| | | weekHeader: 'ՇԲՏ', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['hy']); |
| | | });/* Indonesian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Deden Fathurahman (dedenf@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['id'] = { |
| | | closeText: 'Tutup', |
| | | prevText: '<mundur', |
| | | nextText: 'maju>', |
| | | currentText: 'hari ini', |
| | | monthNames: ['Januari','Februari','Maret','April','Mei','Juni', |
| | | 'Juli','Agustus','September','Oktober','Nopember','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', |
| | | 'Jul','Agus','Sep','Okt','Nop','Des'], |
| | | dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'], |
| | | dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'], |
| | | dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'], |
| | | weekHeader: 'Mg', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['id']); |
| | | });/* Icelandic initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Haukur H. Thorsson (haukur@eskill.is). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['is'] = { |
| | | closeText: 'Loka', |
| | | prevText: '< Fyrri', |
| | | nextText: 'Næsti >', |
| | | currentText: 'Í dag', |
| | | monthNames: ['Janúar','Febrúar','Mars','Apríl','Maí','Júní', |
| | | 'Júlí','Ágúst','September','Október','Nóvember','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maí','Jún', |
| | | 'Júl','Ágú','Sep','Okt','Nóv','Des'], |
| | | dayNames: ['Sunnudagur','Mánudagur','Þriðjudagur','Miðvikudagur','Fimmtudagur','Föstudagur','Laugardagur'], |
| | | dayNamesShort: ['Sun','Mán','Þri','Mið','Fim','Fös','Lau'], |
| | | dayNamesMin: ['Su','Má','Þr','Mi','Fi','Fö','La'], |
| | | weekHeader: 'Vika', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['is']); |
| | | });/* Italian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Antonello Pasella (antonello.pasella@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['it'] = { |
| | | closeText: 'Chiudi', |
| | | prevText: '<Prec', |
| | | nextText: 'Succ>', |
| | | currentText: 'Oggi', |
| | | monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', |
| | | 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], |
| | | monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', |
| | | 'Lug','Ago','Set','Ott','Nov','Dic'], |
| | | dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], |
| | | dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], |
| | | dayNamesMin: ['Do','Lu','Ma','Me','Gi','Ve','Sa'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['it']); |
| | | }); |
| | | /* Japanese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Kentaro SATO (kentaro@ranvis.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ja'] = { |
| | | closeText: '閉じる', |
| | | prevText: '<前', |
| | | nextText: '次>', |
| | | currentText: '今日', |
| | | monthNames: ['1月','2月','3月','4月','5月','6月', |
| | | '7月','8月','9月','10月','11月','12月'], |
| | | monthNamesShort: ['1月','2月','3月','4月','5月','6月', |
| | | '7月','8月','9月','10月','11月','12月'], |
| | | dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'], |
| | | dayNamesShort: ['日','月','火','水','木','金','土'], |
| | | dayNamesMin: ['日','月','火','水','木','金','土'], |
| | | weekHeader: '週', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ja']); |
| | | });/* Korean initialisation for the jQuery calendar extension. */ |
| | | /* Written by DaeKwon Kang (ncrash.dk@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ko'] = { |
| | | closeText: '닫기', |
| | | prevText: '이전달', |
| | | nextText: '다음달', |
| | | currentText: '오늘', |
| | | monthNames: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', |
| | | '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], |
| | | monthNamesShort: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', |
| | | '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], |
| | | dayNames: ['일','월','화','수','목','금','토'], |
| | | dayNamesShort: ['일','월','화','수','목','금','토'], |
| | | dayNamesMin: ['일','월','화','수','목','금','토'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: '년'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ko']); |
| | | });/* Kazakh (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Dmitriy Karasyov (dmitriy.karasyov@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['kz'] = { |
| | | closeText: 'Жабу', |
| | | prevText: '<Алдыңғы', |
| | | nextText: 'Келесі>', |
| | | currentText: 'Бүгін', |
| | | monthNames: ['Қаңтар','Ақпан','Наурыз','Сәуір','Мамыр','Маусым', |
| | | 'Шілде','Тамыз','Қыркүйек','Қазан','Қараша','Желтоқсан'], |
| | | monthNamesShort: ['Қаң','Ақп','Нау','Сәу','Мам','Мау', |
| | | 'Шіл','Там','Қыр','Қаз','Қар','Жел'], |
| | | dayNames: ['Жексенбі','Дүйсенбі','Сейсенбі','Сәрсенбі','Бейсенбі','Жұма','Сенбі'], |
| | | dayNamesShort: ['жкс','дсн','ссн','срс','бсн','жма','снб'], |
| | | dayNamesMin: ['Жк','Дс','Сс','Ср','Бс','Жм','Сн'], |
| | | weekHeader: 'Не', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['kz']); |
| | | }); |
| | | /* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* @author Arturas Paleicikas <arturas@avalon.lt> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['lt'] = { |
| | | closeText: 'Uždaryti', |
| | | prevText: '<Atgal', |
| | | nextText: 'Pirmyn>', |
| | | currentText: 'Šiandien', |
| | | monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis', |
| | | 'Liepa','Rugpjūtis','Rugsėjis','Spalis','Lapkritis','Gruodis'], |
| | | monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir', |
| | | 'Lie','Rugp','Rugs','Spa','Lap','Gru'], |
| | | dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'], |
| | | dayNamesShort: ['sek','pir','ant','tre','ket','pen','šeš'], |
| | | dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Še'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['lt']); |
| | | });/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* @author Arturas Paleicikas <arturas.paleicikas@metasite.net> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['lv'] = { |
| | | closeText: 'Aizvērt', |
| | | prevText: 'Iepr', |
| | | nextText: 'Nāka', |
| | | currentText: 'Šodien', |
| | | monthNames: ['Janvāris','Februāris','Marts','Aprīlis','Maijs','Jūnijs', |
| | | 'Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jūn', |
| | | 'Jūl','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['svētdiena','pirmdiena','otrdiena','trešdiena','ceturtdiena','piektdiena','sestdiena'], |
| | | dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'], |
| | | dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'], |
| | | weekHeader: 'Nav', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['lv']); |
| | | });/* Malaysian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ms'] = { |
| | | closeText: 'Tutup', |
| | | prevText: '<Sebelum', |
| | | nextText: 'Selepas>', |
| | | currentText: 'hari ini', |
| | | monthNames: ['Januari','Februari','Mac','April','Mei','Jun', |
| | | 'Julai','Ogos','September','Oktober','November','Disember'], |
| | | monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun', |
| | | 'Jul','Ogo','Sep','Okt','Nov','Dis'], |
| | | dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'], |
| | | dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'], |
| | | dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'], |
| | | weekHeader: 'Mg', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ms']); |
| | | });/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mathias Bynens <http://mathiasbynens.be/> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional.nl = { |
| | | closeText: 'Sluiten', |
| | | prevText: '←', |
| | | nextText: '→', |
| | | currentText: 'Vandaag', |
| | | monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', |
| | | 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], |
| | | monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun', |
| | | 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], |
| | | dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], |
| | | dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], |
| | | dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional.nl); |
| | | });/* Norwegian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Naimdjon Takhirov (naimdjon@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['no'] = { |
| | | closeText: 'Lukk', |
| | | prevText: '«Forrige', |
| | | nextText: 'Neste»', |
| | | currentText: 'I dag', |
| | | monthNames: ['Januar','Februar','Mars','April','Mai','Juni', |
| | | 'Juli','August','September','Oktober','November','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Des'], |
| | | dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], |
| | | dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], |
| | | dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], |
| | | weekHeader: 'Uke', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['no']); |
| | | }); |
| | | /* Polish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['pl'] = { |
| | | closeText: 'Zamknij', |
| | | prevText: '<Poprzedni', |
| | | nextText: 'Następny>', |
| | | currentText: 'Dziś', |
| | | monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', |
| | | 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], |
| | | monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze', |
| | | 'Lip','Sie','Wrz','Pa','Lis','Gru'], |
| | | dayNames: ['Niedziela','Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota'], |
| | | dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'], |
| | | dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'], |
| | | weekHeader: 'Tydz', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['pl']); |
| | | }); |
| | | /* Brazilian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Leonildo Costa Silva (leocsilva@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['pt-BR'] = { |
| | | closeText: 'Fechar', |
| | | prevText: '<Anterior', |
| | | nextText: 'Próximo>', |
| | | currentText: 'Hoje', |
| | | monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', |
| | | 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], |
| | | monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', |
| | | 'Jul','Ago','Set','Out','Nov','Dez'], |
| | | dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], |
| | | dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['pt-BR']); |
| | | });/* Portuguese initialisation for the jQuery UI date picker plugin. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['pt'] = { |
| | | closeText: 'Fechar', |
| | | prevText: '<Anterior', |
| | | nextText: 'Seguinte', |
| | | currentText: 'Hoje', |
| | | monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', |
| | | 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], |
| | | monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', |
| | | 'Jul','Ago','Set','Out','Nov','Dez'], |
| | | dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], |
| | | dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | weekHeader: 'Sem', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['pt']); |
| | | });/* Romanian initialisation for the jQuery UI date picker plugin. |
| | | * |
| | | * Written by Edmond L. (ll_edmond@walla.com) |
| | | * and Ionut G. Stan (ionut.g.stan@gmail.com) |
| | | */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ro'] = { |
| | | closeText: 'Închide', |
| | | prevText: '« Luna precedentă', |
| | | nextText: 'Luna următoare »', |
| | | currentText: 'Azi', |
| | | monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie', |
| | | 'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], |
| | | monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', |
| | | 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
| | | dayNames: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], |
| | | dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], |
| | | dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'], |
| | | weekHeader: 'Săpt', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ro']); |
| | | }); |
| | | /* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Andrew Stromnov (stromnov@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ru'] = { |
| | | closeText: 'Закрыть', |
| | | prevText: '<Пред', |
| | | nextText: 'След>', |
| | | currentText: 'Сегодня', |
| | | monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', |
| | | 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], |
| | | monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', |
| | | 'Июл','Авг','Сен','Окт','Ноя','Дек'], |
| | | dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], |
| | | dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], |
| | | dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], |
| | | weekHeader: 'Нед', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ru']); |
| | | });/* Slovak initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Vojtech Rinik (vojto@hmm.sk). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sk'] = { |
| | | closeText: 'Zavrieť', |
| | | prevText: '<Predchádzajúci', |
| | | nextText: 'Nasledujúci>', |
| | | currentText: 'Dnes', |
| | | monthNames: ['Január','Február','Marec','Apríl','Máj','Jún', |
| | | 'Júl','August','September','Október','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún', |
| | | 'Júl','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedel\'a','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Str','Štv','Pia','Sob'], |
| | | dayNamesMin: ['Ne','Po','Ut','St','Št','Pia','So'], |
| | | weekHeader: 'Ty', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sk']); |
| | | }); |
| | | /* Slovenian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jaka Jancar (jaka@kubje.org). */ |
| | | /* c = č, s = š z = ž C = Č S = Š Z = Ž */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sl'] = { |
| | | closeText: 'Zapri', |
| | | prevText: '<Prejšnji', |
| | | nextText: 'Naslednji>', |
| | | currentText: 'Trenutni', |
| | | monthNames: ['Januar','Februar','Marec','April','Maj','Junij', |
| | | 'Julij','Avgust','September','Oktober','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Avg','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota'], |
| | | dayNamesShort: ['Ned','Pon','Tor','Sre','Čet','Pet','Sob'], |
| | | dayNamesMin: ['Ne','Po','To','Sr','Če','Pe','So'], |
| | | weekHeader: 'Teden', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sl']); |
| | | }); |
| | | /* Albanian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Flakron Bytyqi (flakron@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sq'] = { |
| | | closeText: 'mbylle', |
| | | prevText: '<mbrapa', |
| | | nextText: 'Përpara>', |
| | | currentText: 'sot', |
| | | monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor', |
| | | 'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'], |
| | | monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer', |
| | | 'Kor','Gus','Sht','Tet','Nën','Dhj'], |
| | | dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'], |
| | | dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'], |
| | | dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'], |
| | | weekHeader: 'Ja', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sq']); |
| | | }); |
| | | /* Serbian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Dejan Dimić. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sr-SR'] = { |
| | | closeText: 'Zatvori', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Danas', |
| | | monthNames: ['Januar','Februar','Mart','April','Maj','Jun', |
| | | 'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Avg','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'], |
| | | dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], |
| | | weekHeader: 'Sed', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sr-SR']); |
| | | }); |
| | | /* Serbian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Dejan Dimić. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sr'] = { |
| | | closeText: 'Затвори', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Данас', |
| | | monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун', |
| | | 'Јул','Август','Септембар','Октобар','Новембар','Децембар'], |
| | | monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун', |
| | | 'Јул','Авг','Сеп','Окт','Нов','Дец'], |
| | | dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'], |
| | | dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'], |
| | | dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'], |
| | | weekHeader: 'Сед', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sr']); |
| | | }); |
| | | /* Swedish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Anders Ekdahl ( anders@nomadiz.se). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sv'] = { |
| | | closeText: 'Stäng', |
| | | prevText: '«Förra', |
| | | nextText: 'Nästa»', |
| | | currentText: 'Idag', |
| | | monthNames: ['Januari','Februari','Mars','April','Maj','Juni', |
| | | 'Juli','Augusti','September','Oktober','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'], |
| | | dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'], |
| | | dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'], |
| | | weekHeader: 'Ve', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sv']); |
| | | }); |
| | | /* Tamil (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by S A Sureshkumar (saskumar@live.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ta'] = { |
| | | closeText: 'மூடு', |
| | | prevText: 'முன்னையது', |
| | | nextText: 'அடுத்தது', |
| | | currentText: 'இன்று', |
| | | monthNames: ['தை','மாசி','பங்குனி','சித்திரை','வைகாசி','ஆனி', |
| | | 'ஆடி','ஆவணி','புரட்டாசி','ஐப்பசி','கார்த்திகை','மார்கழி'], |
| | | monthNamesShort: ['தை','மாசி','பங்','சித்','வைகா','ஆனி', |
| | | 'ஆடி','ஆவ','புர','ஐப்','கார்','மார்'], |
| | | dayNames: ['ஞாயிற்றுக்கிழமை','திங்கட்கிழமை','செவ்வாய்க்கிழமை','புதன்கிழமை','வியாழக்கிழமை','வெள்ளிக்கிழமை','சனிக்கிழமை'], |
| | | dayNamesShort: ['ஞாயிறு','திங்கள்','செவ்வாய்','புதன்','வியாழன்','வெள்ளி','சனி'], |
| | | dayNamesMin: ['ஞா','தி','செ','பு','வி','வெ','ச'], |
| | | weekHeader: 'Не', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ta']); |
| | | }); |
| | | /* Thai initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by pipo (pipo@sixhead.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['th'] = { |
| | | closeText: 'ปิด', |
| | | prevText: '« ย้อน', |
| | | nextText: 'ถัดไป »', |
| | | currentText: 'วันนี้', |
| | | monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน', |
| | | 'กรกฏาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'], |
| | | monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.', |
| | | 'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'], |
| | | dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'], |
| | | dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], |
| | | dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['th']); |
| | | });/* Turkish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Izzet Emre Erkan (kara@karalamalar.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['tr'] = { |
| | | closeText: 'kapat', |
| | | prevText: '<geri', |
| | | nextText: 'ileri>', |
| | | currentText: 'bugün', |
| | | monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran', |
| | | 'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'], |
| | | monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz', |
| | | 'Tem','Ağu','Eyl','Eki','Kas','Ara'], |
| | | dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'], |
| | | dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], |
| | | dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], |
| | | weekHeader: 'Hf', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['tr']); |
| | | });/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Maxim Drogobitskiy (maxdao@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['uk'] = { |
| | | closeText: 'Закрити', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Сьогодні', |
| | | monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень', |
| | | 'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'], |
| | | monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер', |
| | | 'Лип','Сер','Вер','Жов','Лис','Гру'], |
| | | dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'], |
| | | dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'], |
| | | dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'], |
| | | weekHeader: 'Не', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['uk']); |
| | | });/* Vietnamese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Translated by Le Thanh Huy (lthanhhuy@cit.ctu.edu.vn). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['vi'] = { |
| | | closeText: 'Đóng', |
| | | prevText: '<Trước', |
| | | nextText: 'Tiếp>', |
| | | currentText: 'Hôm nay', |
| | | monthNames: ['Tháng Một', 'Tháng Hai', 'Tháng Ba', 'Tháng Tư', 'Tháng Năm', 'Tháng Sáu', |
| | | 'Tháng Bảy', 'Tháng Tám', 'Tháng Chín', 'Tháng Mười', 'Tháng Mười Một', 'Tháng Mười Hai'], |
| | | monthNamesShort: ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', |
| | | 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'], |
| | | dayNames: ['Chủ Nhật', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy'], |
| | | dayNamesShort: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], |
| | | dayNamesMin: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], |
| | | weekHeader: 'Tu', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['vi']); |
| | | }); |
| | | /* Chinese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Cloudream (cloudream@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['zh-CN'] = { |
| | | closeText: '关闭', |
| | | prevText: '<上月', |
| | | nextText: '下月>', |
| | | currentText: '今天', |
| | | monthNames: ['一月','二月','三月','四月','五月','六月', |
| | | '七月','八月','九月','十月','十一月','十二月'], |
| | | monthNamesShort: ['一','二','三','四','五','六', |
| | | '七','八','九','十','十一','十二'], |
| | | dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], |
| | | dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], |
| | | dayNamesMin: ['日','一','二','三','四','五','六'], |
| | | weekHeader: '周', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['zh-CN']); |
| | | }); |
| | | /* Chinese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by SCCY (samuelcychan@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['zh-HK'] = { |
| | | closeText: '關閉', |
| | | prevText: '<上月', |
| | | nextText: '下月>', |
| | | currentText: '今天', |
| | | monthNames: ['一月','二月','三月','四月','五月','六月', |
| | | '七月','八月','九月','十月','十一月','十二月'], |
| | | monthNamesShort: ['一','二','三','四','五','六', |
| | | '七','八','九','十','十一','十二'], |
| | | dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], |
| | | dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], |
| | | dayNamesMin: ['日','一','二','三','四','五','六'], |
| | | weekHeader: '周', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['zh-HK']); |
| | | }); |
| | | /* Chinese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Ressol (ressol@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['zh-TW'] = { |
| | | closeText: '關閉', |
| | | prevText: '<上月', |
| | | nextText: '下月>', |
| | | currentText: '今天', |
| | | monthNames: ['一月','二月','三月','四月','五月','六月', |
| | | '七月','八月','九月','十月','十一月','十二月'], |
| | | monthNamesShort: ['一','二','三','四','五','六', |
| | | '七','八','九','十','十一','十二'], |
| | | dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], |
| | | dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], |
| | | dayNamesMin: ['日','一','二','三','四','五','六'], |
| | | weekHeader: '周', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['zh-TW']); |
| | | }); |
New file |
| | |
| | | /* Afrikaans initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Renier Pretorius. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['af'] = { |
| | | closeText: 'Selekteer', |
| | | prevText: 'Vorige', |
| | | nextText: 'Volgende', |
| | | currentText: 'Vandag', |
| | | monthNames: ['Januarie','Februarie','Maart','April','Mei','Junie', |
| | | 'Julie','Augustus','September','Oktober','November','Desember'], |
| | | monthNamesShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', |
| | | 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'], |
| | | dayNames: ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'], |
| | | dayNamesShort: ['Son', 'Maa', 'Din', 'Woe', 'Don', 'Vry', 'Sat'], |
| | | dayNamesMin: ['So','Ma','Di','Wo','Do','Vr','Sa'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['af']); |
| | | }); |
New file |
| | |
| | | /* Arabic Translation for jQuery UI date picker plugin. */ |
| | | /* Khaled Al Horani -- koko.dw@gmail.com */ |
| | | /* خالد الحوراني -- koko.dw@gmail.com */ |
| | | /* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ar'] = { |
| | | closeText: 'إغلاق', |
| | | prevText: '<السابق', |
| | | nextText: 'التالي>', |
| | | currentText: 'اليوم', |
| | | monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'آذار', 'حزيران', |
| | | 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], |
| | | monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], |
| | | dayNames: ['السبت', 'الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة'], |
| | | dayNamesShort: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], |
| | | dayNamesMin: ['سبت', 'أحد', 'اثنين', 'ثلاثاء', 'أربعاء', 'خميس', 'جمعة'], |
| | | weekHeader: 'أسبوع', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: true, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ar']); |
| | | }); |
New file |
| | |
| | | /* Azerbaijani (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jamil Najafov (necefov33@gmail.com). */ |
| | | jQuery(function($) { |
| | | $.datepicker.regional['az'] = { |
| | | closeText: 'Bağla', |
| | | prevText: '<Geri', |
| | | nextText: 'İrəli>', |
| | | currentText: 'Bugün', |
| | | monthNames: ['Yanvar','Fevral','Mart','Aprel','May','İyun', |
| | | 'İyul','Avqust','Sentyabr','Oktyabr','Noyabr','Dekabr'], |
| | | monthNamesShort: ['Yan','Fev','Mar','Apr','May','İyun', |
| | | 'İyul','Avq','Sen','Okt','Noy','Dek'], |
| | | dayNames: ['Bazar','Bazar ertəsi','Çərşənbə axşamı','Çərşənbə','Cümə axşamı','Cümə','Şənbə'], |
| | | dayNamesShort: ['B','Be','Ça','Ç','Ca','C','Ş'], |
| | | dayNamesMin: ['B','B','Ç','С','Ç','C','Ş'], |
| | | weekHeader: 'Hf', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['az']); |
| | | }); |
New file |
| | |
| | | /* Bulgarian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Stoyan Kyosev (http://svest.org). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['bg'] = { |
| | | closeText: 'затвори', |
| | | prevText: '<назад', |
| | | nextText: 'напред>', |
| | | nextBigText: '>>', |
| | | currentText: 'днес', |
| | | monthNames: ['Януари','Февруари','Март','Април','Май','Юни', |
| | | 'Юли','Август','Септември','Октомври','Ноември','Декември'], |
| | | monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни', |
| | | 'Юли','Авг','Сеп','Окт','Нов','Дек'], |
| | | dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'], |
| | | dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'], |
| | | dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['bg']); |
| | | }); |
New file |
| | |
| | | /* Bosnian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Kenan Konjo. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['bs'] = { |
| | | closeText: 'Zatvori', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Danas', |
| | | monthNames: ['Januar','Februar','Mart','April','Maj','Juni', |
| | | 'Juli','August','Septembar','Oktobar','Novembar','Decembar'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedelja','Ponedeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], |
| | | dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['bs']); |
| | | }); |
New file |
| | |
| | | /* Inicialització en català per a l'extenció 'calendar' per jQuery. */ |
| | | /* Writers: (joan.leon@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ca'] = { |
| | | closeText: 'Tancar', |
| | | prevText: '<Ant', |
| | | nextText: 'Seg>', |
| | | currentText: 'Avui', |
| | | monthNames: ['Gener','Febrer','Març','Abril','Maig','Juny', |
| | | 'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'], |
| | | monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun', |
| | | 'Jul','Ago','Set','Oct','Nov','Des'], |
| | | dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'], |
| | | dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'], |
| | | dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ca']); |
| | | }); |
New file |
| | |
| | | /* Czech initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Tomas Muller (tomas@tomas-muller.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['cs'] = { |
| | | closeText: 'Zavřít', |
| | | prevText: '<Dříve', |
| | | nextText: 'Později>', |
| | | currentText: 'Nyní', |
| | | monthNames: ['leden','únor','březen','duben','květen','červen', |
| | | 'červenec','srpen','září','říjen','listopad','prosinec'], |
| | | monthNamesShort: ['led','úno','bře','dub','kvě','čer', |
| | | 'čvc','srp','zář','říj','lis','pro'], |
| | | dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], |
| | | dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], |
| | | dayNamesMin: ['ne','po','út','st','čt','pá','so'], |
| | | weekHeader: 'Týd', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['cs']); |
| | | }); |
New file |
| | |
| | | /* Danish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jan Christensen ( deletestuff@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['da'] = { |
| | | closeText: 'Luk', |
| | | prevText: '<Forrige', |
| | | nextText: 'Næste>', |
| | | currentText: 'Idag', |
| | | monthNames: ['Januar','Februar','Marts','April','Maj','Juni', |
| | | 'Juli','August','September','Oktober','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], |
| | | dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], |
| | | dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], |
| | | weekHeader: 'Uge', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['da']); |
| | | }); |
New file |
| | |
| | | /* Swiss-German initialisation for the jQuery UI date picker plugin. */ |
| | | /* By Douglas Jose & Juerg Meier. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['de-CH'] = { |
| | | closeText: 'schliessen', |
| | | prevText: '<zurück', |
| | | nextText: 'nächster>', |
| | | currentText: 'heute', |
| | | monthNames: ['Januar','Februar','März','April','Mai','Juni', |
| | | 'Juli','August','September','Oktober','November','Dezember'], |
| | | monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dez'], |
| | | dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], |
| | | dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], |
| | | dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], |
| | | weekHeader: 'Wo', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['de-CH']); |
| | | }); |
New file |
| | |
| | | /* German initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Milian Wolff (mail@milianw.de). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['de'] = { |
| | | closeText: 'schließen', |
| | | prevText: '<zurück', |
| | | nextText: 'Vor>', |
| | | currentText: 'heute', |
| | | monthNames: ['Januar','Februar','März','April','Mai','Juni', |
| | | 'Juli','August','September','Oktober','November','Dezember'], |
| | | monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dez'], |
| | | dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], |
| | | dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], |
| | | dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], |
| | | weekHeader: 'Wo', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['de']); |
| | | }); |
New file |
| | |
| | | /* Greek (el) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Alex Cicovic (http://www.alexcicovic.com) */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['el'] = { |
| | | closeText: 'Κλείσιμο', |
| | | prevText: 'Προηγούμενος', |
| | | nextText: 'Επόμενος', |
| | | currentText: 'Τρέχων Μήνας', |
| | | monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος', |
| | | 'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'], |
| | | monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν', |
| | | 'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'], |
| | | dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'], |
| | | dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'], |
| | | dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'], |
| | | weekHeader: 'Εβδ', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['el']); |
| | | }); |
New file |
| | |
| | | /* English/UK initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Stuart. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['en-GB'] = { |
| | | closeText: 'Done', |
| | | prevText: 'Prev', |
| | | nextText: 'Next', |
| | | currentText: 'Today', |
| | | monthNames: ['January','February','March','April','May','June', |
| | | 'July','August','September','October','November','December'], |
| | | monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', |
| | | 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
| | | dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], |
| | | dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], |
| | | dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['en-GB']); |
| | | }); |
New file |
| | |
| | | /* Esperanto initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Olivier M. (olivierweb@ifrance.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['eo'] = { |
| | | closeText: 'Fermi', |
| | | prevText: '<Anta', |
| | | nextText: 'Sekv>', |
| | | currentText: 'Nuna', |
| | | monthNames: ['Januaro','Februaro','Marto','Aprilo','Majo','Junio', |
| | | 'Julio','Aŭgusto','Septembro','Oktobro','Novembro','Decembro'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aŭg','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Dimanĉo','Lundo','Mardo','Merkredo','Ĵaŭdo','Vendredo','Sabato'], |
| | | dayNamesShort: ['Dim','Lun','Mar','Mer','Ĵaŭ','Ven','Sab'], |
| | | dayNamesMin: ['Di','Lu','Ma','Me','Ĵa','Ve','Sa'], |
| | | weekHeader: 'Sb', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['eo']); |
| | | }); |
New file |
| | |
| | | /* Inicialización en español para la extensión 'UI date picker' para jQuery. */ |
| | | /* Traducido por Vester (xvester@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['es'] = { |
| | | closeText: 'Cerrar', |
| | | prevText: '<Ant', |
| | | nextText: 'Sig>', |
| | | currentText: 'Hoy', |
| | | monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', |
| | | 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], |
| | | monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', |
| | | 'Jul','Ago','Sep','Oct','Nov','Dic'], |
| | | dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], |
| | | dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], |
| | | dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['es']); |
| | | }); |
New file |
| | |
| | | /* Estonian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mart Sõmermaa (mrts.pydev at gmail com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['et'] = { |
| | | closeText: 'Sulge', |
| | | prevText: 'Eelnev', |
| | | nextText: 'Järgnev', |
| | | currentText: 'Täna', |
| | | monthNames: ['Jaanuar','Veebruar','Märts','Aprill','Mai','Juuni', |
| | | 'Juuli','August','September','Oktoober','November','Detsember'], |
| | | monthNamesShort: ['Jaan', 'Veebr', 'Märts', 'Apr', 'Mai', 'Juuni', |
| | | 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'], |
| | | dayNames: ['Pühapäev', 'Esmaspäev', 'Teisipäev', 'Kolmapäev', 'Neljapäev', 'Reede', 'Laupäev'], |
| | | dayNamesShort: ['Pühap', 'Esmasp', 'Teisip', 'Kolmap', 'Neljap', 'Reede', 'Laup'], |
| | | dayNamesMin: ['P','E','T','K','N','R','L'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['et']); |
| | | }); |
New file |
| | |
| | | /* Euskarako oinarria 'UI date picker' jquery-ko extentsioarentzat */ |
| | | /* Karrikas-ek itzulia (karrikas@karrikas.com) */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['eu'] = { |
| | | closeText: 'Egina', |
| | | prevText: '<Aur', |
| | | nextText: 'Hur>', |
| | | currentText: 'Gaur', |
| | | monthNames: ['Urtarrila','Otsaila','Martxoa','Apirila','Maiatza','Ekaina', |
| | | 'Uztaila','Abuztua','Iraila','Urria','Azaroa','Abendua'], |
| | | monthNamesShort: ['Urt','Ots','Mar','Api','Mai','Eka', |
| | | 'Uzt','Abu','Ira','Urr','Aza','Abe'], |
| | | dayNames: ['Igandea','Astelehena','Asteartea','Asteazkena','Osteguna','Ostirala','Larunbata'], |
| | | dayNamesShort: ['Iga','Ast','Ast','Ast','Ost','Ost','Lar'], |
| | | dayNamesMin: ['Ig','As','As','As','Os','Os','La'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['eu']); |
| | | }); |
New file |
| | |
| | | /* Persian (Farsi) Translation for the jQuery UI date picker plugin. */ |
| | | /* Javad Mowlanezhad -- jmowla@gmail.com */ |
| | | /* Jalali calendar should supported soon! (Its implemented but I have to test it) */ |
| | | jQuery(function($) { |
| | | $.datepicker.regional['fa'] = { |
| | | closeText: 'بستن', |
| | | prevText: '<قبلي', |
| | | nextText: 'بعدي>', |
| | | currentText: 'امروز', |
| | | monthNames: ['فروردين','ارديبهشت','خرداد','تير','مرداد','شهريور', |
| | | 'مهر','آبان','آذر','دي','بهمن','اسفند'], |
| | | monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], |
| | | dayNames: ['يکشنبه','دوشنبه','سهشنبه','چهارشنبه','پنجشنبه','جمعه','شنبه'], |
| | | dayNamesShort: ['ي','د','س','چ','پ','ج', 'ش'], |
| | | dayNamesMin: ['ي','د','س','چ','پ','ج', 'ش'], |
| | | weekHeader: 'هف', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 6, |
| | | isRTL: true, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fa']); |
| | | }); |
New file |
| | |
| | | /* Finnish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Harri Kilpi� (harrikilpio@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fi'] = { |
| | | closeText: 'Sulje', |
| | | prevText: '«Edellinen', |
| | | nextText: 'Seuraava»', |
| | | currentText: 'Tänään', |
| | | monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', |
| | | 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], |
| | | monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kesä', |
| | | 'Heinä','Elo','Syys','Loka','Marras','Joulu'], |
| | | dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','Su'], |
| | | dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'], |
| | | dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'], |
| | | weekHeader: 'Vk', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fi']); |
| | | }); |
New file |
| | |
| | | /* Faroese initialisation for the jQuery UI date picker plugin */ |
| | | /* Written by Sverri Mohr Olsen, sverrimo@gmail.com */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fo'] = { |
| | | closeText: 'Lat aftur', |
| | | prevText: '<Fyrra', |
| | | nextText: 'Næsta>', |
| | | currentText: 'Í dag', |
| | | monthNames: ['Januar','Februar','Mars','Apríl','Mei','Juni', |
| | | 'Juli','August','September','Oktober','November','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Des'], |
| | | dayNames: ['Sunnudagur','Mánadagur','Týsdagur','Mikudagur','Hósdagur','Fríggjadagur','Leyardagur'], |
| | | dayNamesShort: ['Sun','Mán','Týs','Mik','Hós','Frí','Ley'], |
| | | dayNamesMin: ['Su','Má','Tý','Mi','Hó','Fr','Le'], |
| | | weekHeader: 'Vk', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fo']); |
| | | }); |
New file |
| | |
| | | /* Swiss-French initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written Martin Voelkle (martin.voelkle@e-tc.ch). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fr-CH'] = { |
| | | closeText: 'Fermer', |
| | | prevText: '<Préc', |
| | | nextText: 'Suiv>', |
| | | currentText: 'Courant', |
| | | monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', |
| | | 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], |
| | | monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', |
| | | 'Jul','Aoû','Sep','Oct','Nov','Déc'], |
| | | dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], |
| | | dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], |
| | | dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fr-CH']); |
| | | }); |
New file |
| | |
| | | /* French initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Keith Wood (kbwood{at}iinet.com.au) and Stéphane Nahmani (sholby@sholby.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['fr'] = { |
| | | closeText: 'Fermer', |
| | | prevText: '<Préc', |
| | | nextText: 'Suiv>', |
| | | currentText: 'Courant', |
| | | monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', |
| | | 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], |
| | | monthNamesShort: ['Jan','Fév','Mar','Avr','Mai','Jun', |
| | | 'Jul','Aoû','Sep','Oct','Nov','Déc'], |
| | | dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], |
| | | dayNamesShort: ['Dim','Lun','Mar','Mer','Jeu','Ven','Sam'], |
| | | dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['fr']); |
| | | }); |
New file |
| | |
| | | /* Galician localization for 'UI date picker' jQuery extension. */ |
| | | /* Translated by Jorge Barreiro <yortx.barry@gmail.com>. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['gl'] = { |
| | | closeText: 'Pechar', |
| | | prevText: '<Ant', |
| | | nextText: 'Seg>', |
| | | currentText: 'Hoxe', |
| | | monthNames: ['Xaneiro','Febreiro','Marzo','Abril','Maio','Xuño', |
| | | 'Xullo','Agosto','Setembro','Outubro','Novembro','Decembro'], |
| | | monthNamesShort: ['Xan','Feb','Mar','Abr','Mai','Xuñ', |
| | | 'Xul','Ago','Set','Out','Nov','Dec'], |
| | | dayNames: ['Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado'], |
| | | dayNamesShort: ['Dom','Lun','Mar','Mér','Xov','Ven','Sáb'], |
| | | dayNamesMin: ['Do','Lu','Ma','Mé','Xo','Ve','Sá'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['gl']); |
| | | }); |
New file |
| | |
| | | /* Hebrew initialisation for the UI Datepicker extension. */ |
| | | /* Written by Amir Hardon (ahardon at gmail dot com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['he'] = { |
| | | closeText: 'סגור', |
| | | prevText: '<הקודם', |
| | | nextText: 'הבא>', |
| | | currentText: 'היום', |
| | | monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', |
| | | 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], |
| | | monthNamesShort: ['1','2','3','4','5','6', |
| | | '7','8','9','10','11','12'], |
| | | dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], |
| | | dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], |
| | | dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: true, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['he']); |
| | | }); |
New file |
| | |
| | | /* Croatian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Vjekoslav Nesek. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['hr'] = { |
| | | closeText: 'Zatvori', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Danas', |
| | | monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipanj', |
| | | 'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'], |
| | | monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip', |
| | | 'Srp','Kol','Ruj','Lis','Stu','Pro'], |
| | | dayNames: ['Nedjelja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], |
| | | dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], |
| | | weekHeader: 'Tje', |
| | | dateFormat: 'dd.mm.yy.', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['hr']); |
| | | }); |
New file |
| | |
| | | /* Hungarian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Istvan Karaszi (jquery@spam.raszi.hu). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['hu'] = { |
| | | closeText: 'bezárás', |
| | | prevText: '« vissza', |
| | | nextText: 'előre »', |
| | | currentText: 'ma', |
| | | monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', |
| | | 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], |
| | | monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', |
| | | 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], |
| | | dayNames: ['Vasárnap', 'Hétfö', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], |
| | | dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'], |
| | | dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], |
| | | weekHeader: 'Hé', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['hu']); |
| | | }); |
New file |
| | |
| | | /* Armenian(UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Levon Zakaryan (levon.zakaryan@gmail.com)*/ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['hy'] = { |
| | | closeText: 'Փակել', |
| | | prevText: '<Նախ.', |
| | | nextText: 'Հաջ.>', |
| | | currentText: 'Այսօր', |
| | | monthNames: ['Հունվար','Փետրվար','Մարտ','Ապրիլ','Մայիս','Հունիս', |
| | | 'Հուլիս','Օգոստոս','Սեպտեմբեր','Հոկտեմբեր','Նոյեմբեր','Դեկտեմբեր'], |
| | | monthNamesShort: ['Հունվ','Փետր','Մարտ','Ապր','Մայիս','Հունիս', |
| | | 'Հուլ','Օգս','Սեպ','Հոկ','Նոյ','Դեկ'], |
| | | dayNames: ['կիրակի','եկուշաբթի','երեքշաբթի','չորեքշաբթի','հինգշաբթի','ուրբաթ','շաբաթ'], |
| | | dayNamesShort: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'], |
| | | dayNamesMin: ['կիր','երկ','երք','չրք','հնգ','ուրբ','շբթ'], |
| | | weekHeader: 'ՇԲՏ', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['hy']); |
| | | }); |
New file |
| | |
| | | /* Indonesian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Deden Fathurahman (dedenf@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['id'] = { |
| | | closeText: 'Tutup', |
| | | prevText: '<mundur', |
| | | nextText: 'maju>', |
| | | currentText: 'hari ini', |
| | | monthNames: ['Januari','Februari','Maret','April','Mei','Juni', |
| | | 'Juli','Agustus','September','Oktober','Nopember','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', |
| | | 'Jul','Agus','Sep','Okt','Nop','Des'], |
| | | dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'], |
| | | dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'], |
| | | dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'], |
| | | weekHeader: 'Mg', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['id']); |
| | | }); |
New file |
| | |
| | | /* Icelandic initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Haukur H. Thorsson (haukur@eskill.is). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['is'] = { |
| | | closeText: 'Loka', |
| | | prevText: '< Fyrri', |
| | | nextText: 'Næsti >', |
| | | currentText: 'Í dag', |
| | | monthNames: ['Janúar','Febrúar','Mars','Apríl','Maí','Júní', |
| | | 'Júlí','Ágúst','September','Október','Nóvember','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maí','Jún', |
| | | 'Júl','Ágú','Sep','Okt','Nóv','Des'], |
| | | dayNames: ['Sunnudagur','Mánudagur','Þriðjudagur','Miðvikudagur','Fimmtudagur','Föstudagur','Laugardagur'], |
| | | dayNamesShort: ['Sun','Mán','Þri','Mið','Fim','Fös','Lau'], |
| | | dayNamesMin: ['Su','Má','Þr','Mi','Fi','Fö','La'], |
| | | weekHeader: 'Vika', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['is']); |
| | | }); |
New file |
| | |
| | | /* Italian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Antonello Pasella (antonello.pasella@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['it'] = { |
| | | closeText: 'Chiudi', |
| | | prevText: '<Prec', |
| | | nextText: 'Succ>', |
| | | currentText: 'Oggi', |
| | | monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', |
| | | 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], |
| | | monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', |
| | | 'Lug','Ago','Set','Ott','Nov','Dic'], |
| | | dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], |
| | | dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], |
| | | dayNamesMin: ['Do','Lu','Ma','Me','Gi','Ve','Sa'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['it']); |
| | | }); |
New file |
| | |
| | | /* Japanese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Kentaro SATO (kentaro@ranvis.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ja'] = { |
| | | closeText: '閉じる', |
| | | prevText: '<前', |
| | | nextText: '次>', |
| | | currentText: '今日', |
| | | monthNames: ['1月','2月','3月','4月','5月','6月', |
| | | '7月','8月','9月','10月','11月','12月'], |
| | | monthNamesShort: ['1月','2月','3月','4月','5月','6月', |
| | | '7月','8月','9月','10月','11月','12月'], |
| | | dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'], |
| | | dayNamesShort: ['日','月','火','水','木','金','土'], |
| | | dayNamesMin: ['日','月','火','水','木','金','土'], |
| | | weekHeader: '週', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ja']); |
| | | }); |
New file |
| | |
| | | /* Korean initialisation for the jQuery calendar extension. */ |
| | | /* Written by DaeKwon Kang (ncrash.dk@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ko'] = { |
| | | closeText: '닫기', |
| | | prevText: '이전달', |
| | | nextText: '다음달', |
| | | currentText: '오늘', |
| | | monthNames: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', |
| | | '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], |
| | | monthNamesShort: ['1월(JAN)','2월(FEB)','3월(MAR)','4월(APR)','5월(MAY)','6월(JUN)', |
| | | '7월(JUL)','8월(AUG)','9월(SEP)','10월(OCT)','11월(NOV)','12월(DEC)'], |
| | | dayNames: ['일','월','화','수','목','금','토'], |
| | | dayNamesShort: ['일','월','화','수','목','금','토'], |
| | | dayNamesMin: ['일','월','화','수','목','금','토'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: '년'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ko']); |
| | | }); |
New file |
| | |
| | | /* Kazakh (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Dmitriy Karasyov (dmitriy.karasyov@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['kz'] = { |
| | | closeText: 'Жабу', |
| | | prevText: '<Алдыңғы', |
| | | nextText: 'Келесі>', |
| | | currentText: 'Бүгін', |
| | | monthNames: ['Қаңтар','Ақпан','Наурыз','Сәуір','Мамыр','Маусым', |
| | | 'Шілде','Тамыз','Қыркүйек','Қазан','Қараша','Желтоқсан'], |
| | | monthNamesShort: ['Қаң','Ақп','Нау','Сәу','Мам','Мау', |
| | | 'Шіл','Там','Қыр','Қаз','Қар','Жел'], |
| | | dayNames: ['Жексенбі','Дүйсенбі','Сейсенбі','Сәрсенбі','Бейсенбі','Жұма','Сенбі'], |
| | | dayNamesShort: ['жкс','дсн','ссн','срс','бсн','жма','снб'], |
| | | dayNamesMin: ['Жк','Дс','Сс','Ср','Бс','Жм','Сн'], |
| | | weekHeader: 'Не', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['kz']); |
| | | }); |
New file |
| | |
| | | /* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* @author Arturas Paleicikas <arturas@avalon.lt> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['lt'] = { |
| | | closeText: 'Uždaryti', |
| | | prevText: '<Atgal', |
| | | nextText: 'Pirmyn>', |
| | | currentText: 'Šiandien', |
| | | monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis', |
| | | 'Liepa','Rugpjūtis','Rugsėjis','Spalis','Lapkritis','Gruodis'], |
| | | monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir', |
| | | 'Lie','Rugp','Rugs','Spa','Lap','Gru'], |
| | | dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'], |
| | | dayNamesShort: ['sek','pir','ant','tre','ket','pen','šeš'], |
| | | dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Še'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['lt']); |
| | | }); |
New file |
| | |
| | | /* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* @author Arturas Paleicikas <arturas.paleicikas@metasite.net> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['lv'] = { |
| | | closeText: 'Aizvērt', |
| | | prevText: 'Iepr', |
| | | nextText: 'Nāka', |
| | | currentText: 'Šodien', |
| | | monthNames: ['Janvāris','Februāris','Marts','Aprīlis','Maijs','Jūnijs', |
| | | 'Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jūn', |
| | | 'Jūl','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['svētdiena','pirmdiena','otrdiena','trešdiena','ceturtdiena','piektdiena','sestdiena'], |
| | | dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'], |
| | | dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'], |
| | | weekHeader: 'Nav', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['lv']); |
| | | }); |
New file |
| | |
| | | /* Malaysian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mohd Nawawi Mohamad Jamili (nawawi@ronggeng.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ms'] = { |
| | | closeText: 'Tutup', |
| | | prevText: '<Sebelum', |
| | | nextText: 'Selepas>', |
| | | currentText: 'hari ini', |
| | | monthNames: ['Januari','Februari','Mac','April','Mei','Jun', |
| | | 'Julai','Ogos','September','Oktober','November','Disember'], |
| | | monthNamesShort: ['Jan','Feb','Mac','Apr','Mei','Jun', |
| | | 'Jul','Ogo','Sep','Okt','Nov','Dis'], |
| | | dayNames: ['Ahad','Isnin','Selasa','Rabu','Khamis','Jumaat','Sabtu'], |
| | | dayNamesShort: ['Aha','Isn','Sel','Rab','kha','Jum','Sab'], |
| | | dayNamesMin: ['Ah','Is','Se','Ra','Kh','Ju','Sa'], |
| | | weekHeader: 'Mg', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ms']); |
| | | }); |
New file |
| | |
| | | /* Dutch/Belgian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mathias Bynens <http://mathiasbynens.be/> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['nl-BE'] = { |
| | | closeText: 'Sluiten', |
| | | prevText: '←', |
| | | nextText: '→', |
| | | currentText: 'Vandaag', |
| | | monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', |
| | | 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], |
| | | monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun', |
| | | 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], |
| | | dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], |
| | | dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], |
| | | dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['nl-BE']); |
| | | }); |
New file |
| | |
| | | /* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Mathias Bynens <http://mathiasbynens.be/> */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional.nl = { |
| | | closeText: 'Sluiten', |
| | | prevText: '←', |
| | | nextText: '→', |
| | | currentText: 'Vandaag', |
| | | monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', |
| | | 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], |
| | | monthNamesShort: ['jan', 'feb', 'maa', 'apr', 'mei', 'jun', |
| | | 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], |
| | | dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], |
| | | dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], |
| | | dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional.nl); |
| | | }); |
New file |
| | |
| | | /* Norwegian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Naimdjon Takhirov (naimdjon@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['no'] = { |
| | | closeText: 'Lukk', |
| | | prevText: '«Forrige', |
| | | nextText: 'Neste»', |
| | | currentText: 'I dag', |
| | | monthNames: ['Januar','Februar','Mars','April','Mai','Juni', |
| | | 'Juli','August','September','Oktober','November','Desember'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Des'], |
| | | dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], |
| | | dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], |
| | | dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], |
| | | weekHeader: 'Uke', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['no']); |
| | | }); |
New file |
| | |
| | | /* Polish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['pl'] = { |
| | | closeText: 'Zamknij', |
| | | prevText: '<Poprzedni', |
| | | nextText: 'Następny>', |
| | | currentText: 'Dziś', |
| | | monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', |
| | | 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], |
| | | monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze', |
| | | 'Lip','Sie','Wrz','Pa','Lis','Gru'], |
| | | dayNames: ['Niedziela','Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota'], |
| | | dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'], |
| | | dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'], |
| | | weekHeader: 'Tydz', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['pl']); |
| | | }); |
New file |
| | |
| | | /* Brazilian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Leonildo Costa Silva (leocsilva@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['pt-BR'] = { |
| | | closeText: 'Fechar', |
| | | prevText: '<Anterior', |
| | | nextText: 'Próximo>', |
| | | currentText: 'Hoje', |
| | | monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', |
| | | 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], |
| | | monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', |
| | | 'Jul','Ago','Set','Out','Nov','Dez'], |
| | | dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], |
| | | dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | weekHeader: 'Sm', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['pt-BR']); |
| | | }); |
New file |
| | |
| | | /* Portuguese initialisation for the jQuery UI date picker plugin. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['pt'] = { |
| | | closeText: 'Fechar', |
| | | prevText: '<Anterior', |
| | | nextText: 'Seguinte', |
| | | currentText: 'Hoje', |
| | | monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', |
| | | 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], |
| | | monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', |
| | | 'Jul','Ago','Set','Out','Nov','Dez'], |
| | | dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], |
| | | dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], |
| | | weekHeader: 'Sem', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['pt']); |
| | | }); |
New file |
| | |
| | | /* Romanian initialisation for the jQuery UI date picker plugin. |
| | | * |
| | | * Written by Edmond L. (ll_edmond@walla.com) |
| | | * and Ionut G. Stan (ionut.g.stan@gmail.com) |
| | | */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ro'] = { |
| | | closeText: 'Închide', |
| | | prevText: '« Luna precedentă', |
| | | nextText: 'Luna următoare »', |
| | | currentText: 'Azi', |
| | | monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie', |
| | | 'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], |
| | | monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', |
| | | 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
| | | dayNames: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], |
| | | dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], |
| | | dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'], |
| | | weekHeader: 'Săpt', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ro']); |
| | | }); |
New file |
| | |
| | | /* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Andrew Stromnov (stromnov@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ru'] = { |
| | | closeText: 'Закрыть', |
| | | prevText: '<Пред', |
| | | nextText: 'След>', |
| | | currentText: 'Сегодня', |
| | | monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', |
| | | 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], |
| | | monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', |
| | | 'Июл','Авг','Сен','Окт','Ноя','Дек'], |
| | | dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], |
| | | dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], |
| | | dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], |
| | | weekHeader: 'Нед', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ru']); |
| | | }); |
New file |
| | |
| | | /* Slovak initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Vojtech Rinik (vojto@hmm.sk). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sk'] = { |
| | | closeText: 'Zavrieť', |
| | | prevText: '<Predchádzajúci', |
| | | nextText: 'Nasledujúci>', |
| | | currentText: 'Dnes', |
| | | monthNames: ['Január','Február','Marec','Apríl','Máj','Jún', |
| | | 'Júl','August','September','Október','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún', |
| | | 'Júl','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedel\'a','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Str','Štv','Pia','Sob'], |
| | | dayNamesMin: ['Ne','Po','Ut','St','Št','Pia','So'], |
| | | weekHeader: 'Ty', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sk']); |
| | | }); |
New file |
| | |
| | | /* Slovenian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Jaka Jancar (jaka@kubje.org). */ |
| | | /* c = č, s = š z = ž C = Č S = Š Z = Ž */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sl'] = { |
| | | closeText: 'Zapri', |
| | | prevText: '<Prejšnji', |
| | | nextText: 'Naslednji>', |
| | | currentText: 'Trenutni', |
| | | monthNames: ['Januar','Februar','Marec','April','Maj','Junij', |
| | | 'Julij','Avgust','September','Oktober','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Avg','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota'], |
| | | dayNamesShort: ['Ned','Pon','Tor','Sre','Čet','Pet','Sob'], |
| | | dayNamesMin: ['Ne','Po','To','Sr','Če','Pe','So'], |
| | | weekHeader: 'Teden', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sl']); |
| | | }); |
New file |
| | |
| | | /* Albanian initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Flakron Bytyqi (flakron@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sq'] = { |
| | | closeText: 'mbylle', |
| | | prevText: '<mbrapa', |
| | | nextText: 'Përpara>', |
| | | currentText: 'sot', |
| | | monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor', |
| | | 'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'], |
| | | monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer', |
| | | 'Kor','Gus','Sht','Tet','Nën','Dhj'], |
| | | dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'], |
| | | dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'], |
| | | dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'], |
| | | weekHeader: 'Ja', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sq']); |
| | | }); |
New file |
| | |
| | | /* Serbian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Dejan Dimić. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sr-SR'] = { |
| | | closeText: 'Zatvori', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Danas', |
| | | monthNames: ['Januar','Februar','Mart','April','Maj','Jun', |
| | | 'Jul','Avgust','Septembar','Oktobar','Novembar','Decembar'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Avg','Sep','Okt','Nov','Dec'], |
| | | dayNames: ['Nedelja','Ponedeljak','Utorak','Sreda','Četvrtak','Petak','Subota'], |
| | | dayNamesShort: ['Ned','Pon','Uto','Sre','Čet','Pet','Sub'], |
| | | dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], |
| | | weekHeader: 'Sed', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sr-SR']); |
| | | }); |
New file |
| | |
| | | /* Serbian i18n for the jQuery UI date picker plugin. */ |
| | | /* Written by Dejan Dimić. */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sr'] = { |
| | | closeText: 'Затвори', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Данас', |
| | | monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун', |
| | | 'Јул','Август','Септембар','Октобар','Новембар','Децембар'], |
| | | monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун', |
| | | 'Јул','Авг','Сеп','Окт','Нов','Дец'], |
| | | dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'], |
| | | dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'], |
| | | dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'], |
| | | weekHeader: 'Сед', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sr']); |
| | | }); |
New file |
| | |
| | | /* Swedish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Anders Ekdahl ( anders@nomadiz.se). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['sv'] = { |
| | | closeText: 'Stäng', |
| | | prevText: '«Förra', |
| | | nextText: 'Nästa»', |
| | | currentText: 'Idag', |
| | | monthNames: ['Januari','Februari','Mars','April','Maj','Juni', |
| | | 'Juli','Augusti','September','Oktober','November','December'], |
| | | monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', |
| | | 'Jul','Aug','Sep','Okt','Nov','Dec'], |
| | | dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'], |
| | | dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'], |
| | | dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'], |
| | | weekHeader: 'Ve', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['sv']); |
| | | }); |
New file |
| | |
| | | /* Tamil (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by S A Sureshkumar (saskumar@live.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['ta'] = { |
| | | closeText: 'மூடு', |
| | | prevText: 'முன்னையது', |
| | | nextText: 'அடுத்தது', |
| | | currentText: 'இன்று', |
| | | monthNames: ['தை','மாசி','பங்குனி','சித்திரை','வைகாசி','ஆனி', |
| | | 'ஆடி','ஆவணி','புரட்டாசி','ஐப்பசி','கார்த்திகை','மார்கழி'], |
| | | monthNamesShort: ['தை','மாசி','பங்','சித்','வைகா','ஆனி', |
| | | 'ஆடி','ஆவ','புர','ஐப்','கார்','மார்'], |
| | | dayNames: ['ஞாயிற்றுக்கிழமை','திங்கட்கிழமை','செவ்வாய்க்கிழமை','புதன்கிழமை','வியாழக்கிழமை','வெள்ளிக்கிழமை','சனிக்கிழமை'], |
| | | dayNamesShort: ['ஞாயிறு','திங்கள்','செவ்வாய்','புதன்','வியாழன்','வெள்ளி','சனி'], |
| | | dayNamesMin: ['ஞா','தி','செ','பு','வி','வெ','ச'], |
| | | weekHeader: 'Не', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['ta']); |
| | | }); |
New file |
| | |
| | | /* Thai initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by pipo (pipo@sixhead.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['th'] = { |
| | | closeText: 'ปิด', |
| | | prevText: '« ย้อน', |
| | | nextText: 'ถัดไป »', |
| | | currentText: 'วันนี้', |
| | | monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน', |
| | | 'กรกฏาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'], |
| | | monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.', |
| | | 'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'], |
| | | dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'], |
| | | dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], |
| | | dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], |
| | | weekHeader: 'Wk', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['th']); |
| | | }); |
New file |
| | |
| | | /* Turkish initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Izzet Emre Erkan (kara@karalamalar.net). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['tr'] = { |
| | | closeText: 'kapat', |
| | | prevText: '<geri', |
| | | nextText: 'ileri>', |
| | | currentText: 'bugün', |
| | | monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran', |
| | | 'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'], |
| | | monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz', |
| | | 'Tem','Ağu','Eyl','Eki','Kas','Ara'], |
| | | dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'], |
| | | dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], |
| | | dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], |
| | | weekHeader: 'Hf', |
| | | dateFormat: 'dd.mm.yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['tr']); |
| | | }); |
New file |
| | |
| | | /* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Maxim Drogobitskiy (maxdao@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['uk'] = { |
| | | closeText: 'Закрити', |
| | | prevText: '<', |
| | | nextText: '>', |
| | | currentText: 'Сьогодні', |
| | | monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень', |
| | | 'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'], |
| | | monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер', |
| | | 'Лип','Сер','Вер','Жов','Лис','Гру'], |
| | | dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'], |
| | | dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'], |
| | | dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'], |
| | | weekHeader: 'Не', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['uk']); |
| | | }); |
New file |
| | |
| | | /* Vietnamese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Translated by Le Thanh Huy (lthanhhuy@cit.ctu.edu.vn). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['vi'] = { |
| | | closeText: 'Đóng', |
| | | prevText: '<Trước', |
| | | nextText: 'Tiếp>', |
| | | currentText: 'Hôm nay', |
| | | monthNames: ['Tháng Một', 'Tháng Hai', 'Tháng Ba', 'Tháng Tư', 'Tháng Năm', 'Tháng Sáu', |
| | | 'Tháng Bảy', 'Tháng Tám', 'Tháng Chín', 'Tháng Mười', 'Tháng Mười Một', 'Tháng Mười Hai'], |
| | | monthNamesShort: ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', |
| | | 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'], |
| | | dayNames: ['Chủ Nhật', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy'], |
| | | dayNamesShort: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], |
| | | dayNamesMin: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], |
| | | weekHeader: 'Tu', |
| | | dateFormat: 'dd/mm/yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: false, |
| | | yearSuffix: ''}; |
| | | $.datepicker.setDefaults($.datepicker.regional['vi']); |
| | | }); |
New file |
| | |
| | | /* Chinese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Cloudream (cloudream@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['zh-CN'] = { |
| | | closeText: '关闭', |
| | | prevText: '<上月', |
| | | nextText: '下月>', |
| | | currentText: '今天', |
| | | monthNames: ['一月','二月','三月','四月','五月','六月', |
| | | '七月','八月','九月','十月','十一月','十二月'], |
| | | monthNamesShort: ['一','二','三','四','五','六', |
| | | '七','八','九','十','十一','十二'], |
| | | dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], |
| | | dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], |
| | | dayNamesMin: ['日','一','二','三','四','五','六'], |
| | | weekHeader: '周', |
| | | dateFormat: 'yy-mm-dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['zh-CN']); |
| | | }); |
New file |
| | |
| | | /* Chinese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by SCCY (samuelcychan@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['zh-HK'] = { |
| | | closeText: '關閉', |
| | | prevText: '<上月', |
| | | nextText: '下月>', |
| | | currentText: '今天', |
| | | monthNames: ['一月','二月','三月','四月','五月','六月', |
| | | '七月','八月','九月','十月','十一月','十二月'], |
| | | monthNamesShort: ['一','二','三','四','五','六', |
| | | '七','八','九','十','十一','十二'], |
| | | dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], |
| | | dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], |
| | | dayNamesMin: ['日','一','二','三','四','五','六'], |
| | | weekHeader: '周', |
| | | dateFormat: 'dd-mm-yy', |
| | | firstDay: 0, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['zh-HK']); |
| | | }); |
New file |
| | |
| | | /* Chinese initialisation for the jQuery UI date picker plugin. */ |
| | | /* Written by Ressol (ressol@gmail.com). */ |
| | | jQuery(function($){ |
| | | $.datepicker.regional['zh-TW'] = { |
| | | closeText: '關閉', |
| | | prevText: '<上月', |
| | | nextText: '下月>', |
| | | currentText: '今天', |
| | | monthNames: ['一月','二月','三月','四月','五月','六月', |
| | | '七月','八月','九月','十月','十一月','十二月'], |
| | | monthNamesShort: ['一','二','三','四','五','六', |
| | | '七','八','九','十','十一','十二'], |
| | | dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], |
| | | dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], |
| | | dayNamesMin: ['日','一','二','三','四','五','六'], |
| | | weekHeader: '周', |
| | | dateFormat: 'yy/mm/dd', |
| | | firstDay: 1, |
| | | isRTL: false, |
| | | showMonthAfterYear: true, |
| | | yearSuffix: '年'}; |
| | | $.datepicker.setDefaults($.datepicker.regional['zh-TW']); |
| | | }); |
New file |
| | |
| | | /*! |
| | | * jQuery UI 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI |
| | | */ |
| | | (function(c,j){function k(a,b){var d=a.nodeName.toLowerCase();if("area"===d){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&l(a)}return(/input|select|textarea|button|object/.test(d)?!a.disabled:"a"==d?a.href||b:b)&&l(a)}function l(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.14", |
| | | keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus(); |
| | | b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this, |
| | | "overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection", |
| | | function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,m,n){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(m)g-=parseFloat(c.curCSS(f,"border"+this+"Width",true))||0;if(n)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth, |
| | | outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){return k(a,!isNaN(c.attr(a,"tabindex")))},tabbable:function(a){var b=c.attr(a,"tabindex"),d=isNaN(b); |
| | | return(d||b>=0)&&k(a,!d)}});c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e= |
| | | 0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery); |
| | | ;/*! |
| | | * jQuery UI Widget 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Widget |
| | | */ |
| | | (function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h, |
| | | a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h; |
| | | e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options, |
| | | this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")}, |
| | | widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this}, |
| | | enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery); |
| | | ;/*! |
| | | * jQuery UI Mouse 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Mouse |
| | | * |
| | | * Depends: |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(b){var d=false;b(document).mousedown(function(){d=false});b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+ |
| | | this.widgetName)},_mouseDown:function(a){if(!d){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,f=a.which==1,g=typeof this.options.cancel=="string"?b(a.target).closest(this.options.cancel).length:false;if(!f||g||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!== |
| | | false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(e){return c._mouseMove(e)};this._mouseUpDelegate=function(e){return c._mouseUp(e)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return d=true}},_mouseMove:function(a){if(b.browser.msie&& |
| | | !(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted= |
| | | false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Position 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Position |
| | | */ |
| | | (function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, |
| | | left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= |
| | | k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= |
| | | m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= |
| | | d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= |
| | | a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), |
| | | g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Draggable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Draggables |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper== |
| | | "original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b= |
| | | this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;d(b.iframeFix===true?"iframe":b.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")});return true},_mouseStart:function(a){var b=this.options;this.helper= |
| | | this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); |
| | | this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);d.ui.ddmanager&&d.ui.ddmanager.dragStart(this,a);return true}, |
| | | _mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b= |
| | | false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration, |
| | | 10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},_mouseUp:function(a){this.options.iframeFix===true&&d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});d.ui.ddmanager&&d.ui.ddmanager.dragStop(this,a);return d.ui.mouse.prototype._mouseUp.call(this,a)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle|| |
| | | !d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone().removeAttr("id"):this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&& |
| | | a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent= |
| | | this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"), |
| | | 10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), |
| | | 10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[a.containment=="document"?0:d(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,a.containment=="document"?0:d(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, |
| | | (a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){a=d(a.containment);var b=a[0];if(b){a.offset();var c=d(b).css("overflow")!= |
| | | "hidden";this.containment=[(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"), |
| | | 10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=a}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+ |
| | | this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&& |
| | | !(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,h=a.pageY;if(this.originalPosition){var g;if(this.containment){if(this.relative_container){g=this.relative_container.offset();g=[this.containment[0]+g.left,this.containment[1]+g.top,this.containment[2]+g.left,this.containment[3]+g.top]}else g=this.containment;if(a.pageX-this.offset.click.left<g[0])e=g[0]+this.offset.click.left; |
| | | if(a.pageY-this.offset.click.top<g[1])h=g[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>g[2])e=g[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>g[3])h=g[3]+this.offset.click.top}if(b.grid){h=b.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/b.grid[1])*b.grid[1]:this.originalPageY;h=g?!(h-this.offset.click.top<g[1]||h-this.offset.click.top>g[3])?h:!(h-this.offset.click.top<g[1])?h-b.grid[1]:h+b.grid[1]:h;e=b.grid[0]?this.originalPageX+Math.round((e-this.originalPageX)/ |
| | | b.grid[0])*b.grid[0]:this.originalPageX;e=g?!(e-this.offset.click.left<g[0]||e-this.offset.click.left>g[2])?e:!(e-this.offset.click.left<g[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version< |
| | | 526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b, |
| | | c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.14"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var h=d.data(this,"sortable");if(h&&!h.options.disabled){c.sortables.push({instance:h,shouldRevert:h.options.revert}); |
| | | h.refreshPositions();h._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval= |
| | | false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().removeAttr("id").appendTo(this.instance.element).data("sortable-item",true); |
| | | this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top; |
| | | c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&& |
| | | this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity= |
| | | a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!= |
| | | "x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left< |
| | | c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()- |
| | | c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this, |
| | | width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,h=b.offset.left,g=h+c.helperProportions.width,n=b.offset.top,o=n+c.helperProportions.height,i=c.snapElements.length-1;i>=0;i--){var j=c.snapElements[i].left,l=j+c.snapElements[i].width,k=c.snapElements[i].top,m=k+c.snapElements[i].height;if(j-e<h&&h<l+e&&k-e<n&&n<m+e||j-e<h&&h<l+e&&k-e<o&&o<m+e||j-e<g&&g<l+e&&k-e<n&&n<m+e||j-e<g&&g<l+e&&k-e<o&& |
| | | o<m+e){if(f.snapMode!="inner"){var p=Math.abs(k-o)<=e,q=Math.abs(m-n)<=e,r=Math.abs(j-g)<=e,s=Math.abs(l-h)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l}).left-c.margins.left}var t= |
| | | p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(k-n)<=e;q=Math.abs(m-o)<=e;r=Math.abs(j-h)<=e;s=Math.abs(l-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:k,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:m-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:j}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:l-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[i].snapping&& |
| | | (p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=p||q||r||s||t}else{c.snapElements[i].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[i].item}));c.snapElements[i].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"), |
| | | 10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Droppable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Droppables |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.draggable.js |
| | | */ |
| | | (function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this); |
| | | a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&& |
| | | this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass); |
| | | this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g= |
| | | d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop", |
| | | a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.14"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height; |
| | | switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>= |
| | | i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!= |
| | | "none";if(c[f].visible){e=="mousedown"&&c[f]._activate.call(c[f],b);c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight}}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem|| |
| | | a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},dragStart:function(a,b){a.element.parentsUntil("body").bind("scroll.droppable",function(){a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)})},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c= |
| | | !c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})},dragStop:function(a,b){a.element.parentsUntil("body").unbind("scroll.droppable"); |
| | | a.options.refreshPositions||d.ui.ddmanager.prepareOffsets(a,b)}}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Resizable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Resizables |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element, |
| | | _proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(), |
| | | top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle= |
| | | this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne", |
| | | nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor== |
| | | String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),l=0;l=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,l);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection(); |
| | | this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){if(!a.disabled){e(this).removeClass("ui-resizable-autohide");b._handles.show()}},function(){if(!a.disabled)if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy(); |
| | | var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a= |
| | | false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"}); |
| | | this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff= |
| | | {width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis]; |
| | | if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false}, |
| | | _mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f, |
| | | {top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateVirtualBoundaries:function(b){var a=this.options,c,d,f;a={minWidth:k(a.minWidth)?a.minWidth:0,maxWidth:k(a.maxWidth)?a.maxWidth:Infinity,minHeight:k(a.minHeight)?a.minHeight:0,maxHeight:k(a.maxHeight)?a.maxHeight: |
| | | Infinity};if(this._aspectRatio||b){b=a.minHeight*this.aspectRatio;d=a.minWidth/this.aspectRatio;c=a.maxHeight*this.aspectRatio;f=a.maxWidth/this.aspectRatio;if(b>a.minWidth)a.minWidth=b;if(d>a.minHeight)a.minHeight=d;if(c<a.maxWidth)a.maxWidth=c;if(f<a.maxHeight)a.maxHeight=f}this._vBoundaries=a},_updateCache:function(b){this.offset=this.helper.offset();if(k(b.left))this.position.left=b.left;if(k(b.top))this.position.top=b.top;if(k(b.height))this.size.height=b.height;if(k(b.width))this.size.width= |
| | | b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(k(b.height))b.width=b.height*this.aspectRatio;else if(k(b.width))b.height=b.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this._vBoundaries,c=this.axis,d=k(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=k(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=k(b.width)&&a.minWidth&& |
| | | a.minWidth>b.width,h=k(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,l=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&l)b.left=i-a.minWidth;if(d&&l)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left= |
| | | null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)|| |
| | | 0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+ |
| | | a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+ |
| | | c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]); |
| | | b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.14"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(), |
| | | 10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top- |
| | | f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var l=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:l.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(l.css("position"))){c._revertToRelativePosition=true;l.css({position:"absolute",top:"auto",left:"auto"})}l.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType? |
| | | e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a= |
| | | e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing, |
| | | step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement= |
| | | e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset; |
| | | var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left: |
| | | a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top- |
| | | d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition, |
| | | f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25, |
| | | display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b= |
| | | e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height= |
| | | d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},k=function(b){return!isNaN(parseInt(b,10))}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Selectable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Selectables |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"), |
| | | selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX, |
| | | c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting", |
| | | c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d= |
| | | this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting"); |
| | | a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&& |
| | | !a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d= |
| | | e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.14"})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Sortable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Sortables |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){var a=this.options;this.containerCache={};this.element.addClass("ui-sortable"); |
| | | this.refresh();this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a=== |
| | | "disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&& |
| | | !b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top, |
| | | left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]}; |
| | | this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!= |
| | | document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a); |
| | | return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top< |
| | | b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()- |
| | | b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this, |
| | | a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0], |
| | | e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset(); |
| | | c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"): |
| | | this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null, |
| | | dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")}, |
| | | toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers|| |
| | | this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection(); |
| | | var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)}, |
| | | _getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith(); |
| | | if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), |
| | | this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element), |
| | | this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&& |
| | | this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b];if(!(c.instance!=this.currentContainer&&this.currentContainer&&c.item[0]!=this.currentItem[0])){var e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b= |
| | | this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f= |
| | | d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")|| |
| | | 0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out", |
| | | a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h- |
| | | f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b= |
| | | this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width== |
| | | ""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top= |
| | | this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a= |
| | | {top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"), |
| | | 10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"? |
| | | document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"), |
| | | 10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b= |
| | | this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&& |
| | | this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset(); |
| | | var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g- |
| | | this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g- |
| | | this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0], |
| | | this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]= |
| | | "";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove", |
| | | f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this, |
| | | this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop", |
| | | a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()}, |
| | | _uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.14"})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Accordion 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Accordion |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"); |
| | | a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom"); |
| | | if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion", |
| | | function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a= |
| | | this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"); |
| | | this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons(); |
| | | b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target); |
| | | a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+ |
| | | c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options; |
| | | if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header); |
| | | if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(), |
| | | e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight|| |
| | | e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false", |
| | | "aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.14", |
| | | animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/); |
| | | f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide", |
| | | paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Autocomplete 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Autocomplete |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | * jquery.ui.position.js |
| | | */ |
| | | (function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){g= |
| | | false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!= |
| | | a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)}; |
| | | this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& |
| | | a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); |
| | | d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& |
| | | b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= |
| | | this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close(); |
| | | this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label|| |
| | | b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this; |
| | | d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, |
| | | "\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); |
| | | (function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", |
| | | -1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); |
| | | this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, |
| | | this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| |
| | | this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| |
| | | this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element[d.fn.prop?"prop":"attr"]("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Button 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Button |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(b){var h,i,j,g,l=function(){var a=b(this).find(":ui-button");setTimeout(function(){a.button("refresh")},1)},k=function(a){var c=a.name,e=a.form,f=b([]);if(c)f=e?b(e).find("[name='"+c+"']"):b("[name='"+c+"']",a.ownerDocument).filter(function(){return!this.form});return f};b.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",l);if(typeof this.options.disabled!== |
| | | "boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var a=this,c=this.options,e=this.type==="checkbox"||this.type==="radio",f="ui-state-hover"+(!e?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",function(){if(!c.disabled){b(this).addClass("ui-state-hover"); |
| | | this===h&&b(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||b(this).removeClass(f)}).bind("click.button",function(d){if(c.disabled){d.preventDefault();d.stopImmediatePropagation()}});this.element.bind("focus.button",function(){a.buttonElement.addClass("ui-state-focus")}).bind("blur.button",function(){a.buttonElement.removeClass("ui-state-focus")});if(e){this.element.bind("change.button",function(){g||a.refresh()});this.buttonElement.bind("mousedown.button",function(d){if(!c.disabled){g= |
| | | false;i=d.pageX;j=d.pageY}}).bind("mouseup.button",function(d){if(!c.disabled)if(i!==d.pageX||j!==d.pageY)g=true})}if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled||g)return false;b(this).toggleClass("ui-state-active");a.buttonElement.attr("aria-pressed",a.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled||g)return false;b(this).addClass("ui-state-active");a.buttonElement.attr("aria-pressed",true); |
| | | var d=a.element[0];k(d).not(d).map(function(){return b(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;b(this).addClass("ui-state-active");h=this;b(document).one("mouseup",function(){h=null})}).bind("mouseup.button",function(){if(c.disabled)return false;b(this).removeClass("ui-state-active")}).bind("keydown.button",function(d){if(c.disabled)return false;if(d.keyCode==b.ui.keyCode.SPACE|| |
| | | d.keyCode==b.ui.keyCode.ENTER)b(this).addClass("ui-state-active")}).bind("keyup.button",function(){b(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(d){d.keyCode===b.ui.keyCode.SPACE&&b(this).click()})}this._setOption("disabled",c.disabled);this._resetButton()},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type=== |
| | | "radio"){var a=this.element.parents().filter(":last"),c="label[for="+this.element.attr("id")+"]";this.buttonElement=a.find(c);if(!this.buttonElement.length){a=a.length?a.siblings():this.element.siblings();this.buttonElement=a.filter(c);if(!this.buttonElement.length)this.buttonElement=a.find(c)}this.element.addClass("ui-helper-hidden-accessible");(a=this.element.is(":checked"))&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",a)}else this.buttonElement=this.element}, |
| | | widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||this.buttonElement.removeAttr("title"); |
| | | b.Widget.prototype.destroy.call(this)},_setOption:function(a,c){b.Widget.prototype._setOption.apply(this,arguments);if(a==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");else this._resetButton()},refresh:function(){var a=this.element.is(":disabled");a!==this.options.disabled&&this._setOption("disabled",a);if(this.type==="radio")k(this.element[0]).each(function(){b(this).is(":checked")?b(this).button("widget").addClass("ui-state-active").attr("aria-pressed",true): |
| | | b(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var a=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"), |
| | | c=b("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("<span class='ui-button-icon-primary ui-icon "+e.primary+"'></span>");e.secondary&&a.append("<span class='ui-button-icon-secondary ui-icon "+e.secondary+"'></span>");if(!this.options.text){d.push(f?"ui-button-icons-only": |
| | | "ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")=== |
| | | "ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); |
| | | b.Widget.prototype.destroy.call(this)}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Dialog 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Dialog |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | * jquery.ui.button.js |
| | | * jquery.ui.draggable.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.position.js |
| | | * jquery.ui.resizable.js |
| | | */ |
| | | (function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, |
| | | position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ |
| | | b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), |
| | | h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id", |
| | | e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); |
| | | a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== |
| | | b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+= |
| | | 1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== |
| | | f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, |
| | | function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('<button type="button"></button>').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", |
| | | handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, |
| | | originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", |
| | | f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): |
| | | [a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); |
| | | if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): |
| | | e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= |
| | | this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- |
| | | b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.14",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), |
| | | create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(), |
| | | height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight); |
| | | b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a= |
| | | a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Slider 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Slider |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.mouse.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options,c=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f=a.values&&a.values.length||1,e=[];this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+ |
| | | this.orientation+" ui-widget ui-widget-content ui-corner-all"+(a.disabled?" ui-slider-disabled ui-disabled":""));this.range=d([]);if(a.range){if(a.range===true){if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}this.range=d("<div></div>").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(a.range==="min"||a.range==="max"?" ui-slider-range-"+a.range:""))}for(var j=c.length;j<f;j+=1)e.push("<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>"); |
| | | this.handles=c.add(d(e.join("")).appendTo(b.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", |
| | | g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!b.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");i=b._start(g,l);if(i===false)return}break}m=b.options.step;i=b.options.values&&b.options.values.length? |
| | | (h=b.values(l)):(h=b.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=b._valueMin();break;case d.ui.keyCode.END:h=b._valueMax();break;case d.ui.keyCode.PAGE_UP:h=b._trimAlignValue(i+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=b._trimAlignValue(i-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===b._valueMax())return;h=b._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===b._valueMin())return;h=b._trimAlignValue(i- |
| | | m);break}b._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(g,k);b._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); |
| | | return this},_mouseCapture:function(b){var a=this.options,c,f,e,j,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(a.range===true&&this.values(1)===a.min){g+=1;e=d(this.handles[g])}if(this._start(b,g)===false)return false; |
| | | this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();a=e.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-e.width()/2,top:b.pageY-a.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(b){var a= |
| | | this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;if(this.orientation==="horizontal"){a= |
| | | this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a); |
| | | c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var f;if(this.options.values&&this.options.values.length){f=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>f||a===1&&c<f))c=f;if(c!==this.values(a)){f=this.values();f[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:f});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],value:c}); |
| | | b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value= |
| | | this._trimAlignValue(b);this._refreshValue();this._change(null,0)}else return this._value()},values:function(b,a){var c,f,e;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e<c.length;e+=1){c[e]=this._trimAlignValue(f[e]);this._change(null,e)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b): |
| | | this.value();else return this._values()},_setOption:function(b,a){var c,f=0;if(d.isArray(this.options.values))f=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation(); |
| | | this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<f;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b]; |
| | | return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max}, |
| | | _refreshValue:function(){var b=this.options.range,a=this.options,c=this,f=!this._animateOff?a.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},a.animate); |
| | | if(h===1)c.range[f?"animate":"css"]({width:e-g+"%"},{queue:false,duration:a.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},a.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:a.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1, |
| | | 1)[f?"animate":"css"]({width:e+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.14"})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Tabs 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Tabs |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& |
| | | e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= |
| | | d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| |
| | | (q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); |
| | | this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= |
| | | this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); |
| | | if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); |
| | | this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ |
| | | g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", |
| | | function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; |
| | | this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= |
| | | -1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; |
| | | d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= |
| | | d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, |
| | | e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); |
| | | j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); |
| | | if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, |
| | | this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, |
| | | load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, |
| | | "cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, |
| | | url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.14"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&& |
| | | a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Datepicker 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Datepicker |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | */ |
| | | (function(d,C){function M(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass= |
| | | "ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su", |
| | | "Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10", |
| | | minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=N(d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}function N(a){return a.bind("mouseout",function(b){b= |
| | | d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");b.addClass("ui-state-hover"); |
| | | b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.14"}});var A=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){H(this._defaults, |
| | | a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0, |
| | | selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]= |
| | | h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c= |
| | | this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a, |
| | | "autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker", |
| | | function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput); |
| | | a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left", |
| | | this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus", |
| | | this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b= |
| | | b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5", |
| | | cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false}, |
| | | _getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true),i=this._getMinMaxDate(e,"min"),g=this._getMinMaxDate(e, |
| | | "max");H(e.settings,f);if(i!==null&&f.dateFormat!==C&&f.minDate===C)e.settings.minDate=this._formatDate(e,i);if(g!==null&&f.dateFormat!==C&&f.maxDate===C)e.settings.maxDate=this._formatDate(e,g);this._attachments(d(a),e);this._autoSize(e);this._setDate(e,h);this._updateAlternate(e);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a, |
| | | b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv); |
| | | c[0]?d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target); |
| | | c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey|| |
| | | a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b= |
| | | d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==C?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a); |
| | | d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c= |
| | | d.datepicker._get(b,"beforeShow");H(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c= |
| | | {left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover"); |
| | | if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing=true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv); |
| | | J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"); |
| | | a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]|| |
| | | c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+ |
| | | i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b= |
| | | this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute", |
| | | left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&& |
| | | d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth= |
| | | b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear= |
| | | !b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a); |
| | | a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a)); |
| | | d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()% |
| | | 100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=B+1<a.length&&a.charAt(B+1)==p)&&B++;return p},m=function(p){var D=o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&D?4:p=="o"?3:2)+"}");p=b.substring(q).match(p);if(!p)throw"Missing number at position "+q;q+= |
| | | p[0].length;return parseInt(p[0],10)},n=function(p,D,K){p=d.map(o(p)?K:D,function(w,x){return[[x,w]]}).sort(function(w,x){return-(w[1].length-x[1].length)});var E=-1;d.each(p,function(w,x){w=x[1];if(b.substr(q,w.length).toLowerCase()==w.toLowerCase()){E=x[0];q+=w.length;return false}});if(E!=-1)return E+1;else throw"Unknown name at position "+q;},s=function(){if(b.charAt(q)!=a.charAt(B))throw"Unexpected literal at position "+q;q++},q=0,B=0;B<a.length;B++)if(k)if(a.charAt(B)=="'"&&!o("'"))k=false; |
| | | else s();else switch(a.charAt(B)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();j=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();j=v.getMonth()+1;l=v.getDate();break;case "'":if(o("'"))s();else k=true;break;default:s()}if(q<b.length)throw"Extra/unparsed characters found in date: "+b.substring(q); |
| | | if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y", |
| | | TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length< |
| | | n;)m="0"+m;return m},j=function(o,m,n,s){return i(o)?s[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5),3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",b.getMonth(),h, |
| | | c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+= |
| | | "0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==C?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth= |
| | | f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g= |
| | | (h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j, |
| | | l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay= |
| | | a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(), |
| | | b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n= |
| | | this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+A+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+ |
| | | (c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+A+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+s+'"><span class="ui-icon ui-icon-circle-triangle-'+ |
| | | (c?"w":"e")+'">'+s+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+A+'.datepicker._hideDatepicker();">'+this._get(a, |
| | | "closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,s)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+A+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),B= |
| | | this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x<i[0];x++){var O="";this.maxRows=4;for(var G=0;G<i[1];G++){var P=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",y="";if(l){y+='<div class="ui-datepicker-group';if(i[1]>1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right": |
| | | "left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,B,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var z=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>": |
| | | "";for(t=0;t<7;t++){var r=(t+h)%7;z+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+s[r]+'">'+q[r]+"</span></th>"}y+=z+"</tr></thead><tbody>";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q<z;Q++){y+="<tr>";var R=!j?"":'<td class="ui-datepicker-week-col">'+ |
| | | this._get(a,"calculateWeek")(r)+"</td>";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&r<k||o&&r>o;R+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(F?" ui-datepicker-other-month":"")+(r.getTime()==P.getTime()&&g==a.selectedMonth&&a._keyEvent||E.getTime()==r.getTime()&&E.getTime()==P.getTime()?" "+this._dayOverClass:"")+(L?" "+this._unselectableClass+" ui-state-disabled":"")+(F&&!D?"":" "+I[1]+(r.getTime()==u.getTime()?" "+ |
| | | this._currentClass:"")+(r.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!F||D)&&I[2]?' title="'+I[2]+'"':"")+(L?"":' onclick="DP_jQuery_'+A+".datepicker._selectDay('#"+a.id+"',"+r.getMonth()+","+r.getFullYear()+', this);return false;"')+">"+(F&&!D?" ":L?'<span class="ui-state-default">'+r.getDate()+"</span>":'<a class="ui-state-default'+(r.getTime()==b.getTime()?" ui-state-highlight":"")+(r.getTime()==u.getTime()?" ui-state-active":"")+(F?" ui-priority-secondary":"")+'" href="#">'+ |
| | | r.getDate()+"</a>")+"</td>";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+"</tr>"}g++;if(g>11){g=0;m++}y+="</tbody></table>"+(l?"</div>"+(i[0]>0&&G==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"), |
| | | l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+A+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+A+".datepicker._clickMonthYear('#"+a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+ |
| | | n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()): |
| | | g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+A+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+A+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c== |
| | | "Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear"); |
| | | if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a); |
| | | c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a, |
| | | "dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker= |
| | | function(a){if(!this.length)return this;if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker, |
| | | [this[0]].concat(b));return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.14";window["DP_jQuery_"+A]=d})(jQuery); |
| | | ;/* |
| | | * jQuery UI Progressbar 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Progressbar |
| | | * |
| | | * Depends: |
| | | * jquery.ui.core.js |
| | | * jquery.ui.widget.js |
| | | */ |
| | | (function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); |
| | | this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* |
| | | this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.14"})})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/ |
| | | */ |
| | | jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], |
| | | 16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, |
| | | a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= |
| | | a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", |
| | | "borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, |
| | | 0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, |
| | | 211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, |
| | | d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; |
| | | f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, |
| | | [{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.14",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b= |
| | | 0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}); |
| | | c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c, |
| | | a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments); |
| | | a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%", |
| | | "pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d* |
| | | ((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/= |
| | | e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/= |
| | | e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/ |
| | | h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5* |
| | | h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c, |
| | | e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Blind 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Blind |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","bottom","left","right"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a, |
| | | g);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Bounce 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Bounce |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","bottom","left","right"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/ |
| | | 3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a); |
| | | b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Clip 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Clip |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","bottom","left","right","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position, |
| | | c/2)}var h={};h[g.size]=f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Drop 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Drop |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e== |
| | | "show"?1:0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Explode 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Explode |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f= |
| | | 0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ |
| | | e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Fade 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Fade |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Fold 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Fold |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], |
| | | 10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Highlight 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Highlight |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& |
| | | this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Pulsate 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Pulsate |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration, |
| | | a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Scale 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Scale |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a, |
| | | b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity= |
| | | 1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],g=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"], |
| | | p=c.effects.setMode(a,b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}}; |
| | | if(m=="box"||m=="both"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a); |
| | | a.css("overflow","hidden").css(a.from);if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from); |
| | | child.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a, |
| | | n?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Shake 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Shake |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","bottom","left","right"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]= |
| | | (h=="pos"?"-=":"+=")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Slide 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Slide |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e); |
| | | var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); |
| | | ;/* |
| | | * jQuery UI Effects Transfer 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Effects/Transfer |
| | | * |
| | | * Depends: |
| | | * jquery.effects.core.js |
| | | */ |
| | | (function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); |
| | | b.dequeue()})})}})(jQuery); |
| | | ; |
New file |
| | |
| | | /* |
| | | * jQuery UI CSS Framework 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Theming/API |
| | | */ |
| | | |
| | | /* Layout helpers |
| | | ----------------------------------*/ |
| | | .ui-helper-hidden { display: none; } |
| | | .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } |
| | | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } |
| | | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } |
| | | .ui-helper-clearfix { display: inline-block; } |
| | | /* required comment for clearfix to work in Opera \*/ |
| | | * html .ui-helper-clearfix { height:1%; } |
| | | .ui-helper-clearfix { display:block; } |
| | | /* end clearfix */ |
| | | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } |
| | | |
| | | |
| | | /* Interaction Cues |
| | | ----------------------------------*/ |
| | | .ui-state-disabled { cursor: default !important; } |
| | | |
| | | |
| | | /* Icons |
| | | ----------------------------------*/ |
| | | |
| | | /* states and images */ |
| | | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } |
| | | |
| | | |
| | | /* Misc visuals |
| | | ----------------------------------*/ |
| | | |
| | | /* Overlays */ |
| | | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } |
| | | |
| | | |
| | | /* |
| | | * jQuery UI CSS Framework 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Theming/API |
| | | * |
| | | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller&ffDefault=Lucida%20Grande,%20Verdana,%20Arial,%20Helvetica,%20sans-serif&fwDefault=normal&fsDefault=1em&cornerRadius=0&bgColorHeader=f4f4f4&bgTextureHeader=04_highlight_hard.png&bgImgOpacityHeader=90&borderColorHeader=999999&fcHeader=333333&iconColorHeader=333333&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=000000&iconColorContent=000000&bgColorDefault=e6e6e7&bgTextureDefault=04_highlight_hard.png&bgImgOpacityDefault=90&borderColorDefault=aaaaaa&fcDefault=000000&iconColorDefault=666666&bgColorHover=e6e6e7&bgTextureHover=04_highlight_hard.png&bgImgOpacityHover=90&borderColorHover=999999&fcHover=000000&iconColorHover=333333&bgColorActive=a3a3a3&bgTextureActive=04_highlight_hard.png&bgImgOpacityActive=90&borderColorActive=a4a4a4&fcActive=000000&iconColorActive=333333&bgColorHighlight=cc3333&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=90&borderColorHighlight=cc3333&fcHighlight=ffffff&iconColorHighlight=dddddd&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cc3333&fcError=cc3333&iconColorError=cc3333&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=35&thicknessShadow=6px&offsetTopShadow=-6px&offsetLeftShadow=-6px&cornerRadiusShadow=6px |
| | | */ |
| | | |
| | | |
| | | /* Component containers |
| | | ----------------------------------*/ |
| | | .ui-widget { font-family: Lucida Grande, Verdana, Arial, Helvetica, sans-serif; font-size: 1em; } |
| | | .ui-widget .ui-widget { font-size: 1em; } |
| | | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Verdana, Arial, Helvetica, sans-serif; font-size: 1em; } |
| | | .ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #000000; } |
| | | .ui-widget-content a { color: #000000; } |
| | | .ui-widget-header { border: 1px solid #999999; border-width: 0 0 1px 0; background: #f4f4f4 url(images/listheader.png) 50% 50% repeat; color: #333333; font-weight: bold; margin: -0.2em -0.2em 0 -0.2em; } |
| | | .ui-widget-header a { color: #333333; } |
| | | |
| | | /* Interaction states |
| | | ----------------------------------*/ |
| | | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #aaaaaa; background: #e6e6e7 url(images/ui-bg_highlight-hard_90_e6e6e7_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #000000; } |
| | | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #000000; text-decoration: none; } |
| | | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #e6e6e7 url(images/ui-bg_highlight-hard_90_e6e6e7_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #000000; } |
| | | .ui-state-hover a, .ui-state-hover a:hover { color: #000000; text-decoration: none; } |
| | | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #a4a4a4; background: #a3a3a3 url(images/ui-bg_highlight-hard_90_a3a3a3_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #000000; } |
| | | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #000000; text-decoration: none; } |
| | | .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #c33; color: #a00; } |
| | | .ui-tabs-nav .ui-state-focus { border: 1px solid #a4a4a4; color: #000000; } |
| | | .ui-widget :active { outline: none; } |
| | | |
| | | /* Interaction Cues |
| | | ----------------------------------*/ |
| | | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #cc3333; background: #cc3333 url(images/ui-bg_flat_90_cc3333_40x100.png) 50% 50% repeat-x; color: #ffffff; } |
| | | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #ffffff; } |
| | | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cc3333; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cc3333; } |
| | | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cc3333; } |
| | | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cc3333; } |
| | | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } |
| | | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .6; filter:Alpha(Opacity=60); font-weight: normal; } |
| | | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } |
| | | |
| | | /* Icons |
| | | ----------------------------------*/ |
| | | |
| | | /* states and images */ |
| | | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_000000_256x240.png); } |
| | | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_000000_256x240.png); } |
| | | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_333333_256x240.png); } |
| | | .ui-state-default .ui-icon { background-image: url(images/ui-icons_666666_256x240.png); } |
| | | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_333333_256x240.png); } |
| | | .ui-state-active .ui-icon {background-image: url(images/ui-icons_333333_256x240.png); } |
| | | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_dddddd_256x240.png); } |
| | | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cc3333_256x240.png); } |
| | | |
| | | /* positioning */ |
| | | .ui-icon-carat-1-n { background-position: 0 0; } |
| | | .ui-icon-carat-1-ne { background-position: -16px 0; } |
| | | .ui-icon-carat-1-e { background-position: -32px 0; } |
| | | .ui-icon-carat-1-se { background-position: -48px 0; } |
| | | .ui-icon-carat-1-s { background-position: -64px 0; } |
| | | .ui-icon-carat-1-sw { background-position: -80px 0; } |
| | | .ui-icon-carat-1-w { background-position: -96px 0; } |
| | | .ui-icon-carat-1-nw { background-position: -112px 0; } |
| | | .ui-icon-carat-2-n-s { background-position: -128px 0; } |
| | | .ui-icon-carat-2-e-w { background-position: -144px 0; } |
| | | .ui-icon-triangle-1-n { background-position: 0 -16px; } |
| | | .ui-icon-triangle-1-ne { background-position: -16px -16px; } |
| | | .ui-icon-triangle-1-e { background-position: -32px -16px; } |
| | | .ui-icon-triangle-1-se { background-position: -48px -16px; } |
| | | .ui-icon-triangle-1-s { background-position: -64px -16px; } |
| | | .ui-icon-triangle-1-sw { background-position: -80px -16px; } |
| | | .ui-icon-triangle-1-w { background-position: -96px -16px; } |
| | | .ui-icon-triangle-1-nw { background-position: -112px -16px; } |
| | | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } |
| | | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } |
| | | .ui-icon-arrow-1-n { background-position: 0 -32px; } |
| | | .ui-icon-arrow-1-ne { background-position: -16px -32px; } |
| | | .ui-icon-arrow-1-e { background-position: -32px -32px; } |
| | | .ui-icon-arrow-1-se { background-position: -48px -32px; } |
| | | .ui-icon-arrow-1-s { background-position: -64px -32px; } |
| | | .ui-icon-arrow-1-sw { background-position: -80px -32px; } |
| | | .ui-icon-arrow-1-w { background-position: -96px -32px; } |
| | | .ui-icon-arrow-1-nw { background-position: -112px -32px; } |
| | | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } |
| | | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } |
| | | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } |
| | | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } |
| | | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } |
| | | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } |
| | | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } |
| | | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } |
| | | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } |
| | | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } |
| | | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } |
| | | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } |
| | | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } |
| | | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } |
| | | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } |
| | | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } |
| | | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } |
| | | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } |
| | | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } |
| | | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } |
| | | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } |
| | | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } |
| | | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } |
| | | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } |
| | | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } |
| | | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } |
| | | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } |
| | | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } |
| | | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } |
| | | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } |
| | | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } |
| | | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } |
| | | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } |
| | | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } |
| | | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } |
| | | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } |
| | | .ui-icon-arrow-4 { background-position: 0 -80px; } |
| | | .ui-icon-arrow-4-diag { background-position: -16px -80px; } |
| | | .ui-icon-extlink { background-position: -32px -80px; } |
| | | .ui-icon-newwin { background-position: -48px -80px; } |
| | | .ui-icon-refresh { background-position: -64px -80px; } |
| | | .ui-icon-shuffle { background-position: -80px -80px; } |
| | | .ui-icon-transfer-e-w { background-position: -96px -80px; } |
| | | .ui-icon-transferthick-e-w { background-position: -112px -80px; } |
| | | .ui-icon-folder-collapsed { background-position: 0 -96px; } |
| | | .ui-icon-folder-open { background-position: -16px -96px; } |
| | | .ui-icon-document { background-position: -32px -96px; } |
| | | .ui-icon-document-b { background-position: -48px -96px; } |
| | | .ui-icon-note { background-position: -64px -96px; } |
| | | .ui-icon-mail-closed { background-position: -80px -96px; } |
| | | .ui-icon-mail-open { background-position: -96px -96px; } |
| | | .ui-icon-suitcase { background-position: -112px -96px; } |
| | | .ui-icon-comment { background-position: -128px -96px; } |
| | | .ui-icon-person { background-position: -144px -96px; } |
| | | .ui-icon-print { background-position: -160px -96px; } |
| | | .ui-icon-trash { background-position: -176px -96px; } |
| | | .ui-icon-locked { background-position: -192px -96px; } |
| | | .ui-icon-unlocked { background-position: -208px -96px; } |
| | | .ui-icon-bookmark { background-position: -224px -96px; } |
| | | .ui-icon-tag { background-position: -240px -96px; } |
| | | .ui-icon-home { background-position: 0 -112px; } |
| | | .ui-icon-flag { background-position: -16px -112px; } |
| | | .ui-icon-calendar { background-position: -32px -112px; } |
| | | .ui-icon-cart { background-position: -48px -112px; } |
| | | .ui-icon-pencil { background-position: -64px -112px; } |
| | | .ui-icon-clock { background-position: -80px -112px; } |
| | | .ui-icon-disk { background-position: -96px -112px; } |
| | | .ui-icon-calculator { background-position: -112px -112px; } |
| | | .ui-icon-zoomin { background-position: -128px -112px; } |
| | | .ui-icon-zoomout { background-position: -144px -112px; } |
| | | .ui-icon-search { background-position: -160px -112px; } |
| | | .ui-icon-wrench { background-position: -176px -112px; } |
| | | .ui-icon-gear { background-position: -192px -112px; } |
| | | .ui-icon-heart { background-position: -208px -112px; } |
| | | .ui-icon-star { background-position: -224px -112px; } |
| | | .ui-icon-link { background-position: -240px -112px; } |
| | | .ui-icon-cancel { background-position: 0 -128px; } |
| | | .ui-icon-plus { background-position: -16px -128px; } |
| | | .ui-icon-plusthick { background-position: -32px -128px; } |
| | | .ui-icon-minus { background-position: -48px -128px; } |
| | | .ui-icon-minusthick { background-position: -64px -128px; } |
| | | .ui-icon-close { background-position: -80px -128px; } |
| | | .ui-icon-closethick { background-position: -96px -128px; } |
| | | .ui-icon-key { background-position: -112px -128px; } |
| | | .ui-icon-lightbulb { background-position: -128px -128px; } |
| | | .ui-icon-scissors { background-position: -144px -128px; } |
| | | .ui-icon-clipboard { background-position: -160px -128px; } |
| | | .ui-icon-copy { background-position: -176px -128px; } |
| | | .ui-icon-contact { background-position: -192px -128px; } |
| | | .ui-icon-image { background-position: -208px -128px; } |
| | | .ui-icon-video { background-position: -224px -128px; } |
| | | .ui-icon-script { background-position: -240px -128px; } |
| | | .ui-icon-alert { background-position: 0 -144px; } |
| | | .ui-icon-info { background-position: -16px -144px; } |
| | | .ui-icon-notice { background-position: -32px -144px; } |
| | | .ui-icon-help { background-position: -48px -144px; } |
| | | .ui-icon-check { background-position: -64px -144px; } |
| | | .ui-icon-bullet { background-position: -80px -144px; } |
| | | .ui-icon-radio-off { background-position: -96px -144px; } |
| | | .ui-icon-radio-on { background-position: -112px -144px; } |
| | | .ui-icon-pin-w { background-position: -128px -144px; } |
| | | .ui-icon-pin-s { background-position: -144px -144px; } |
| | | .ui-icon-play { background-position: 0 -160px; } |
| | | .ui-icon-pause { background-position: -16px -160px; } |
| | | .ui-icon-seek-next { background-position: -32px -160px; } |
| | | .ui-icon-seek-prev { background-position: -48px -160px; } |
| | | .ui-icon-seek-end { background-position: -64px -160px; } |
| | | .ui-icon-seek-start { background-position: -80px -160px; } |
| | | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ |
| | | .ui-icon-seek-first { background-position: -80px -160px; } |
| | | .ui-icon-stop { background-position: -96px -160px; } |
| | | .ui-icon-eject { background-position: -112px -160px; } |
| | | .ui-icon-volume-off { background-position: -128px -160px; } |
| | | .ui-icon-volume-on { background-position: -144px -160px; } |
| | | .ui-icon-power { background-position: 0 -176px; } |
| | | .ui-icon-signal-diag { background-position: -16px -176px; } |
| | | .ui-icon-signal { background-position: -32px -176px; } |
| | | .ui-icon-battery-0 { background-position: -48px -176px; } |
| | | .ui-icon-battery-1 { background-position: -64px -176px; } |
| | | .ui-icon-battery-2 { background-position: -80px -176px; } |
| | | .ui-icon-battery-3 { background-position: -96px -176px; } |
| | | .ui-icon-circle-plus { background-position: 0 -192px; } |
| | | .ui-icon-circle-minus { background-position: -16px -192px; } |
| | | .ui-icon-circle-close { background-position: -32px -192px; } |
| | | .ui-icon-circle-triangle-e { background-position: -48px -192px; } |
| | | .ui-icon-circle-triangle-s { background-position: -64px -192px; } |
| | | .ui-icon-circle-triangle-w { background-position: -80px -192px; } |
| | | .ui-icon-circle-triangle-n { background-position: -96px -192px; } |
| | | .ui-icon-circle-arrow-e { background-position: -112px -192px; } |
| | | .ui-icon-circle-arrow-s { background-position: -128px -192px; } |
| | | .ui-icon-circle-arrow-w { background-position: -144px -192px; } |
| | | .ui-icon-circle-arrow-n { background-position: -160px -192px; } |
| | | .ui-icon-circle-zoomin { background-position: -176px -192px; } |
| | | .ui-icon-circle-zoomout { background-position: -192px -192px; } |
| | | .ui-icon-circle-check { background-position: -208px -192px; } |
| | | .ui-icon-circlesmall-plus { background-position: 0 -208px; } |
| | | .ui-icon-circlesmall-minus { background-position: -16px -208px; } |
| | | .ui-icon-circlesmall-close { background-position: -32px -208px; } |
| | | .ui-icon-squaresmall-plus { background-position: -48px -208px; } |
| | | .ui-icon-squaresmall-minus { background-position: -64px -208px; } |
| | | .ui-icon-squaresmall-close { background-position: -80px -208px; } |
| | | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } |
| | | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } |
| | | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } |
| | | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } |
| | | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } |
| | | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } |
| | | |
| | | |
| | | /* Misc visuals |
| | | ----------------------------------*/ |
| | | |
| | | /* Corner radius */ |
| | | .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 0; -webkit-border-top-left-radius: 0; -khtml-border-top-left-radius: 0; border-top-left-radius: 0; } |
| | | .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 0; -webkit-border-top-right-radius: 0; -khtml-border-top-right-radius: 0; border-top-right-radius: 0; } |
| | | .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; -khtml-border-bottom-left-radius: 0; border-bottom-left-radius: 0; } |
| | | .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; -khtml-border-bottom-right-radius: 0; border-bottom-right-radius: 0; } |
| | | |
| | | /* Overlays */ |
| | | .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } |
| | | .ui-widget-shadow { margin: -6px 0 0 -6px; padding: 6px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .35;filter:Alpha(Opacity=35); -moz-border-radius: 6px; -khtml-border-radius: 6px; -webkit-border-radius: 6px; border-radius: 6px; }/* |
| | | * jQuery UI Resizable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Resizable#theming |
| | | */ |
| | | .ui-resizable { position: relative;} |
| | | .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } |
| | | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } |
| | | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } |
| | | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } |
| | | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } |
| | | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } |
| | | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } |
| | | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } |
| | | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } |
| | | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* |
| | | * jQuery UI Selectable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Selectable#theming |
| | | */ |
| | | .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } |
| | | /* |
| | | * jQuery UI Accordion 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Accordion#theming |
| | | */ |
| | | /* IE/Win - Fix animation bug - #4615 */ |
| | | .ui-accordion { width: 100%; } |
| | | .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } |
| | | .ui-accordion .ui-accordion-li-fix { display: inline; } |
| | | .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } |
| | | .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } |
| | | .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } |
| | | .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } |
| | | .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } |
| | | .ui-accordion .ui-accordion-content-active { display: block; } |
| | | /* |
| | | * jQuery UI Autocomplete 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Autocomplete#theming |
| | | */ |
| | | .ui-autocomplete { position: absolute; cursor: default; } |
| | | |
| | | /* workarounds */ |
| | | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ |
| | | |
| | | #ui-active-menuitem { background:#c33; border-color:#a22; color:#fff; } |
| | | |
| | | /* |
| | | * jQuery UI Menu 1.8.14 |
| | | * |
| | | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Menu#theming |
| | | */ |
| | | .ui-menu { |
| | | list-style:none; |
| | | padding: 2px; |
| | | margin: 0; |
| | | display:block; |
| | | float: left; |
| | | box-shadow: 1px 1px 18px #999; |
| | | -moz-box-shadow: 1px 1px 12px #999; |
| | | -webkit-box-shadow: #999 1px 1px 12px; |
| | | } |
| | | .ui-menu .ui-menu { |
| | | margin-top: -3px; |
| | | } |
| | | .ui-menu .ui-menu-item { |
| | | margin:0; |
| | | padding: 0; |
| | | zoom: 1; |
| | | float: left; |
| | | clear: left; |
| | | width: 100%; |
| | | } |
| | | .ui-menu .ui-menu-item a { |
| | | text-decoration:none; |
| | | display:block; |
| | | padding:.2em .4em; |
| | | line-height:1.5; |
| | | zoom:1; |
| | | } |
| | | .ui-menu .ui-menu-item a.ui-state-hover, |
| | | .ui-menu .ui-menu-item a.ui-state-active { |
| | | font-weight: normal; |
| | | margin: -1px; |
| | | } |
| | | /* |
| | | * jQuery UI Button 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Button#theming |
| | | */ |
| | | .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: default; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ |
| | | .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ |
| | | button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ |
| | | .ui-button-icons-only { width: 3.4em; } |
| | | button.ui-button-icons-only { width: 3.7em; } |
| | | button.ui-button-text-only, a.ui-button-text-only { background-image: url(images/buttongradient.png) !important; } |
| | | |
| | | /*button text element */ |
| | | .ui-button .ui-button-text { display: block; line-height: 1.4; } |
| | | .ui-button-text-only .ui-button-text { padding: .3em 1em; } |
| | | .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } |
| | | .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } |
| | | .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } |
| | | .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } |
| | | /* no icon support for input elements, provide padding by default */ |
| | | input.ui-button { padding: .4em 1em; } |
| | | |
| | | /*button icon element(s) */ |
| | | .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } |
| | | .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } |
| | | .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } |
| | | .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } |
| | | .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } |
| | | |
| | | /*button sets*/ |
| | | .ui-buttonset { margin-right: 7px; } |
| | | .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } |
| | | |
| | | /* workarounds */ |
| | | button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ |
| | | /* |
| | | * jQuery UI Dialog 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Dialog#theming |
| | | */ |
| | | .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; box-shadow: 1px 1px 18px #999; -moz-box-shadow: 1px 1px 12px #999; -webkit-box-shadow: #999 1px 1px 12px; } |
| | | .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } |
| | | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } |
| | | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } |
| | | .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } |
| | | .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } |
| | | .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } |
| | | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } |
| | | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } |
| | | .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: default; } |
| | | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } |
| | | .ui-draggable .ui-dialog-titlebar { cursor: move; } |
| | | /* |
| | | * jQuery UI Slider 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Slider#theming |
| | | */ |
| | | .ui-slider { position: relative; text-align: left; } |
| | | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } |
| | | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } |
| | | |
| | | .ui-slider-horizontal { height: .8em; } |
| | | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } |
| | | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } |
| | | .ui-slider-horizontal .ui-slider-range-min { left: 0; } |
| | | .ui-slider-horizontal .ui-slider-range-max { right: 0; } |
| | | |
| | | .ui-slider-vertical { width: .8em; height: 100px; } |
| | | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } |
| | | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } |
| | | .ui-slider-vertical .ui-slider-range-min { bottom: 0; } |
| | | .ui-slider-vertical .ui-slider-range-max { top: 0; }/* |
| | | * jQuery UI Tabs 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Tabs#theming |
| | | */ |
| | | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ |
| | | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } |
| | | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 0 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; border-top-left-radius: 2px; -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; border-top-right-radius: 2px; } |
| | | .ui-tabs .ui-tabs-nav li a { float: left; padding: .3em 1em; text-decoration: none; } |
| | | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } |
| | | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } |
| | | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ |
| | | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } |
| | | .ui-tabs .ui-tabs-hide { display: none !important; } |
| | | |
| | | .ui-dialog .ui-tabs .ui-tabs-nav li.ui-tabs-selected { background:#fff; } |
| | | |
| | | /* |
| | | * jQuery UI Datepicker 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Datepicker#theming |
| | | */ |
| | | .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; box-shadow: 1px 1px 18px #999; -moz-box-shadow: 1px 1px 12px #999; -webkit-box-shadow: #999 1px 1px 12px; } |
| | | .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } |
| | | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } |
| | | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } |
| | | .ui-datepicker .ui-datepicker-prev { left:2px; } |
| | | .ui-datepicker .ui-datepicker-next { right:2px; } |
| | | .ui-datepicker .ui-datepicker-prev-hover { left:1px; } |
| | | .ui-datepicker .ui-datepicker-next-hover { right:1px; } |
| | | .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } |
| | | .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } |
| | | .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } |
| | | .ui-datepicker select.ui-datepicker-month-year {width: 100%;} |
| | | .ui-datepicker select.ui-datepicker-month, |
| | | .ui-datepicker select.ui-datepicker-year { width: 49%;} |
| | | .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } |
| | | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } |
| | | .ui-datepicker td { border: 0; padding: 1px; } |
| | | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } |
| | | .ui-datepicker td.ui-datepicker-current-day .ui-state-active { background:#c33; border-color:#a22; color:#fff; } |
| | | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } |
| | | .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: default; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } |
| | | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } |
| | | |
| | | /* with multiple calendars */ |
| | | .ui-datepicker.ui-datepicker-multi { width:auto; } |
| | | .ui-datepicker-multi .ui-datepicker-group { float:left; } |
| | | .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } |
| | | .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } |
| | | .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } |
| | | .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } |
| | | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } |
| | | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } |
| | | .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } |
| | | .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } |
| | | |
| | | /* RTL support */ |
| | | .ui-datepicker-rtl { direction: rtl; } |
| | | .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } |
| | | .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } |
| | | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } |
| | | .ui-datepicker-rtl .ui-datepicker-group { float:right; } |
| | | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } |
| | | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } |
| | | |
| | | /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ |
| | | .ui-datepicker-cover { |
| | | display: none; /*sorry for IE5*/ |
| | | display/**/: block; /*sorry for IE5*/ |
| | | position: absolute; /*must have*/ |
| | | z-index: -1; /*must have*/ |
| | | filter: mask(); /*must have*/ |
| | | top: -4px; /*must have*/ |
| | | left: -4px; /*must have*/ |
| | | width: 200px; /*must have*/ |
| | | height: 200px; /*must have*/ |
| | | }/* |
| | | * jQuery UI Progressbar 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Progressbar#theming |
| | | */ |
| | | .ui-progressbar { height:2em; text-align: left; } |
| | | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } |
New file |
| | |
| | | --- jquery-ui-1.8.14.custom.css.orig 2011-07-20 13:59:40.000000000 +0200 |
| | | +++ jquery-ui-1.8.14.custom.css 2011-07-24 16:23:47.000000000 +0200 |
| | | @@ -61,7 +61,7 @@ |
| | | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Verdana, Arial, Helvetica, sans-serif; font-size: 1em; } |
| | | .ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #000000; } |
| | | .ui-widget-content a { color: #000000; } |
| | | -.ui-widget-header { border: 1px solid #999999; background: #f4f4f4 url(images/ui-bg_highlight-hard_90_f4f4f4_1x100.png) 50% 50% repeat-x; color: #333333; font-weight: bold; } |
| | | +.ui-widget-header { border: 1px solid #999999; border-width: 0 0 1px 0; background: #f4f4f4 url(images/listheader.png) 50% 50% repeat; color: #333333; font-weight: bold; margin: -0.2em -0.2em 0 -0.2em; } |
| | | .ui-widget-header a { color: #333333; } |
| | | |
| | | /* Interaction states |
| | | @@ -72,6 +72,8 @@ |
| | | .ui-state-hover a, .ui-state-hover a:hover { color: #000000; text-decoration: none; } |
| | | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #a4a4a4; background: #a3a3a3 url(images/ui-bg_highlight-hard_90_a3a3a3_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #000000; } |
| | | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #000000; text-decoration: none; } |
| | | +.ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #c33; color: #a00; } |
| | | +.ui-tabs-nav .ui-state-focus { border: 1px solid #a4a4a4; color: #000000; } |
| | | .ui-widget :active { outline: none; } |
| | | |
| | | /* Interaction Cues |
| | | @@ -82,7 +84,7 @@ |
| | | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cc3333; } |
| | | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cc3333; } |
| | | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } |
| | | -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } |
| | | +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .6; filter:Alpha(Opacity=60); font-weight: normal; } |
| | | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } |
| | | |
| | | /* Icons |
| | | @@ -349,6 +351,8 @@ |
| | | /* workarounds */ |
| | | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ |
| | | |
| | | +#ui-active-menuitem { background:#c33; border-color:#a22; color:#fff; } |
| | | + |
| | | /* |
| | | * jQuery UI Menu 1.8.14 |
| | | * |
| | | @@ -364,6 +368,9 @@ |
| | | margin: 0; |
| | | display:block; |
| | | float: left; |
| | | + box-shadow: 1px 1px 18px #999; |
| | | + -moz-box-shadow: 1px 1px 12px #999; |
| | | + -webkit-box-shadow: #999 1px 1px 12px; |
| | | } |
| | | .ui-menu .ui-menu { |
| | | margin-top: -3px; |
| | | @@ -397,15 +404,16 @@ |
| | | * |
| | | * http://docs.jquery.com/UI/Button#theming |
| | | */ |
| | | -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ |
| | | +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: default; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ |
| | | .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ |
| | | button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ |
| | | .ui-button-icons-only { width: 3.4em; } |
| | | button.ui-button-icons-only { width: 3.7em; } |
| | | +button.ui-button-text-only, a.ui-button-text-only { background-image: url(images/buttongradient.png) !important; } |
| | | |
| | | /*button text element */ |
| | | .ui-button .ui-button-text { display: block; line-height: 1.4; } |
| | | -.ui-button-text-only .ui-button-text { padding: .4em 1em; } |
| | | +.ui-button-text-only .ui-button-text { padding: .3em 1em; } |
| | | .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } |
| | | .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } |
| | | .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } |
| | | @@ -435,7 +443,7 @@ |
| | | * |
| | | * http://docs.jquery.com/UI/Dialog#theming |
| | | */ |
| | | -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } |
| | | +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; box-shadow: 1px 1px 18px #999; -moz-box-shadow: 1px 1px 12px #999; -webkit-box-shadow: #999 1px 1px 12px; } |
| | | .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } |
| | | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } |
| | | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } |
| | | @@ -444,7 +452,7 @@ |
| | | .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } |
| | | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } |
| | | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } |
| | | -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } |
| | | +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: default; } |
| | | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } |
| | | .ui-draggable .ui-dialog-titlebar { cursor: move; } |
| | | /* |
| | | @@ -481,13 +489,16 @@ |
| | | */ |
| | | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ |
| | | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } |
| | | -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } |
| | | -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } |
| | | +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 0 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; border-top-left-radius: 2px; -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; border-top-right-radius: 2px; } |
| | | +.ui-tabs .ui-tabs-nav li a { float: left; padding: .3em 1em; text-decoration: none; } |
| | | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } |
| | | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } |
| | | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ |
| | | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } |
| | | .ui-tabs .ui-tabs-hide { display: none !important; } |
| | | + |
| | | +.ui-dialog .ui-tabs .ui-tabs-nav li.ui-tabs-selected { background:#fff; } |
| | | + |
| | | /* |
| | | * jQuery UI Datepicker 1.8.14 |
| | | * |
| | | @@ -497,7 +508,7 @@ |
| | | * |
| | | * http://docs.jquery.com/UI/Datepicker#theming |
| | | */ |
| | | -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } |
| | | +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; box-shadow: 1px 1px 18px #999; -moz-box-shadow: 1px 1px 12px #999; -webkit-box-shadow: #999 1px 1px 12px; } |
| | | .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } |
| | | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } |
| | | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } |
| | | @@ -515,8 +526,9 @@ |
| | | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } |
| | | .ui-datepicker td { border: 0; padding: 1px; } |
| | | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } |
| | | +.ui-datepicker td.ui-datepicker-current-day .ui-state-active { background:#c33; border-color:#a22; color:#fff; } |
| | | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } |
| | | -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } |
| | | +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: default; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } |
| | | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } |
| | | |
| | | /* with multiple calendars */ |
New file |
| | |
| | | /* |
| | | * jQuery UI CSS Framework 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Theming/API |
| | | */ |
| | | |
| | | /* Layout helpers |
| | | ----------------------------------*/ |
| | | .ui-helper-hidden { display: none; } |
| | | .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } |
| | | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } |
| | | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } |
| | | .ui-helper-clearfix { display: inline-block; } |
| | | /* required comment for clearfix to work in Opera \*/ |
| | | * html .ui-helper-clearfix { height:1%; } |
| | | .ui-helper-clearfix { display:block; } |
| | | /* end clearfix */ |
| | | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } |
| | | |
| | | |
| | | /* Interaction Cues |
| | | ----------------------------------*/ |
| | | .ui-state-disabled { cursor: default !important; } |
| | | |
| | | |
| | | /* Icons |
| | | ----------------------------------*/ |
| | | |
| | | /* states and images */ |
| | | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } |
| | | |
| | | |
| | | /* Misc visuals |
| | | ----------------------------------*/ |
| | | |
| | | /* Overlays */ |
| | | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } |
| | | |
| | | |
| | | /* |
| | | * jQuery UI CSS Framework 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Theming/API |
| | | * |
| | | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px |
| | | */ |
| | | |
| | | |
| | | /* Component containers |
| | | ----------------------------------*/ |
| | | .ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; } |
| | | .ui-widget .ui-widget { font-size: 1em; } |
| | | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; } |
| | | .ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; } |
| | | .ui-widget-content a { color: #222222; } |
| | | .ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } |
| | | .ui-widget-header a { color: #ffffff; } |
| | | |
| | | /* Interaction states |
| | | ----------------------------------*/ |
| | | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; } |
| | | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; } |
| | | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; } |
| | | .ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; } |
| | | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; } |
| | | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; } |
| | | .ui-widget :active { outline: none; } |
| | | |
| | | /* Interaction Cues |
| | | ----------------------------------*/ |
| | | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; } |
| | | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } |
| | | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } |
| | | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } |
| | | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } |
| | | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } |
| | | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } |
| | | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } |
| | | |
| | | /* Icons |
| | | ----------------------------------*/ |
| | | |
| | | /* states and images */ |
| | | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); } |
| | | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); } |
| | | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); } |
| | | .ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); } |
| | | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); } |
| | | .ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); } |
| | | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); } |
| | | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); } |
| | | |
| | | /* positioning */ |
| | | .ui-icon-carat-1-n { background-position: 0 0; } |
| | | .ui-icon-carat-1-ne { background-position: -16px 0; } |
| | | .ui-icon-carat-1-e { background-position: -32px 0; } |
| | | .ui-icon-carat-1-se { background-position: -48px 0; } |
| | | .ui-icon-carat-1-s { background-position: -64px 0; } |
| | | .ui-icon-carat-1-sw { background-position: -80px 0; } |
| | | .ui-icon-carat-1-w { background-position: -96px 0; } |
| | | .ui-icon-carat-1-nw { background-position: -112px 0; } |
| | | .ui-icon-carat-2-n-s { background-position: -128px 0; } |
| | | .ui-icon-carat-2-e-w { background-position: -144px 0; } |
| | | .ui-icon-triangle-1-n { background-position: 0 -16px; } |
| | | .ui-icon-triangle-1-ne { background-position: -16px -16px; } |
| | | .ui-icon-triangle-1-e { background-position: -32px -16px; } |
| | | .ui-icon-triangle-1-se { background-position: -48px -16px; } |
| | | .ui-icon-triangle-1-s { background-position: -64px -16px; } |
| | | .ui-icon-triangle-1-sw { background-position: -80px -16px; } |
| | | .ui-icon-triangle-1-w { background-position: -96px -16px; } |
| | | .ui-icon-triangle-1-nw { background-position: -112px -16px; } |
| | | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } |
| | | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } |
| | | .ui-icon-arrow-1-n { background-position: 0 -32px; } |
| | | .ui-icon-arrow-1-ne { background-position: -16px -32px; } |
| | | .ui-icon-arrow-1-e { background-position: -32px -32px; } |
| | | .ui-icon-arrow-1-se { background-position: -48px -32px; } |
| | | .ui-icon-arrow-1-s { background-position: -64px -32px; } |
| | | .ui-icon-arrow-1-sw { background-position: -80px -32px; } |
| | | .ui-icon-arrow-1-w { background-position: -96px -32px; } |
| | | .ui-icon-arrow-1-nw { background-position: -112px -32px; } |
| | | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } |
| | | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } |
| | | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } |
| | | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } |
| | | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } |
| | | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } |
| | | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } |
| | | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } |
| | | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } |
| | | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } |
| | | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } |
| | | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } |
| | | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } |
| | | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } |
| | | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } |
| | | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } |
| | | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } |
| | | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } |
| | | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } |
| | | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } |
| | | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } |
| | | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } |
| | | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } |
| | | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } |
| | | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } |
| | | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } |
| | | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } |
| | | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } |
| | | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } |
| | | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } |
| | | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } |
| | | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } |
| | | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } |
| | | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } |
| | | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } |
| | | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } |
| | | .ui-icon-arrow-4 { background-position: 0 -80px; } |
| | | .ui-icon-arrow-4-diag { background-position: -16px -80px; } |
| | | .ui-icon-extlink { background-position: -32px -80px; } |
| | | .ui-icon-newwin { background-position: -48px -80px; } |
| | | .ui-icon-refresh { background-position: -64px -80px; } |
| | | .ui-icon-shuffle { background-position: -80px -80px; } |
| | | .ui-icon-transfer-e-w { background-position: -96px -80px; } |
| | | .ui-icon-transferthick-e-w { background-position: -112px -80px; } |
| | | .ui-icon-folder-collapsed { background-position: 0 -96px; } |
| | | .ui-icon-folder-open { background-position: -16px -96px; } |
| | | .ui-icon-document { background-position: -32px -96px; } |
| | | .ui-icon-document-b { background-position: -48px -96px; } |
| | | .ui-icon-note { background-position: -64px -96px; } |
| | | .ui-icon-mail-closed { background-position: -80px -96px; } |
| | | .ui-icon-mail-open { background-position: -96px -96px; } |
| | | .ui-icon-suitcase { background-position: -112px -96px; } |
| | | .ui-icon-comment { background-position: -128px -96px; } |
| | | .ui-icon-person { background-position: -144px -96px; } |
| | | .ui-icon-print { background-position: -160px -96px; } |
| | | .ui-icon-trash { background-position: -176px -96px; } |
| | | .ui-icon-locked { background-position: -192px -96px; } |
| | | .ui-icon-unlocked { background-position: -208px -96px; } |
| | | .ui-icon-bookmark { background-position: -224px -96px; } |
| | | .ui-icon-tag { background-position: -240px -96px; } |
| | | .ui-icon-home { background-position: 0 -112px; } |
| | | .ui-icon-flag { background-position: -16px -112px; } |
| | | .ui-icon-calendar { background-position: -32px -112px; } |
| | | .ui-icon-cart { background-position: -48px -112px; } |
| | | .ui-icon-pencil { background-position: -64px -112px; } |
| | | .ui-icon-clock { background-position: -80px -112px; } |
| | | .ui-icon-disk { background-position: -96px -112px; } |
| | | .ui-icon-calculator { background-position: -112px -112px; } |
| | | .ui-icon-zoomin { background-position: -128px -112px; } |
| | | .ui-icon-zoomout { background-position: -144px -112px; } |
| | | .ui-icon-search { background-position: -160px -112px; } |
| | | .ui-icon-wrench { background-position: -176px -112px; } |
| | | .ui-icon-gear { background-position: -192px -112px; } |
| | | .ui-icon-heart { background-position: -208px -112px; } |
| | | .ui-icon-star { background-position: -224px -112px; } |
| | | .ui-icon-link { background-position: -240px -112px; } |
| | | .ui-icon-cancel { background-position: 0 -128px; } |
| | | .ui-icon-plus { background-position: -16px -128px; } |
| | | .ui-icon-plusthick { background-position: -32px -128px; } |
| | | .ui-icon-minus { background-position: -48px -128px; } |
| | | .ui-icon-minusthick { background-position: -64px -128px; } |
| | | .ui-icon-close { background-position: -80px -128px; } |
| | | .ui-icon-closethick { background-position: -96px -128px; } |
| | | .ui-icon-key { background-position: -112px -128px; } |
| | | .ui-icon-lightbulb { background-position: -128px -128px; } |
| | | .ui-icon-scissors { background-position: -144px -128px; } |
| | | .ui-icon-clipboard { background-position: -160px -128px; } |
| | | .ui-icon-copy { background-position: -176px -128px; } |
| | | .ui-icon-contact { background-position: -192px -128px; } |
| | | .ui-icon-image { background-position: -208px -128px; } |
| | | .ui-icon-video { background-position: -224px -128px; } |
| | | .ui-icon-script { background-position: -240px -128px; } |
| | | .ui-icon-alert { background-position: 0 -144px; } |
| | | .ui-icon-info { background-position: -16px -144px; } |
| | | .ui-icon-notice { background-position: -32px -144px; } |
| | | .ui-icon-help { background-position: -48px -144px; } |
| | | .ui-icon-check { background-position: -64px -144px; } |
| | | .ui-icon-bullet { background-position: -80px -144px; } |
| | | .ui-icon-radio-off { background-position: -96px -144px; } |
| | | .ui-icon-radio-on { background-position: -112px -144px; } |
| | | .ui-icon-pin-w { background-position: -128px -144px; } |
| | | .ui-icon-pin-s { background-position: -144px -144px; } |
| | | .ui-icon-play { background-position: 0 -160px; } |
| | | .ui-icon-pause { background-position: -16px -160px; } |
| | | .ui-icon-seek-next { background-position: -32px -160px; } |
| | | .ui-icon-seek-prev { background-position: -48px -160px; } |
| | | .ui-icon-seek-end { background-position: -64px -160px; } |
| | | .ui-icon-seek-start { background-position: -80px -160px; } |
| | | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ |
| | | .ui-icon-seek-first { background-position: -80px -160px; } |
| | | .ui-icon-stop { background-position: -96px -160px; } |
| | | .ui-icon-eject { background-position: -112px -160px; } |
| | | .ui-icon-volume-off { background-position: -128px -160px; } |
| | | .ui-icon-volume-on { background-position: -144px -160px; } |
| | | .ui-icon-power { background-position: 0 -176px; } |
| | | .ui-icon-signal-diag { background-position: -16px -176px; } |
| | | .ui-icon-signal { background-position: -32px -176px; } |
| | | .ui-icon-battery-0 { background-position: -48px -176px; } |
| | | .ui-icon-battery-1 { background-position: -64px -176px; } |
| | | .ui-icon-battery-2 { background-position: -80px -176px; } |
| | | .ui-icon-battery-3 { background-position: -96px -176px; } |
| | | .ui-icon-circle-plus { background-position: 0 -192px; } |
| | | .ui-icon-circle-minus { background-position: -16px -192px; } |
| | | .ui-icon-circle-close { background-position: -32px -192px; } |
| | | .ui-icon-circle-triangle-e { background-position: -48px -192px; } |
| | | .ui-icon-circle-triangle-s { background-position: -64px -192px; } |
| | | .ui-icon-circle-triangle-w { background-position: -80px -192px; } |
| | | .ui-icon-circle-triangle-n { background-position: -96px -192px; } |
| | | .ui-icon-circle-arrow-e { background-position: -112px -192px; } |
| | | .ui-icon-circle-arrow-s { background-position: -128px -192px; } |
| | | .ui-icon-circle-arrow-w { background-position: -144px -192px; } |
| | | .ui-icon-circle-arrow-n { background-position: -160px -192px; } |
| | | .ui-icon-circle-zoomin { background-position: -176px -192px; } |
| | | .ui-icon-circle-zoomout { background-position: -192px -192px; } |
| | | .ui-icon-circle-check { background-position: -208px -192px; } |
| | | .ui-icon-circlesmall-plus { background-position: 0 -208px; } |
| | | .ui-icon-circlesmall-minus { background-position: -16px -208px; } |
| | | .ui-icon-circlesmall-close { background-position: -32px -208px; } |
| | | .ui-icon-squaresmall-plus { background-position: -48px -208px; } |
| | | .ui-icon-squaresmall-minus { background-position: -64px -208px; } |
| | | .ui-icon-squaresmall-close { background-position: -80px -208px; } |
| | | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } |
| | | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } |
| | | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } |
| | | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } |
| | | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } |
| | | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } |
| | | |
| | | |
| | | /* Misc visuals |
| | | ----------------------------------*/ |
| | | |
| | | /* Corner radius */ |
| | | .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px; } |
| | | .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px; } |
| | | .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; } |
| | | .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; } |
| | | |
| | | /* Overlays */ |
| | | .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } |
| | | .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* |
| | | * jQuery UI Resizable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Resizable#theming |
| | | */ |
| | | .ui-resizable { position: relative;} |
| | | .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } |
| | | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } |
| | | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } |
| | | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } |
| | | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } |
| | | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } |
| | | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } |
| | | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } |
| | | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } |
| | | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* |
| | | * jQuery UI Selectable 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Selectable#theming |
| | | */ |
| | | .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } |
| | | /* |
| | | * jQuery UI Accordion 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Accordion#theming |
| | | */ |
| | | /* IE/Win - Fix animation bug - #4615 */ |
| | | .ui-accordion { width: 100%; } |
| | | .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } |
| | | .ui-accordion .ui-accordion-li-fix { display: inline; } |
| | | .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } |
| | | .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } |
| | | .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } |
| | | .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } |
| | | .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } |
| | | .ui-accordion .ui-accordion-content-active { display: block; } |
| | | /* |
| | | * jQuery UI Autocomplete 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Autocomplete#theming |
| | | */ |
| | | .ui-autocomplete { position: absolute; cursor: default; } |
| | | |
| | | /* workarounds */ |
| | | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ |
| | | |
| | | /* |
| | | * jQuery UI Menu 1.8.14 |
| | | * |
| | | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Menu#theming |
| | | */ |
| | | .ui-menu { |
| | | list-style:none; |
| | | padding: 2px; |
| | | margin: 0; |
| | | display:block; |
| | | float: left; |
| | | } |
| | | .ui-menu .ui-menu { |
| | | margin-top: -3px; |
| | | } |
| | | .ui-menu .ui-menu-item { |
| | | margin:0; |
| | | padding: 0; |
| | | zoom: 1; |
| | | float: left; |
| | | clear: left; |
| | | width: 100%; |
| | | } |
| | | .ui-menu .ui-menu-item a { |
| | | text-decoration:none; |
| | | display:block; |
| | | padding:.2em .4em; |
| | | line-height:1.5; |
| | | zoom:1; |
| | | } |
| | | .ui-menu .ui-menu-item a.ui-state-hover, |
| | | .ui-menu .ui-menu-item a.ui-state-active { |
| | | font-weight: normal; |
| | | margin: -1px; |
| | | } |
| | | /* |
| | | * jQuery UI Button 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Button#theming |
| | | */ |
| | | .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ |
| | | .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ |
| | | button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ |
| | | .ui-button-icons-only { width: 3.4em; } |
| | | button.ui-button-icons-only { width: 3.7em; } |
| | | |
| | | /*button text element */ |
| | | .ui-button .ui-button-text { display: block; line-height: 1.4; } |
| | | .ui-button-text-only .ui-button-text { padding: .4em 1em; } |
| | | .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } |
| | | .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } |
| | | .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } |
| | | .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } |
| | | /* no icon support for input elements, provide padding by default */ |
| | | input.ui-button { padding: .4em 1em; } |
| | | |
| | | /*button icon element(s) */ |
| | | .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } |
| | | .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } |
| | | .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } |
| | | .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } |
| | | .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } |
| | | |
| | | /*button sets*/ |
| | | .ui-buttonset { margin-right: 7px; } |
| | | .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } |
| | | |
| | | /* workarounds */ |
| | | button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ |
| | | /* |
| | | * jQuery UI Dialog 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Dialog#theming |
| | | */ |
| | | .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } |
| | | .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } |
| | | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } |
| | | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } |
| | | .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } |
| | | .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } |
| | | .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } |
| | | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } |
| | | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } |
| | | .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } |
| | | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } |
| | | .ui-draggable .ui-dialog-titlebar { cursor: move; } |
| | | /* |
| | | * jQuery UI Slider 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Slider#theming |
| | | */ |
| | | .ui-slider { position: relative; text-align: left; } |
| | | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } |
| | | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } |
| | | |
| | | .ui-slider-horizontal { height: .8em; } |
| | | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } |
| | | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } |
| | | .ui-slider-horizontal .ui-slider-range-min { left: 0; } |
| | | .ui-slider-horizontal .ui-slider-range-max { right: 0; } |
| | | |
| | | .ui-slider-vertical { width: .8em; height: 100px; } |
| | | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } |
| | | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } |
| | | .ui-slider-vertical .ui-slider-range-min { bottom: 0; } |
| | | .ui-slider-vertical .ui-slider-range-max { top: 0; }/* |
| | | * jQuery UI Tabs 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Tabs#theming |
| | | */ |
| | | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ |
| | | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } |
| | | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } |
| | | .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } |
| | | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } |
| | | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } |
| | | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ |
| | | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } |
| | | .ui-tabs .ui-tabs-hide { display: none !important; } |
| | | /* |
| | | * jQuery UI Datepicker 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Datepicker#theming |
| | | */ |
| | | .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } |
| | | .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } |
| | | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } |
| | | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } |
| | | .ui-datepicker .ui-datepicker-prev { left:2px; } |
| | | .ui-datepicker .ui-datepicker-next { right:2px; } |
| | | .ui-datepicker .ui-datepicker-prev-hover { left:1px; } |
| | | .ui-datepicker .ui-datepicker-next-hover { right:1px; } |
| | | .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } |
| | | .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } |
| | | .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } |
| | | .ui-datepicker select.ui-datepicker-month-year {width: 100%;} |
| | | .ui-datepicker select.ui-datepicker-month, |
| | | .ui-datepicker select.ui-datepicker-year { width: 49%;} |
| | | .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } |
| | | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } |
| | | .ui-datepicker td { border: 0; padding: 1px; } |
| | | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } |
| | | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } |
| | | .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } |
| | | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } |
| | | |
| | | /* with multiple calendars */ |
| | | .ui-datepicker.ui-datepicker-multi { width:auto; } |
| | | .ui-datepicker-multi .ui-datepicker-group { float:left; } |
| | | .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } |
| | | .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } |
| | | .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } |
| | | .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } |
| | | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } |
| | | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } |
| | | .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } |
| | | .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } |
| | | |
| | | /* RTL support */ |
| | | .ui-datepicker-rtl { direction: rtl; } |
| | | .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } |
| | | .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } |
| | | .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } |
| | | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } |
| | | .ui-datepicker-rtl .ui-datepicker-group { float:right; } |
| | | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } |
| | | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } |
| | | |
| | | /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ |
| | | .ui-datepicker-cover { |
| | | display: none; /*sorry for IE5*/ |
| | | display/**/: block; /*sorry for IE5*/ |
| | | position: absolute; /*must have*/ |
| | | z-index: -1; /*must have*/ |
| | | filter: mask(); /*must have*/ |
| | | top: -4px; /*must have*/ |
| | | left: -4px; /*must have*/ |
| | | width: 200px; /*must have*/ |
| | | height: 200px; /*must have*/ |
| | | }/* |
| | | * jQuery UI Progressbar 1.8.14 |
| | | * |
| | | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
| | | * Dual licensed under the MIT or GPL Version 2 licenses. |
| | | * http://jquery.org/license |
| | | * |
| | | * http://docs.jquery.com/UI/Progressbar#theming |
| | | */ |
| | | .ui-progressbar { height:2em; text-align: left; } |
| | | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } |
New file |
| | |
| | | * version 4.3 [2011-07-28] |
| | | ----------------------------------------------------------- |
| | | - Fixed handling of error in Net_Sieve::listScripts() |
| | | - Fixed handling of REFERRAL responses (http://pear.php.net/bugs/bug.php?id=17107) |
| | | - Fixed bug where wrong folders hierarchy was displayed on folders listing |
| | | |
| | | * version 4.2 [2011-05-24] |
| | | ----------------------------------------------------------- |
| | | - Moved elsif replacement code to handle only imports from other formats |
| | | - Fixed mod_mailbox() usage for newer Roundcube versions |
| | | - Fixed regex extension (error: regex require missing) |
| | | |
| | | * version 4.1 [2011-03-07] |
| | | ----------------------------------------------------------- |
| | | - Fix fileinto target is always INBOX (#1487776) |
| | | - Fix escaping of backslash character in quoted strings (#1487780) |
| | | - Fix handling of non-safe characters (double-quote, backslash) |
| | | or UTF-8 characters (dovecot's implementation bug workaround) |
| | | in script names |
| | | - Fix saving of a script using flags extension on servers with imap4flags support (#1487825) |
| | | |
| | | * version 4.0 [2011-02-10] |
| | | ----------------------------------------------------------- |
| | | - Fix STARTTLS for timsieved < 2.3.10 |
| | | - Added :regex and :matches support (#1487746) |
| | | - Added setflag/addflag/removeflag support (#1487449) |
| | | - Added support for vacation :subject field (#1487120) |
| | | - rcube_sieve_script class moved to separate file |
| | | - Moved javascript code from skin templates into managesieve.js file |
| | | |
| | | * version 3.0 [2011-02-01] |
| | | ----------------------------------------------------------- |
| | | - Added support for SASL proxy authentication (#1486691) |
| | | - Fixed parsing of scripts with \r\n line separator |
| | | - Apply forgotten changes for form errors handling |
| | | - Fix multi-line strings parsing (#1487685) |
| | | - Added tests for script parser |
| | | - Rewritten script parser |
| | | - Fix double request when clicking on Filters tab using Firefox |
| | | |
| | | * version 2.10 [2010-10-10] |
| | | ----------------------------------------------------------- |
| | | - Fixed import from Avelsieve |
| | | - Use localized size units (#1486976) |
| | | - Added support for relational operators and i;ascii-numeric comparator |
| | | - Added popups with form errors |
| | | |
| | | * version 2.9 [2010-08-02] |
| | | ----------------------------------------------------------- |
| | | - Fixed vacation parameters parsing (#1486883) |
| | | |
| | | * version 2.8 [2010-07-08] |
| | | ----------------------------------------------------------- |
| | | - Added managesieve_auth_type option (#1486731) |
| | | |
| | | * version 2.7 [2010-07-06] |
| | | ----------------------------------------------------------- |
| | | - Update Net_Sieve to version 1.3.0 (fixes LOGIN athentication) |
| | | - Added support for copying and copy sending of messages (COPY extension) |
| | | |
| | | * version 2.6 [2010-06-03] |
| | | ----------------------------------------------------------- |
| | | - Support %n and %d variables in managesieve_host option |
| | | |
| | | * version 2.5 [2010-05-04] |
| | | ----------------------------------------------------------- |
| | | - Fix filters set label after activation |
| | | - Fix filters set activation, add possibility to deactivate sets (#1486699) |
| | | - Fix download button state when sets list is empty |
| | | - Fix errors when sets list is empty |
| | | |
| | | * version 2.4 [2010-04-01] |
| | | ----------------------------------------------------------- |
| | | - Fixed bug in DIGEST-MD5 authentication (http://pear.php.net/bugs/bug.php?id=17285) |
| | | - Fixed disabling rules with many tests |
| | | - Small css unification with core |
| | | - Scripts import/export |
| | | |
| | | * version 2.3 [2010-03-18] |
| | | ----------------------------------------------------------- |
| | | - Added import from Horde-INGO |
| | | - Support for more than one match using if+stop instead of if+elsif structures (#1486078) |
| | | - Support for selectively disabling rules within a single sieve script (#1485882) |
| | | - Added vertical splitter |
| | | |
| | | * version 2.2 [2010-02-06] |
| | | ----------------------------------------------------------- |
| | | - Fix handling of "<>" characters in filter names (#1486477) |
| | | |
| | | * version 2.1 [2010-01-12] |
| | | ----------------------------------------------------------- |
| | | - Fix "require" structure generation when many modules are used |
| | | - Fix problem with '<' and '>' characters in header tests |
| | | |
| | | * version 2.0 [2009-11-02] |
| | | ----------------------------------------------------------- |
| | | - Added 'managesieve_debug' option |
| | | - Added multi-script support |
| | | - Small css improvements + sprite image buttons |
| | | - PEAR::NetSieve 1.2.0b1 |
| | | |
| | | * version 1.7 [2009-09-20] |
| | | ----------------------------------------------------------- |
| | | - Support multiple managesieve hosts using %h variable |
| | | in managesieve_host option |
| | | - Fix first rule deleting (#1486140) |
| | | |
| | | * version 1.6 [2009-09-08] |
| | | ----------------------------------------------------------- |
| | | - Fix warning when importing squirrelmail rules |
| | | - Fix handling of "true" as "anyof (true)" test |
| | | |
| | | * version 1.5 [2009-09-04] |
| | | ----------------------------------------------------------- |
| | | - Added es_ES, ua_UA localizations |
| | | - Added 'managesieve_mbox_encoding' option |
| | | |
| | | * version 1.4 [2009-07-29] |
| | | ----------------------------------------------------------- |
| | | - Updated PEAR::Net_Sieve to 1.1.7 |
| | | |
| | | * version 1.3 [2009-07-24] |
| | | ----------------------------------------------------------- |
| | | - support more languages |
| | | - support config.inc.php file |
| | | |
| | | * version 1.2 [2009-06-28] |
| | | ----------------------------------------------------------- |
| | | - Support IMAP namespaces in fileinto (#1485943) |
| | | - Added it_IT localization |
| | | |
| | | * version 1.1 [2009-05-27] |
| | | ----------------------------------------------------------- |
| | | - Added new icons |
| | | - Added support for headers lists (coma-separated) in rules |
| | | - Added de_CH localization |
| | | |
| | | * version 1.0 [2009-05-21] |
| | | ----------------------------------------------------------- |
| | | - Rewritten using plugin API |
| | | - Added hu_HU localization (Tamas Tevesz) |
| | | |
| | | * version beta7 (svn-r2300) [2009-03-01] |
| | | ----------------------------------------------------------- |
| | | - Added SquirrelMail script auto-import (Jonathan Ernst) |
| | | - Added 'vacation' support (Jonathan Ernst & alec) |
| | | - Added 'stop' support (Jonathan Ernst) |
| | | - Added option for extensions disabling (Jonathan Ernst & alec) |
| | | - Added fi_FI, nl_NL, bg_BG localization |
| | | - Small style fixes |
| | | |
| | | * version 0.2-stable1 (svn-r2205) [2009-01-03] |
| | | ----------------------------------------------------------- |
| | | - Fix moving down filter row |
| | | - Fixes for compressed js files in stable release package |
| | | - Created patch for svn version r2205 |
| | | |
| | | * version 0.2-stable [2008-12-31] |
| | | ----------------------------------------------------------- |
| | | - Added ru_RU, fr_FR, zh_CN translation |
| | | - Fixes for Roundcube 0.2-stable |
| | | |
| | | * version rc0.2beta [2008-09-21] |
| | | ----------------------------------------------------------- |
| | | - Small css fixes for IE |
| | | - Fixes for Roundcube 0.2-beta |
| | | |
| | | * version beta6 [2008-08-08] |
| | | ----------------------------------------------------------- |
| | | - Added de_DE translation |
| | | - Fix for Roundcube r1634 |
| | | |
| | | * version beta5 [2008-06-10] |
| | | ----------------------------------------------------------- |
| | | - Fixed 'exists' operators |
| | | - Fixed 'not*' operators for custom headers |
| | | - Fixed filters deleting |
| | | |
| | | * version beta4 [2008-06-09] |
| | | ----------------------------------------------------------- |
| | | - Fix for Roundcube r1490 |
| | | |
| | | * version beta3 [2008-05-22] |
| | | ----------------------------------------------------------- |
| | | - Fixed textarea error class setting |
| | | - Added pagetitle setting |
| | | - Added option 'managesieve_replace_delimiter' |
| | | - Fixed errors on IE (still need some css fixes) |
| | | |
| | | * version beta2 [2008-05-20] |
| | | ----------------------------------------------------------- |
| | | - Use 'if' only for first filter and 'elsif' for the rest |
| | | |
| | | * version beta1 [2008-05-15] |
| | | ----------------------------------------------------------- |
| | | - Initial version for Roundcube r1388. |
New file |
| | |
| | | <?php |
| | | |
| | | // managesieve server port |
| | | $rcmail_config['managesieve_port'] = 2000; |
| | | |
| | | // managesieve server address, default is localhost. |
| | | // Replacement variables supported in host name: |
| | | // %h - user's IMAP hostname |
| | | // %n - http hostname ($_SERVER['SERVER_NAME']) |
| | | // %d - domain (http hostname without the first part) |
| | | // For example %n = mail.domain.tld, %d = domain.tld |
| | | $rcmail_config['managesieve_host'] = 'localhost'; |
| | | |
| | | // authentication method. Can be CRAM-MD5, DIGEST-MD5, PLAIN, LOGIN, EXTERNAL |
| | | // or none. Optional, defaults to best method supported by server. |
| | | $rcmail_config['managesieve_auth_type'] = null; |
| | | |
| | | // Optional managesieve authentication identifier to be used as authorization proxy. |
| | | // Authenticate as a different user but act on behalf of the logged in user. |
| | | // Works with PLAIN and DIGEST-MD5 auth. |
| | | $rcmail_config['managesieve_auth_cid'] = null; |
| | | |
| | | // Optional managesieve authentication password to be used for imap_auth_cid |
| | | $rcmail_config['managesieve_auth_pw'] = null; |
| | | |
| | | // use or not TLS for managesieve server connection |
| | | // it's because I've problems with TLS and dovecot's managesieve plugin |
| | | // and it's not needed on localhost |
| | | $rcmail_config['managesieve_usetls'] = false; |
| | | |
| | | // default contents of filters script (eg. default spam filter) |
| | | $rcmail_config['managesieve_default'] = '/etc/dovecot/sieve/global'; |
| | | |
| | | // Sieve RFC says that we should use UTF-8 endcoding for mailbox names, |
| | | // but some implementations does not covert UTF-8 to modified UTF-7. |
| | | // Defaults to UTF7-IMAP |
| | | $rcmail_config['managesieve_mbox_encoding'] = 'UTF-8'; |
| | | |
| | | // I need this because my dovecot (with listescape plugin) uses |
| | | // ':' delimiter, but creates folders with dot delimiter |
| | | $rcmail_config['managesieve_replace_delimiter'] = ''; |
| | | |
| | | // disabled sieve extensions (body, copy, date, editheader, encoded-character, |
| | | // envelope, environment, ereject, fileinto, ihave, imap4flags, index, |
| | | // mailbox, mboxmetadata, regex, reject, relational, servermetadata, |
| | | // spamtest, spamtestplus, subaddress, vacation, variables, virustest, etc. |
| | | // Note: not all extensions are implemented |
| | | $rcmail_config['managesieve_disabled_extensions'] = array(); |
| | | |
| | | // Enables debugging of conversation with sieve server. Logs it into <log_dir>/sieve |
| | | $rcmail_config['managesieve_debug'] = false; |
| | | |
| | | ?> |
New file |
| | |
| | | <?php |
| | | /** |
| | | * This file contains the Net_Sieve class. |
| | | * |
| | | * PHP version 4 |
| | | * |
| | | * +-----------------------------------------------------------------------+ |
| | | * | All rights reserved. | |
| | | * | | |
| | | * | Redistribution and use in source and binary forms, with or without | |
| | | * | modification, are permitted provided that the following conditions | |
| | | * | are met: | |
| | | * | | |
| | | * | o Redistributions of source code must retain the above copyright | |
| | | * | notice, this list of conditions and the following disclaimer. | |
| | | * | o Redistributions in binary form must reproduce the above copyright | |
| | | * | notice, this list of conditions and the following disclaimer in the | |
| | | * | documentation and/or other materials provided with the distribution.| |
| | | * | | |
| | | * | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| | | * | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| | | * | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| | | * | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| | | * | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| | | * | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| | | * | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| | | * | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| | | * | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| | | * | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| | | * | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| | | * +-----------------------------------------------------------------------+ |
| | | * |
| | | * @category Networking |
| | | * @package Net_Sieve |
| | | * @author Richard Heyes <richard@phpguru.org> |
| | | * @author Damian Fernandez Sosa <damlists@cnba.uba.ar> |
| | | * @author Anish Mistry <amistry@am-productions.biz> |
| | | * @author Jan Schneider <jan@horde.org> |
| | | * @copyright 2002-2003 Richard Heyes |
| | | * @copyright 2006-2008 Anish Mistry |
| | | * @license http://www.opensource.org/licenses/bsd-license.php BSD |
| | | * @version SVN: $Id: Sieve.php 300898 2010-07-01 09:49:02Z yunosh $ |
| | | * @link http://pear.php.net/package/Net_Sieve |
| | | */ |
| | | |
| | | require_once 'PEAR.php'; |
| | | require_once 'Net/Socket.php'; |
| | | |
| | | /** |
| | | * TODO |
| | | * |
| | | * o supportsAuthMech() |
| | | */ |
| | | |
| | | /** |
| | | * Disconnected state |
| | | * @const NET_SIEVE_STATE_DISCONNECTED |
| | | */ |
| | | define('NET_SIEVE_STATE_DISCONNECTED', 1, true); |
| | | |
| | | /** |
| | | * Authorisation state |
| | | * @const NET_SIEVE_STATE_AUTHORISATION |
| | | */ |
| | | define('NET_SIEVE_STATE_AUTHORISATION', 2, true); |
| | | |
| | | /** |
| | | * Transaction state |
| | | * @const NET_SIEVE_STATE_TRANSACTION |
| | | */ |
| | | define('NET_SIEVE_STATE_TRANSACTION', 3, true); |
| | | |
| | | |
| | | /** |
| | | * A class for talking to the timsieved server which comes with Cyrus IMAP. |
| | | * |
| | | * @category Networking |
| | | * @package Net_Sieve |
| | | * @author Richard Heyes <richard@phpguru.org> |
| | | * @author Damian Fernandez Sosa <damlists@cnba.uba.ar> |
| | | * @author Anish Mistry <amistry@am-productions.biz> |
| | | * @author Jan Schneider <jan@horde.org> |
| | | * @copyright 2002-2003 Richard Heyes |
| | | * @copyright 2006-2008 Anish Mistry |
| | | * @license http://www.opensource.org/licenses/bsd-license.php BSD |
| | | * @version Release: 1.3.0 |
| | | * @link http://pear.php.net/package/Net_Sieve |
| | | * @link http://www.ietf.org/rfc/rfc3028.txt RFC 3028 (Sieve: A Mail |
| | | * Filtering Language) |
| | | * @link http://tools.ietf.org/html/draft-ietf-sieve-managesieve A |
| | | * Protocol for Remotely Managing Sieve Scripts |
| | | */ |
| | | class Net_Sieve |
| | | { |
| | | /** |
| | | * The authentication methods this class supports. |
| | | * |
| | | * Can be overwritten if having problems with certain methods. |
| | | * |
| | | * @var array |
| | | */ |
| | | var $supportedAuthMethods = array('DIGEST-MD5', 'CRAM-MD5', 'EXTERNAL', |
| | | 'PLAIN' , 'LOGIN'); |
| | | |
| | | /** |
| | | * SASL authentication methods that require Auth_SASL. |
| | | * |
| | | * @var array |
| | | */ |
| | | var $supportedSASLAuthMethods = array('DIGEST-MD5', 'CRAM-MD5'); |
| | | |
| | | /** |
| | | * The socket handle. |
| | | * |
| | | * @var resource |
| | | */ |
| | | var $_sock; |
| | | |
| | | /** |
| | | * Parameters and connection information. |
| | | * |
| | | * @var array |
| | | */ |
| | | var $_data; |
| | | |
| | | /** |
| | | * Current state of the connection. |
| | | * |
| | | * One of the NET_SIEVE_STATE_* constants. |
| | | * |
| | | * @var integer |
| | | */ |
| | | var $_state; |
| | | |
| | | /** |
| | | * Constructor error. |
| | | * |
| | | * @var PEAR_Error |
| | | */ |
| | | var $_error; |
| | | |
| | | /** |
| | | * Whether to enable debugging. |
| | | * |
| | | * @var boolean |
| | | */ |
| | | var $_debug = false; |
| | | |
| | | /** |
| | | * Debug output handler. |
| | | * |
| | | * This has to be a valid callback. |
| | | * |
| | | * @var string|array |
| | | */ |
| | | var $_debug_handler = null; |
| | | |
| | | /** |
| | | * Whether to pick up an already established connection. |
| | | * |
| | | * @var boolean |
| | | */ |
| | | var $_bypassAuth = false; |
| | | |
| | | /** |
| | | * Whether to use TLS if available. |
| | | * |
| | | * @var boolean |
| | | */ |
| | | var $_useTLS = true; |
| | | |
| | | /** |
| | | * Additional options for stream_context_create(). |
| | | * |
| | | * @var array |
| | | */ |
| | | var $_options = null; |
| | | |
| | | /** |
| | | * Maximum number of referral loops |
| | | * |
| | | * @var array |
| | | */ |
| | | var $_maxReferralCount = 15; |
| | | |
| | | /** |
| | | * Constructor. |
| | | * |
| | | * Sets up the object, connects to the server and logs in. Stores any |
| | | * generated error in $this->_error, which can be retrieved using the |
| | | * getError() method. |
| | | * |
| | | * @param string $user Login username. |
| | | * @param string $pass Login password. |
| | | * @param string $host Hostname of server. |
| | | * @param string $port Port of server. |
| | | * @param string $logintype Type of login to perform (see |
| | | * $supportedAuthMethods). |
| | | * @param string $euser Effective user. If authenticating as an |
| | | * administrator, login as this user. |
| | | * @param boolean $debug Whether to enable debugging (@see setDebug()). |
| | | * @param string $bypassAuth Skip the authentication phase. Useful if the |
| | | * socket is already open. |
| | | * @param boolean $useTLS Use TLS if available. |
| | | * @param array $options Additional options for |
| | | * stream_context_create(). |
| | | * @param mixed $handler A callback handler for the debug output. |
| | | */ |
| | | function Net_Sieve($user = null, $pass = null, $host = 'localhost', |
| | | $port = 2000, $logintype = '', $euser = '', |
| | | $debug = false, $bypassAuth = false, $useTLS = true, |
| | | $options = null, $handler = null) |
| | | { |
| | | $this->_state = NET_SIEVE_STATE_DISCONNECTED; |
| | | $this->_data['user'] = $user; |
| | | $this->_data['pass'] = $pass; |
| | | $this->_data['host'] = $host; |
| | | $this->_data['port'] = $port; |
| | | $this->_data['logintype'] = $logintype; |
| | | $this->_data['euser'] = $euser; |
| | | $this->_sock = new Net_Socket(); |
| | | $this->_bypassAuth = $bypassAuth; |
| | | $this->_useTLS = $useTLS; |
| | | $this->_options = $options; |
| | | $this->setDebug($debug, $handler); |
| | | |
| | | /* Try to include the Auth_SASL package. If the package is not |
| | | * available, we disable the authentication methods that depend upon |
| | | * it. */ |
| | | if ((@include_once 'Auth/SASL.php') === false) { |
| | | $this->_debug('Auth_SASL not present'); |
| | | foreach ($this->supportedSASLAuthMethods as $SASLMethod) { |
| | | $pos = array_search($SASLMethod, $this->supportedAuthMethods); |
| | | $this->_debug('Disabling method ' . $SASLMethod); |
| | | unset($this->supportedAuthMethods[$pos]); |
| | | } |
| | | } |
| | | |
| | | if (strlen($user) && strlen($pass)) { |
| | | $this->_error = $this->_handleConnectAndLogin(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns any error that may have been generated in the constructor. |
| | | * |
| | | * @return boolean|PEAR_Error False if no error, PEAR_Error otherwise. |
| | | */ |
| | | function getError() |
| | | { |
| | | return PEAR::isError($this->_error) ? $this->_error : false; |
| | | } |
| | | |
| | | /** |
| | | * Sets the debug state and handler function. |
| | | * |
| | | * @param boolean $debug Whether to enable debugging. |
| | | * @param string $handler A custom debug handler. Must be a valid callback. |
| | | * |
| | | * @return void |
| | | */ |
| | | function setDebug($debug = true, $handler = null) |
| | | { |
| | | $this->_debug = $debug; |
| | | $this->_debug_handler = $handler; |
| | | } |
| | | |
| | | /** |
| | | * Connects to the server and logs in. |
| | | * |
| | | * @return boolean True on success, PEAR_Error on failure. |
| | | */ |
| | | function _handleConnectAndLogin() |
| | | { |
| | | if (PEAR::isError($res = $this->connect($this->_data['host'], $this->_data['port'], $this->_options, $this->_useTLS))) { |
| | | return $res; |
| | | } |
| | | if ($this->_bypassAuth === false) { |
| | | if (PEAR::isError($res = $this->login($this->_data['user'], $this->_data['pass'], $this->_data['logintype'], $this->_data['euser'], $this->_bypassAuth))) { |
| | | return $res; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Handles connecting to the server and checks the response validity. |
| | | * |
| | | * @param string $host Hostname of server. |
| | | * @param string $port Port of server. |
| | | * @param array $options List of options to pass to |
| | | * stream_context_create(). |
| | | * @param boolean $useTLS Use TLS if available. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function connect($host, $port, $options = null, $useTLS = true) |
| | | { |
| | | $this->_data['host'] = $host; |
| | | $this->_data['port'] = $port; |
| | | $this->_useTLS = $useTLS; |
| | | if (!empty($options) && is_array($options)) { |
| | | $this->_options = array_merge($this->_options, $options); |
| | | } |
| | | |
| | | if (NET_SIEVE_STATE_DISCONNECTED != $this->_state) { |
| | | return PEAR::raiseError('Not currently in DISCONNECTED state', 1); |
| | | } |
| | | |
| | | if (PEAR::isError($res = $this->_sock->connect($host, $port, false, 5, $options))) { |
| | | return $res; |
| | | } |
| | | |
| | | if ($this->_bypassAuth) { |
| | | $this->_state = NET_SIEVE_STATE_TRANSACTION; |
| | | } else { |
| | | $this->_state = NET_SIEVE_STATE_AUTHORISATION; |
| | | if (PEAR::isError($res = $this->_doCmd())) { |
| | | return $res; |
| | | } |
| | | } |
| | | |
| | | // Explicitly ask for the capabilities in case the connection is |
| | | // picked up from an existing connection. |
| | | if (PEAR::isError($res = $this->_cmdCapability())) { |
| | | return PEAR::raiseError( |
| | | 'Failed to connect, server said: ' . $res->getMessage(), 2 |
| | | ); |
| | | } |
| | | |
| | | // Check if we can enable TLS via STARTTLS. |
| | | if ($useTLS && !empty($this->_capability['starttls']) |
| | | && function_exists('stream_socket_enable_crypto') |
| | | ) { |
| | | if (PEAR::isError($res = $this->_startTLS())) { |
| | | return $res; |
| | | } |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Disconnect from the Sieve server. |
| | | * |
| | | * @param boolean $sendLogoutCMD Whether to send LOGOUT command before |
| | | * disconnecting. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function disconnect($sendLogoutCMD = true) |
| | | { |
| | | return $this->_cmdLogout($sendLogoutCMD); |
| | | } |
| | | |
| | | /** |
| | | * Logs into server. |
| | | * |
| | | * @param string $user Login username. |
| | | * @param string $pass Login password. |
| | | * @param string $logintype Type of login method to use. |
| | | * @param string $euser Effective UID (perform on behalf of $euser). |
| | | * @param boolean $bypassAuth Do not perform authentication. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function login($user, $pass, $logintype = null, $euser = '', $bypassAuth = false) |
| | | { |
| | | $this->_data['user'] = $user; |
| | | $this->_data['pass'] = $pass; |
| | | $this->_data['logintype'] = $logintype; |
| | | $this->_data['euser'] = $euser; |
| | | $this->_bypassAuth = $bypassAuth; |
| | | |
| | | if (NET_SIEVE_STATE_AUTHORISATION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in AUTHORISATION state', 1); |
| | | } |
| | | |
| | | if (!$bypassAuth ) { |
| | | if (PEAR::isError($res = $this->_cmdAuthenticate($user, $pass, $logintype, $euser))) { |
| | | return $res; |
| | | } |
| | | } |
| | | $this->_state = NET_SIEVE_STATE_TRANSACTION; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Returns an indexed array of scripts currently on the server. |
| | | * |
| | | * @return array Indexed array of scriptnames. |
| | | */ |
| | | function listScripts() |
| | | { |
| | | if (is_array($scripts = $this->_cmdListScripts())) { |
| | | $this->_active = $scripts[1]; |
| | | return $scripts[0]; |
| | | } else { |
| | | return $scripts; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Returns the active script. |
| | | * |
| | | * @return string The active scriptname. |
| | | */ |
| | | function getActive() |
| | | { |
| | | if (!empty($this->_active)) { |
| | | return $this->_active; |
| | | } |
| | | if (is_array($scripts = $this->_cmdListScripts())) { |
| | | $this->_active = $scripts[1]; |
| | | return $scripts[1]; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Sets the active script. |
| | | * |
| | | * @param string $scriptname The name of the script to be set as active. |
| | | * |
| | | * @return boolean True on success, PEAR_Error on failure. |
| | | */ |
| | | function setActive($scriptname) |
| | | { |
| | | return $this->_cmdSetActive($scriptname); |
| | | } |
| | | |
| | | /** |
| | | * Retrieves a script. |
| | | * |
| | | * @param string $scriptname The name of the script to be retrieved. |
| | | * |
| | | * @return string The script on success, PEAR_Error on failure. |
| | | */ |
| | | function getScript($scriptname) |
| | | { |
| | | return $this->_cmdGetScript($scriptname); |
| | | } |
| | | |
| | | /** |
| | | * Adds a script to the server. |
| | | * |
| | | * @param string $scriptname Name of the script. |
| | | * @param string $script The script content. |
| | | * @param boolean $makeactive Whether to make this the active script. |
| | | * |
| | | * @return boolean True on success, PEAR_Error on failure. |
| | | */ |
| | | function installScript($scriptname, $script, $makeactive = false) |
| | | { |
| | | if (PEAR::isError($res = $this->_cmdPutScript($scriptname, $script))) { |
| | | return $res; |
| | | } |
| | | if ($makeactive) { |
| | | return $this->_cmdSetActive($scriptname); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Removes a script from the server. |
| | | * |
| | | * @param string $scriptname Name of the script. |
| | | * |
| | | * @return boolean True on success, PEAR_Error on failure. |
| | | */ |
| | | function removeScript($scriptname) |
| | | { |
| | | return $this->_cmdDeleteScript($scriptname); |
| | | } |
| | | |
| | | /** |
| | | * Checks if the server has space to store the script by the server. |
| | | * |
| | | * @param string $scriptname The name of the script to mark as active. |
| | | * @param integer $size The size of the script. |
| | | * |
| | | * @return boolean|PEAR_Error True if there is space, PEAR_Error otherwise. |
| | | * |
| | | * @todo Rename to hasSpace() |
| | | */ |
| | | function haveSpace($scriptname, $size) |
| | | { |
| | | if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in TRANSACTION state', 1); |
| | | } |
| | | |
| | | $command = sprintf('HAVESPACE %s %d', $this->_escape($scriptname), $size); |
| | | if (PEAR::isError($res = $this->_doCmd($command))) { |
| | | return $res; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Returns the list of extensions the server supports. |
| | | * |
| | | * @return array List of extensions or PEAR_Error on failure. |
| | | */ |
| | | function getExtensions() |
| | | { |
| | | if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { |
| | | return PEAR::raiseError('Not currently connected', 7); |
| | | } |
| | | return $this->_capability['extensions']; |
| | | } |
| | | |
| | | /** |
| | | * Returns whether the server supports an extension. |
| | | * |
| | | * @param string $extension The extension to check. |
| | | * |
| | | * @return boolean Whether the extension is supported or PEAR_Error on |
| | | * failure. |
| | | */ |
| | | function hasExtension($extension) |
| | | { |
| | | if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { |
| | | return PEAR::raiseError('Not currently connected', 7); |
| | | } |
| | | |
| | | $extension = trim($this->_toUpper($extension)); |
| | | if (is_array($this->_capability['extensions'])) { |
| | | foreach ($this->_capability['extensions'] as $ext) { |
| | | if ($ext == $extension) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Returns the list of authentication methods the server supports. |
| | | * |
| | | * @return array List of authentication methods or PEAR_Error on failure. |
| | | */ |
| | | function getAuthMechs() |
| | | { |
| | | if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { |
| | | return PEAR::raiseError('Not currently connected', 7); |
| | | } |
| | | return $this->_capability['sasl']; |
| | | } |
| | | |
| | | /** |
| | | * Returns whether the server supports an authentication method. |
| | | * |
| | | * @param string $method The method to check. |
| | | * |
| | | * @return boolean Whether the method is supported or PEAR_Error on |
| | | * failure. |
| | | */ |
| | | function hasAuthMech($method) |
| | | { |
| | | if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { |
| | | return PEAR::raiseError('Not currently connected', 7); |
| | | } |
| | | |
| | | $method = trim($this->_toUpper($method)); |
| | | if (is_array($this->_capability['sasl'])) { |
| | | foreach ($this->_capability['sasl'] as $sasl) { |
| | | if ($sasl == $method) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * Handles the authentication using any known method. |
| | | * |
| | | * @param string $uid The userid to authenticate as. |
| | | * @param string $pwd The password to authenticate with. |
| | | * @param string $userMethod The method to use. If empty, the class chooses |
| | | * the best (strongest) available method. |
| | | * @param string $euser The effective uid to authenticate as. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _cmdAuthenticate($uid, $pwd, $userMethod = null, $euser = '') |
| | | { |
| | | if (PEAR::isError($method = $this->_getBestAuthMethod($userMethod))) { |
| | | return $method; |
| | | } |
| | | switch ($method) { |
| | | case 'DIGEST-MD5': |
| | | return $this->_authDigestMD5($uid, $pwd, $euser); |
| | | case 'CRAM-MD5': |
| | | $result = $this->_authCRAMMD5($uid, $pwd, $euser); |
| | | break; |
| | | case 'LOGIN': |
| | | $result = $this->_authLOGIN($uid, $pwd, $euser); |
| | | break; |
| | | case 'PLAIN': |
| | | $result = $this->_authPLAIN($uid, $pwd, $euser); |
| | | break; |
| | | case 'EXTERNAL': |
| | | $result = $this->_authEXTERNAL($uid, $pwd, $euser); |
| | | break; |
| | | default : |
| | | $result = PEAR::raiseError( |
| | | $method . ' is not a supported authentication method' |
| | | ); |
| | | break; |
| | | } |
| | | |
| | | if (PEAR::isError($res = $this->_doCmd())) { |
| | | return $res; |
| | | } |
| | | |
| | | return $result; |
| | | } |
| | | |
| | | /** |
| | | * Authenticates the user using the PLAIN method. |
| | | * |
| | | * @param string $user The userid to authenticate as. |
| | | * @param string $pass The password to authenticate with. |
| | | * @param string $euser The effective uid to authenticate as. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _authPLAIN($user, $pass, $euser) |
| | | { |
| | | return $this->_sendCmd( |
| | | sprintf( |
| | | 'AUTHENTICATE "PLAIN" "%s"', |
| | | base64_encode($euser . chr(0) . $user . chr(0) . $pass) |
| | | ) |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * Authenticates the user using the LOGIN method. |
| | | * |
| | | * @param string $user The userid to authenticate as. |
| | | * @param string $pass The password to authenticate with. |
| | | * @param string $euser The effective uid to authenticate as. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _authLOGIN($user, $pass, $euser) |
| | | { |
| | | if (PEAR::isError($result = $this->_sendCmd('AUTHENTICATE "LOGIN"'))) { |
| | | return $result; |
| | | } |
| | | if (PEAR::isError($result = $this->_doCmd('"' . base64_encode($user) . '"', true))) { |
| | | return $result; |
| | | } |
| | | return $this->_doCmd('"' . base64_encode($pass) . '"', true); |
| | | } |
| | | |
| | | /** |
| | | * Authenticates the user using the CRAM-MD5 method. |
| | | * |
| | | * @param string $user The userid to authenticate as. |
| | | * @param string $pass The password to authenticate with. |
| | | * @param string $euser The effective uid to authenticate as. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _authCRAMMD5($user, $pass, $euser) |
| | | { |
| | | if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "CRAM-MD5"', true))) { |
| | | return $challenge; |
| | | } |
| | | |
| | | $challenge = base64_decode(trim($challenge)); |
| | | $cram = Auth_SASL::factory('crammd5'); |
| | | if (PEAR::isError($response = $cram->getResponse($user, $pass, $challenge))) { |
| | | return $response; |
| | | } |
| | | |
| | | return $this->_sendStringResponse(base64_encode($response)); |
| | | } |
| | | |
| | | /** |
| | | * Authenticates the user using the DIGEST-MD5 method. |
| | | * |
| | | * @param string $user The userid to authenticate as. |
| | | * @param string $pass The password to authenticate with. |
| | | * @param string $euser The effective uid to authenticate as. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _authDigestMD5($user, $pass, $euser) |
| | | { |
| | | if (PEAR::isError($challenge = $this->_doCmd('AUTHENTICATE "DIGEST-MD5"', true))) { |
| | | return $challenge; |
| | | } |
| | | |
| | | $challenge = base64_decode(trim($challenge)); |
| | | $digest = Auth_SASL::factory('digestmd5'); |
| | | // @todo Really 'localhost'? |
| | | if (PEAR::isError($response = $digest->getResponse($user, $pass, $challenge, 'localhost', 'sieve', $euser))) { |
| | | return $response; |
| | | } |
| | | |
| | | if (PEAR::isError($result = $this->_sendStringResponse(base64_encode($response)))) { |
| | | return $result; |
| | | } |
| | | if (PEAR::isError($result = $this->_doCmd('', true))) { |
| | | return $result; |
| | | } |
| | | if ($this->_toUpper(substr($result, 0, 2)) == 'OK') { |
| | | return; |
| | | } |
| | | |
| | | /* We don't use the protocol's third step because SIEVE doesn't allow |
| | | * subsequent authentication, so we just silently ignore it. */ |
| | | if (PEAR::isError($result = $this->_sendStringResponse(''))) { |
| | | return $result; |
| | | } |
| | | |
| | | return $this->_doCmd(); |
| | | } |
| | | |
| | | /** |
| | | * Authenticates the user using the EXTERNAL method. |
| | | * |
| | | * @param string $user The userid to authenticate as. |
| | | * @param string $pass The password to authenticate with. |
| | | * @param string $euser The effective uid to authenticate as. |
| | | * |
| | | * @return void |
| | | * |
| | | * @since 1.1.7 |
| | | */ |
| | | function _authEXTERNAL($user, $pass, $euser) |
| | | { |
| | | $cmd = sprintf( |
| | | 'AUTHENTICATE "EXTERNAL" "%s"', |
| | | base64_encode(strlen($euser) ? $euser : $user) |
| | | ); |
| | | return $this->_sendCmd($cmd); |
| | | } |
| | | |
| | | /** |
| | | * Removes a script from the server. |
| | | * |
| | | * @param string $scriptname Name of the script to delete. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function _cmdDeleteScript($scriptname) |
| | | { |
| | | if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in AUTHORISATION state', 1); |
| | | } |
| | | |
| | | $command = sprintf('DELETESCRIPT %s', $this->_escape($scriptname)); |
| | | if (PEAR::isError($res = $this->_doCmd($command))) { |
| | | return $res; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the contents of the named script. |
| | | * |
| | | * @param string $scriptname Name of the script to retrieve. |
| | | * |
| | | * @return string The script if successful, PEAR_Error otherwise. |
| | | */ |
| | | function _cmdGetScript($scriptname) |
| | | { |
| | | if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in AUTHORISATION state', 1); |
| | | } |
| | | |
| | | $command = sprintf('GETSCRIPT %s', $this->_escape($scriptname)); |
| | | if (PEAR::isError($res = $this->_doCmd($command))) { |
| | | return $res; |
| | | } |
| | | |
| | | return preg_replace('/^{[0-9]+}\r\n/', '', $res); |
| | | } |
| | | |
| | | /** |
| | | * Sets the active script, i.e. the one that gets run on new mail by the |
| | | * server. |
| | | * |
| | | * @param string $scriptname The name of the script to mark as active. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function _cmdSetActive($scriptname) |
| | | { |
| | | if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in AUTHORISATION state', 1); |
| | | } |
| | | |
| | | $command = sprintf('SETACTIVE %s', $this->_escape($scriptname)); |
| | | if (PEAR::isError($res = $this->_doCmd($command))) { |
| | | return $res; |
| | | } |
| | | |
| | | $this->_activeScript = $scriptname; |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Returns the list of scripts on the server. |
| | | * |
| | | * @return array An array with the list of scripts in the first element |
| | | * and the active script in the second element on success, |
| | | * PEAR_Error otherwise. |
| | | */ |
| | | function _cmdListScripts() |
| | | { |
| | | if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in AUTHORISATION state', 1); |
| | | } |
| | | |
| | | if (PEAR::isError($res = $this->_doCmd('LISTSCRIPTS'))) { |
| | | return $res; |
| | | } |
| | | |
| | | $scripts = array(); |
| | | $activescript = null; |
| | | $res = explode("\r\n", $res); |
| | | foreach ($res as $value) { |
| | | if (preg_match('/^"(.*)"( ACTIVE)?$/i', $value, $matches)) { |
| | | $script_name = stripslashes($matches[1]); |
| | | $scripts[] = $script_name; |
| | | if (!empty($matches[2])) { |
| | | $activescript = $script_name; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return array($scripts, $activescript); |
| | | } |
| | | |
| | | /** |
| | | * Adds a script to the server. |
| | | * |
| | | * @param string $scriptname Name of the new script. |
| | | * @param string $scriptdata The new script. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function _cmdPutScript($scriptname, $scriptdata) |
| | | { |
| | | if (NET_SIEVE_STATE_TRANSACTION != $this->_state) { |
| | | return PEAR::raiseError('Not currently in AUTHORISATION state', 1); |
| | | } |
| | | |
| | | $stringLength = $this->_getLineLength($scriptdata); |
| | | $command = sprintf("PUTSCRIPT %s {%d+}\r\n%s", |
| | | $this->_escape($scriptname), $stringLength, $scriptdata); |
| | | |
| | | if (PEAR::isError($res = $this->_doCmd($command))) { |
| | | return $res; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Logs out of the server and terminates the connection. |
| | | * |
| | | * @param boolean $sendLogoutCMD Whether to send LOGOUT command before |
| | | * disconnecting. |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function _cmdLogout($sendLogoutCMD = true) |
| | | { |
| | | if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { |
| | | return PEAR::raiseError('Not currently connected', 1); |
| | | } |
| | | |
| | | if ($sendLogoutCMD) { |
| | | if (PEAR::isError($res = $this->_doCmd('LOGOUT'))) { |
| | | return $res; |
| | | } |
| | | } |
| | | |
| | | $this->_sock->disconnect(); |
| | | $this->_state = NET_SIEVE_STATE_DISCONNECTED; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Sends the CAPABILITY command |
| | | * |
| | | * @return boolean True on success, PEAR_Error otherwise. |
| | | */ |
| | | function _cmdCapability() |
| | | { |
| | | if (NET_SIEVE_STATE_DISCONNECTED == $this->_state) { |
| | | return PEAR::raiseError('Not currently connected', 1); |
| | | } |
| | | if (PEAR::isError($res = $this->_doCmd('CAPABILITY'))) { |
| | | return $res; |
| | | } |
| | | $this->_parseCapability($res); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Parses the response from the CAPABILITY command and stores the result |
| | | * in $_capability. |
| | | * |
| | | * @param string $data The response from the capability command. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _parseCapability($data) |
| | | { |
| | | // Clear the cached capabilities. |
| | | $this->_capability = array('sasl' => array(), |
| | | 'extensions' => array()); |
| | | |
| | | $data = preg_split('/\r?\n/', $this->_toUpper($data), -1, PREG_SPLIT_NO_EMPTY); |
| | | |
| | | for ($i = 0; $i < count($data); $i++) { |
| | | if (!preg_match('/^"([A-Z]+)"( "(.*)")?$/', $data[$i], $matches)) { |
| | | continue; |
| | | } |
| | | switch ($matches[1]) { |
| | | case 'IMPLEMENTATION': |
| | | $this->_capability['implementation'] = $matches[3]; |
| | | break; |
| | | |
| | | case 'SASL': |
| | | $this->_capability['sasl'] = preg_split('/\s+/', $matches[3]); |
| | | break; |
| | | |
| | | case 'SIEVE': |
| | | $this->_capability['extensions'] = preg_split('/\s+/', $matches[3]); |
| | | break; |
| | | |
| | | case 'STARTTLS': |
| | | $this->_capability['starttls'] = true; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Sends a command to the server |
| | | * |
| | | * @param string $cmd The command to send. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _sendCmd($cmd) |
| | | { |
| | | $status = $this->_sock->getStatus(); |
| | | if (PEAR::isError($status) || $status['eof']) { |
| | | return PEAR::raiseError('Failed to write to socket: connection lost'); |
| | | } |
| | | if (PEAR::isError($error = $this->_sock->write($cmd . "\r\n"))) { |
| | | return PEAR::raiseError( |
| | | 'Failed to write to socket: ' . $error->getMessage() |
| | | ); |
| | | } |
| | | $this->_debug("C: $cmd"); |
| | | } |
| | | |
| | | /** |
| | | * Sends a string response to the server. |
| | | * |
| | | * @param string $str The string to send. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _sendStringResponse($str) |
| | | { |
| | | return $this->_sendCmd('{' . $this->_getLineLength($str) . "+}\r\n" . $str); |
| | | } |
| | | |
| | | /** |
| | | * Receives a single line from the server. |
| | | * |
| | | * @return string The server response line. |
| | | */ |
| | | function _recvLn() |
| | | { |
| | | if (PEAR::isError($lastline = $this->_sock->gets(8192))) { |
| | | return PEAR::raiseError( |
| | | 'Failed to read from socket: ' . $lastline->getMessage() |
| | | ); |
| | | } |
| | | |
| | | $lastline = rtrim($lastline); |
| | | $this->_debug("S: $lastline"); |
| | | |
| | | if ($lastline === '') { |
| | | return PEAR::raiseError('Failed to read from socket'); |
| | | } |
| | | |
| | | return $lastline; |
| | | } |
| | | |
| | | /** |
| | | * Receives x bytes from the server. |
| | | * |
| | | * @param int $length Number of bytes to read |
| | | * |
| | | * @return string The server response. |
| | | */ |
| | | function _recvBytes($length) |
| | | { |
| | | $response = ''; |
| | | $response_length = 0; |
| | | |
| | | while ($response_length < $length) { |
| | | $response .= $this->_sock->read($length - $response_length); |
| | | $response_length = $this->_getLineLength($response); |
| | | } |
| | | |
| | | $this->_debug("S: " . rtrim($response)); |
| | | |
| | | return $response; |
| | | } |
| | | |
| | | /** |
| | | * Send a command and retrieves a response from the server. |
| | | * |
| | | * @param string $cmd The command to send. |
| | | * @param boolean $auth Whether this is an authentication command. |
| | | * |
| | | * @return string|PEAR_Error Reponse string if an OK response, PEAR_Error |
| | | * if a NO response. |
| | | */ |
| | | function _doCmd($cmd = '', $auth = false) |
| | | { |
| | | $referralCount = 0; |
| | | while ($referralCount < $this->_maxReferralCount) { |
| | | if (strlen($cmd)) { |
| | | if (PEAR::isError($error = $this->_sendCmd($cmd))) { |
| | | return $error; |
| | | } |
| | | } |
| | | |
| | | $response = ''; |
| | | while (true) { |
| | | if (PEAR::isError($line = $this->_recvLn())) { |
| | | return $line; |
| | | } |
| | | $uc_line = $this->_toUpper($line); |
| | | |
| | | if ('OK' == substr($uc_line, 0, 2)) { |
| | | $response .= $line; |
| | | return rtrim($response); |
| | | } |
| | | |
| | | if ('NO' == substr($uc_line, 0, 2)) { |
| | | // Check for string literal error message. |
| | | if (preg_match('/{([0-9]+)}$/i', $line, $matches)) { |
| | | $line = substr($line, 0, -(strlen($matches[1])+2)) |
| | | . str_replace( |
| | | "\r\n", ' ', $this->_recvBytes($matches[1] + 2) |
| | | ); |
| | | } |
| | | return PEAR::raiseError(trim($response . substr($line, 2)), 3); |
| | | } |
| | | |
| | | if ('BYE' == substr($uc_line, 0, 3)) { |
| | | if (PEAR::isError($error = $this->disconnect(false))) { |
| | | return PEAR::raiseError( |
| | | 'Cannot handle BYE, the error was: ' |
| | | . $error->getMessage(), |
| | | 4 |
| | | ); |
| | | } |
| | | // Check for referral, then follow it. Otherwise, carp an |
| | | // error. |
| | | if (preg_match('/^bye \(referral "(sieve:\/\/)?([^"]+)/i', $line, $matches)) { |
| | | // Replace the old host with the referral host |
| | | // preserving any protocol prefix. |
| | | $this->_data['host'] = preg_replace( |
| | | '/\w+(?!(\w|\:\/\/)).*/', $matches[2], |
| | | $this->_data['host'] |
| | | ); |
| | | if (PEAR::isError($error = $this->_handleConnectAndLogin())) { |
| | | return PEAR::raiseError( |
| | | 'Cannot follow referral to ' |
| | | . $this->_data['host'] . ', the error was: ' |
| | | . $error->getMessage(), |
| | | 5 |
| | | ); |
| | | } |
| | | break; |
| | | } |
| | | return PEAR::raiseError(trim($response . $line), 6); |
| | | } |
| | | |
| | | if (preg_match('/^{([0-9]+)}/i', $line, $matches)) { |
| | | // Matches literal string responses. |
| | | $line = $this->_recvBytes($matches[1] + 2); |
| | | |
| | | if (!$auth) { |
| | | // Receive the pending OK only if we aren't |
| | | // authenticating since string responses during |
| | | // authentication don't need an OK. |
| | | $this->_recvLn(); |
| | | } |
| | | return $line; |
| | | } |
| | | |
| | | if ($auth) { |
| | | // String responses during authentication don't need an |
| | | // OK. |
| | | $response .= $line; |
| | | return rtrim($response); |
| | | } |
| | | |
| | | $response .= $line . "\r\n"; |
| | | $referralCount++; |
| | | } |
| | | } |
| | | |
| | | return PEAR::raiseError('Max referral count (' . $referralCount . ') reached. Cyrus murder loop error?', 7); |
| | | } |
| | | |
| | | /** |
| | | * Returns the name of the best authentication method that the server |
| | | * has advertised. |
| | | * |
| | | * @param string $userMethod Only consider this method as available. |
| | | * |
| | | * @return string The name of the best supported authentication method or |
| | | * a PEAR_Error object on failure. |
| | | */ |
| | | function _getBestAuthMethod($userMethod = null) |
| | | { |
| | | if (!isset($this->_capability['sasl'])) { |
| | | return PEAR::raiseError('This server doesn\'t support any authentication methods. SASL problem?'); |
| | | } |
| | | if (!$this->_capability['sasl']) { |
| | | return PEAR::raiseError('This server doesn\'t support any authentication methods.'); |
| | | } |
| | | |
| | | if ($userMethod) { |
| | | if (in_array($userMethod, $this->_capability['sasl'])) { |
| | | return $userMethod; |
| | | } |
| | | return PEAR::raiseError( |
| | | sprintf('No supported authentication method found. The server supports these methods: %s, but we want to use: %s', |
| | | implode(', ', $this->_capability['sasl']), |
| | | $userMethod)); |
| | | } |
| | | |
| | | foreach ($this->supportedAuthMethods as $method) { |
| | | if (in_array($method, $this->_capability['sasl'])) { |
| | | return $method; |
| | | } |
| | | } |
| | | |
| | | return PEAR::raiseError( |
| | | sprintf('No supported authentication method found. The server supports these methods: %s, but we only support: %s', |
| | | implode(', ', $this->_capability['sasl']), |
| | | implode(', ', $this->supportedAuthMethods))); |
| | | } |
| | | |
| | | /** |
| | | * Starts a TLS connection. |
| | | * |
| | | * @return boolean True on success, PEAR_Error on failure. |
| | | */ |
| | | function _startTLS() |
| | | { |
| | | if (PEAR::isError($res = $this->_doCmd('STARTTLS'))) { |
| | | return $res; |
| | | } |
| | | |
| | | if (!stream_socket_enable_crypto($this->_sock->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { |
| | | return PEAR::raiseError('Failed to establish TLS connection', 2); |
| | | } |
| | | |
| | | $this->_debug('STARTTLS negotiation successful'); |
| | | |
| | | // The server should be sending a CAPABILITY response after |
| | | // negotiating TLS. Read it, and ignore if it doesn't. |
| | | // Doesn't work with older timsieved versions |
| | | $regexp = '/^CYRUS TIMSIEVED V([0-9.]+)/'; |
| | | if (!preg_match($regexp, $this->_capability['implementation'], $matches) |
| | | || version_compare($matches[1], '2.3.10', '>=') |
| | | ) { |
| | | $this->_doCmd(); |
| | | } |
| | | |
| | | // RFC says we need to query the server capabilities again now that we |
| | | // are under encryption. |
| | | if (PEAR::isError($res = $this->_cmdCapability())) { |
| | | return PEAR::raiseError( |
| | | 'Failed to connect, server said: ' . $res->getMessage(), 2 |
| | | ); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Returns the length of a string. |
| | | * |
| | | * @param string $string A string. |
| | | * |
| | | * @return integer The length of the string. |
| | | */ |
| | | function _getLineLength($string) |
| | | { |
| | | if (extension_loaded('mbstring')) { |
| | | return mb_strlen($string, 'latin1'); |
| | | } else { |
| | | return strlen($string); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Locale independant strtoupper() implementation. |
| | | * |
| | | * @param string $string The string to convert to lowercase. |
| | | * |
| | | * @return string The lowercased string, based on ASCII encoding. |
| | | */ |
| | | function _toUpper($string) |
| | | { |
| | | $language = setlocale(LC_CTYPE, 0); |
| | | setlocale(LC_CTYPE, 'C'); |
| | | $string = strtoupper($string); |
| | | setlocale(LC_CTYPE, $language); |
| | | return $string; |
| | | } |
| | | |
| | | /** |
| | | * Convert string into RFC's quoted-string or literal-c2s form |
| | | * |
| | | * @param string $string The string to convert. |
| | | * |
| | | * @return string Result string |
| | | */ |
| | | function _escape($string) |
| | | { |
| | | // Some implementations doesn't allow UTF-8 characters in quoted-string |
| | | // It's safe to use literal-c2s |
| | | if (preg_match('/[^\x01-\x09\x0B-\x0C\x0E-\x7F]/', $string)) { |
| | | return sprintf("{%d+}\r\n%s", $this->_getLineLength($string), $string); |
| | | } |
| | | |
| | | return '"' . addcslashes($string, '\\"') . '"'; |
| | | } |
| | | |
| | | /** |
| | | * Write debug text to the current debug output handler. |
| | | * |
| | | * @param string $message Debug message text. |
| | | * |
| | | * @return void |
| | | */ |
| | | function _debug($message) |
| | | { |
| | | if ($this->_debug) { |
| | | if ($this->_debug_handler) { |
| | | call_user_func_array($this->_debug_handler, array(&$this, $message)); |
| | | } else { |
| | | echo "$message\n"; |
| | | } |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | <?php |
| | | |
| | | /** |
| | | Classes for managesieve operations (using PEAR::Net_Sieve) |
| | | |
| | | Author: Aleksander Machniak <alec@alec.pl> |
| | | |
| | | $Id$ |
| | | |
| | | */ |
| | | |
| | | // Managesieve Protocol: RFC5804 |
| | | |
| | | define('SIEVE_ERROR_CONNECTION', 1); |
| | | define('SIEVE_ERROR_LOGIN', 2); |
| | | define('SIEVE_ERROR_NOT_EXISTS', 3); // script not exists |
| | | define('SIEVE_ERROR_INSTALL', 4); // script installation |
| | | define('SIEVE_ERROR_ACTIVATE', 5); // script activation |
| | | define('SIEVE_ERROR_DELETE', 6); // script deletion |
| | | define('SIEVE_ERROR_INTERNAL', 7); // internal error |
| | | define('SIEVE_ERROR_DEACTIVATE', 8); // script activation |
| | | define('SIEVE_ERROR_OTHER', 255); // other/unknown error |
| | | |
| | | |
| | | class rcube_sieve |
| | | { |
| | | private $sieve; // Net_Sieve object |
| | | private $error = false; // error flag |
| | | private $list = array(); // scripts list |
| | | |
| | | public $script; // rcube_sieve_script object |
| | | public $current; // name of currently loaded script |
| | | private $disabled; // array of disabled extensions |
| | | private $exts; // array of supported extensions |
| | | |
| | | |
| | | /** |
| | | * Object constructor |
| | | * |
| | | * @param string Username (for managesieve login) |
| | | * @param string Password (for managesieve login) |
| | | * @param string Managesieve server hostname/address |
| | | * @param string Managesieve server port number |
| | | * @param string Managesieve authentication method |
| | | * @param boolean Enable/disable TLS use |
| | | * @param array Disabled extensions |
| | | * @param boolean Enable/disable debugging |
| | | * @param string Proxy authentication identifier |
| | | * @param string Proxy authentication password |
| | | */ |
| | | public function __construct($username, $password='', $host='localhost', $port=2000, |
| | | $auth_type=null, $usetls=true, $disabled=array(), $debug=false, |
| | | $auth_cid=null, $auth_pw=null) |
| | | { |
| | | $this->sieve = new Net_Sieve(); |
| | | |
| | | if ($debug) { |
| | | $this->sieve->setDebug(true, array($this, 'debug_handler')); |
| | | } |
| | | |
| | | if (PEAR::isError($this->sieve->connect($host, $port, null, $usetls))) { |
| | | return $this->_set_error(SIEVE_ERROR_CONNECTION); |
| | | } |
| | | |
| | | if (!empty($auth_cid)) { |
| | | $authz = $username; |
| | | $username = $auth_cid; |
| | | $password = $auth_pw; |
| | | } |
| | | |
| | | if (PEAR::isError($this->sieve->login($username, $password, |
| | | $auth_type ? strtoupper($auth_type) : null, $authz)) |
| | | ) { |
| | | return $this->_set_error(SIEVE_ERROR_LOGIN); |
| | | } |
| | | |
| | | $this->exts = $this->get_extensions(); |
| | | $this->disabled = $disabled; |
| | | } |
| | | |
| | | public function __destruct() { |
| | | $this->sieve->disconnect(); |
| | | } |
| | | |
| | | /** |
| | | * Getter for error code |
| | | */ |
| | | public function error() |
| | | { |
| | | return $this->error ? $this->error : false; |
| | | } |
| | | |
| | | /** |
| | | * Saves current script into server |
| | | */ |
| | | public function save($name = null) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if (!$this->script) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if (!$name) |
| | | $name = $this->current; |
| | | |
| | | $script = $this->script->as_text(); |
| | | |
| | | if (!$script) |
| | | $script = '/* empty script */'; |
| | | |
| | | if (PEAR::isError($this->sieve->installScript($name, $script))) |
| | | return $this->_set_error(SIEVE_ERROR_INSTALL); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Saves text script into server |
| | | */ |
| | | public function save_script($name, $content = null) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if (!$content) |
| | | $content = '/* empty script */'; |
| | | |
| | | if (PEAR::isError($this->sieve->installScript($name, $content))) |
| | | return $this->_set_error(SIEVE_ERROR_INSTALL); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Activates specified script |
| | | */ |
| | | public function activate($name = null) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if (!$name) |
| | | $name = $this->current; |
| | | |
| | | if (PEAR::isError($this->sieve->setActive($name))) |
| | | return $this->_set_error(SIEVE_ERROR_ACTIVATE); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * De-activates specified script |
| | | */ |
| | | public function deactivate() |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if (PEAR::isError($this->sieve->setActive(''))) |
| | | return $this->_set_error(SIEVE_ERROR_DEACTIVATE); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Removes specified script |
| | | */ |
| | | public function remove($name = null) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if (!$name) |
| | | $name = $this->current; |
| | | |
| | | // script must be deactivated first |
| | | if ($name == $this->sieve->getActive()) |
| | | if (PEAR::isError($this->sieve->setActive(''))) |
| | | return $this->_set_error(SIEVE_ERROR_DELETE); |
| | | |
| | | if (PEAR::isError($this->sieve->removeScript($name))) |
| | | return $this->_set_error(SIEVE_ERROR_DELETE); |
| | | |
| | | if ($name == $this->current) |
| | | $this->current = null; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Gets list of supported by server Sieve extensions |
| | | */ |
| | | public function get_extensions() |
| | | { |
| | | if ($this->exts) |
| | | return $this->exts; |
| | | |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | $ext = $this->sieve->getExtensions(); |
| | | // we're working on lower-cased names |
| | | $ext = array_map('strtolower', (array) $ext); |
| | | |
| | | if ($this->script) { |
| | | $supported = $this->script->get_extensions(); |
| | | foreach ($ext as $idx => $ext_name) |
| | | if (!in_array($ext_name, $supported)) |
| | | unset($ext[$idx]); |
| | | } |
| | | |
| | | return array_values($ext); |
| | | } |
| | | |
| | | /** |
| | | * Gets list of scripts from server |
| | | */ |
| | | public function get_scripts() |
| | | { |
| | | if (!$this->list) { |
| | | |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | $list = $this->sieve->listScripts(); |
| | | |
| | | if (PEAR::isError($list)) |
| | | return $this->_set_error(SIEVE_ERROR_OTHER); |
| | | |
| | | $this->list = $list; |
| | | } |
| | | |
| | | return $this->list; |
| | | } |
| | | |
| | | /** |
| | | * Returns active script name |
| | | */ |
| | | public function get_active() |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | return $this->sieve->getActive(); |
| | | } |
| | | |
| | | /** |
| | | * Loads script by name |
| | | */ |
| | | public function load($name) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if ($this->current == $name) |
| | | return true; |
| | | |
| | | $script = $this->sieve->getScript($name); |
| | | |
| | | if (PEAR::isError($script)) |
| | | return $this->_set_error(SIEVE_ERROR_OTHER); |
| | | |
| | | // try to parse from Roundcube format |
| | | $this->script = $this->_parse($script); |
| | | |
| | | $this->current = $name; |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Loads script from text content |
| | | */ |
| | | public function load_script($script) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | // try to parse from Roundcube format |
| | | $this->script = $this->_parse($script); |
| | | } |
| | | |
| | | /** |
| | | * Creates rcube_sieve_script object from text script |
| | | */ |
| | | private function _parse($txt) |
| | | { |
| | | // try to parse from Roundcube format |
| | | $script = new rcube_sieve_script($txt, $this->disabled, $this->exts); |
| | | |
| | | // ... else try to import from different formats |
| | | if (empty($script->content)) { |
| | | $script = $this->_import_rules($txt); |
| | | $script = new rcube_sieve_script($script, $this->disabled, $this->exts); |
| | | |
| | | // replace all elsif with if+stop, we support only ifs |
| | | foreach ($script->content as $idx => $rule) { |
| | | // 'stop' not found? |
| | | foreach ($rule['actions'] as $action) { |
| | | if (preg_match('/^(stop|vacation)$/', $action['type'])) { |
| | | continue 2; |
| | | } |
| | | } |
| | | $script->content[$idx]['actions'][] = array('type' => 'stop'); |
| | | } |
| | | } |
| | | |
| | | return $script; |
| | | } |
| | | |
| | | /** |
| | | * Gets specified script as text |
| | | */ |
| | | public function get_script($name) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | $content = $this->sieve->getScript($name); |
| | | |
| | | if (PEAR::isError($content)) |
| | | return $this->_set_error(SIEVE_ERROR_OTHER); |
| | | |
| | | return $content; |
| | | } |
| | | |
| | | /** |
| | | * Creates empty script or copy of other script |
| | | */ |
| | | public function copy($name, $copy) |
| | | { |
| | | if (!$this->sieve) |
| | | return $this->_set_error(SIEVE_ERROR_INTERNAL); |
| | | |
| | | if ($copy) { |
| | | $content = $this->sieve->getScript($copy); |
| | | |
| | | if (PEAR::isError($content)) |
| | | return $this->_set_error(SIEVE_ERROR_OTHER); |
| | | } |
| | | |
| | | return $this->save_script($name, $content); |
| | | } |
| | | |
| | | private function _import_rules($script) |
| | | { |
| | | $i = 0; |
| | | $name = array(); |
| | | |
| | | // Squirrelmail (Avelsieve) |
| | | if ($tokens = preg_split('/(#START_SIEVE_RULE.*END_SIEVE_RULE)\r?\n/', $script, -1, PREG_SPLIT_DELIM_CAPTURE)) { |
| | | foreach($tokens as $token) { |
| | | if (preg_match('/^#START_SIEVE_RULE.*/', $token, $matches)) { |
| | | $name[$i] = "unnamed rule ".($i+1); |
| | | $content .= "# rule:[".$name[$i]."]\n"; |
| | | } |
| | | elseif (isset($name[$i])) { |
| | | // This preg_replace is added because I've found some Avelsieve scripts |
| | | // with rules containing "if" here. I'm not sure it was working |
| | | // before without this or not. |
| | | $token = preg_replace('/^if\s+/', '', trim($token)); |
| | | $content .= "if $token\n"; |
| | | $i++; |
| | | } |
| | | } |
| | | } |
| | | // Horde (INGO) |
| | | else if ($tokens = preg_split('/(# .+)\r?\n/i', $script, -1, PREG_SPLIT_DELIM_CAPTURE)) { |
| | | foreach($tokens as $token) { |
| | | if (preg_match('/^# (.+)/i', $token, $matches)) { |
| | | $name[$i] = $matches[1]; |
| | | $content .= "# rule:[" . $name[$i] . "]\n"; |
| | | } |
| | | elseif (isset($name[$i])) { |
| | | $token = str_replace(":comparator \"i;ascii-casemap\" ", "", $token); |
| | | $content .= $token . "\n"; |
| | | $i++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return $content; |
| | | } |
| | | |
| | | private function _set_error($error) |
| | | { |
| | | $this->error = $error; |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * This is our own debug handler for connection |
| | | */ |
| | | public function debug_handler(&$sieve, $message) |
| | | { |
| | | write_log('sieve', preg_replace('/\r\n$/', '', $message)); |
| | | } |
| | | } |
plugins/managesieve/lib/rcube_sieve_script.php
plugins/managesieve/localization/bg_BG.inc
plugins/managesieve/localization/cs_CZ.inc
plugins/managesieve/localization/de_CH.inc
plugins/managesieve/localization/de_DE.inc
plugins/managesieve/localization/el_GR.inc
plugins/managesieve/localization/en_GB.inc
plugins/managesieve/localization/en_US.inc
plugins/managesieve/localization/es_AR.inc
plugins/managesieve/localization/es_ES.inc
plugins/managesieve/localization/et_EE.inc
plugins/managesieve/localization/fi_FI.inc
plugins/managesieve/localization/fr_FR.inc
plugins/managesieve/localization/gl_ES.inc
plugins/managesieve/localization/hr_HR.inc
plugins/managesieve/localization/hu_HU.inc
plugins/managesieve/localization/it_IT.inc
plugins/managesieve/localization/ja_JP.inc
plugins/managesieve/localization/nb_NO.inc
plugins/managesieve/localization/nl_NL.inc
plugins/managesieve/localization/pl_PL.inc
plugins/managesieve/localization/pt_BR.inc
plugins/managesieve/localization/pt_PT.inc
plugins/managesieve/localization/ru_RU.inc
plugins/managesieve/localization/sk_SK.inc
plugins/managesieve/localization/sl_SI.inc
plugins/managesieve/localization/sv_SE.inc
plugins/managesieve/localization/uk_UA.inc
plugins/managesieve/localization/zh_CN.inc
plugins/managesieve/localization/zh_TW.inc
plugins/managesieve/managesieve.js
plugins/managesieve/managesieve.php
plugins/managesieve/skins/default/managesieve.css
plugins/managesieve/skins/default/managesieve_toolbar.png
plugins/managesieve/skins/default/templates/filteredit.html
plugins/managesieve/skins/default/templates/managesieve.html
plugins/managesieve/skins/default/templates/setedit.html
plugins/managesieve/tests/Makefile
plugins/managesieve/tests/parser.phpt
plugins/managesieve/tests/tokenize.phpt
plugins/markasjunk/localization/cs_CZ.inc
plugins/markasjunk/localization/da_DK.inc
plugins/markasjunk/localization/de_DE.inc
plugins/markasjunk/localization/en_US.inc
plugins/markasjunk/localization/es_AR.inc
plugins/markasjunk/localization/es_ES.inc
plugins/markasjunk/localization/et_EE.inc
plugins/markasjunk/localization/gl_ES.inc
plugins/markasjunk/localization/it_IT.inc
plugins/markasjunk/localization/ja_JP.inc
plugins/markasjunk/localization/pl_PL.inc
plugins/markasjunk/localization/ru_RU.inc
plugins/markasjunk/localization/sk_SK.inc
plugins/markasjunk/localization/sv_SE.inc
plugins/markasjunk/localization/zh_TW.inc
plugins/markasjunk/markasjunk.js
plugins/markasjunk/markasjunk.php
plugins/markasjunk/package.xml
plugins/markasjunk/skins/default/junk_act.png
plugins/markasjunk/skins/default/junk_pas.png
plugins/new_user_dialog/localization/cs_CZ.inc
plugins/new_user_dialog/localization/de_CH.inc
plugins/new_user_dialog/localization/de_DE.inc
plugins/new_user_dialog/localization/en_US.inc
plugins/new_user_dialog/localization/es_ES.inc
plugins/new_user_dialog/localization/et_EE.inc
plugins/new_user_dialog/localization/gl_ES.inc
plugins/new_user_dialog/localization/it_IT.inc
plugins/new_user_dialog/localization/ja_JP.inc
plugins/new_user_dialog/localization/nl_NL.inc
plugins/new_user_dialog/localization/pl_PL.inc
plugins/new_user_dialog/localization/pt_BR.inc
plugins/new_user_dialog/localization/pt_PT.inc
plugins/new_user_dialog/localization/ru_RU.inc
plugins/new_user_dialog/localization/sk_SK.inc
plugins/new_user_dialog/localization/sl_SI.inc
plugins/new_user_dialog/localization/sv_SE.inc
plugins/new_user_dialog/localization/zh_TW.inc
plugins/new_user_dialog/new_user_dialog.php
plugins/new_user_dialog/newuserdialog.css
plugins/new_user_dialog/package.xml
plugins/new_user_identity/new_user_identity.php
plugins/newmail_notifier/config.inc.php.dist
plugins/newmail_notifier/favicon.ico
plugins/newmail_notifier/localization/en_US.inc
plugins/newmail_notifier/localization/pl_PL.inc
plugins/newmail_notifier/newmail_notifier.js
plugins/newmail_notifier/newmail_notifier.php
plugins/newmail_notifier/sound.wav
plugins/password/README
plugins/password/config.inc.php.dist
plugins/password/drivers/chgsaslpasswd.c
plugins/password/drivers/chgvirtualminpasswd.c
plugins/password/drivers/chpass-wrapper.py
plugins/password/drivers/chpasswd.php
plugins/password/drivers/cpanel.php
plugins/password/drivers/directadmin.php
plugins/password/drivers/hmail.php
plugins/password/drivers/ldap.php
plugins/password/drivers/ldap_simple.php
plugins/password/drivers/pam.php
plugins/password/drivers/poppassd.php
plugins/password/drivers/sasl.php
plugins/password/drivers/sql.php
plugins/password/drivers/virtualmin.php
plugins/password/drivers/vpopmaild.php
plugins/password/drivers/ximss.php
plugins/password/drivers/xmail.php
plugins/password/localization/az_AZ.inc
plugins/password/localization/bg_BG.inc
plugins/password/localization/ca_ES.inc
plugins/password/localization/cs_CZ.inc
plugins/password/localization/da_DK.inc
plugins/password/localization/de_CH.inc
plugins/password/localization/de_DE.inc
plugins/password/localization/en_US.inc
plugins/password/localization/es_AR.inc
plugins/password/localization/es_ES.inc
plugins/password/localization/et_EE.inc
plugins/password/localization/fi_FI.inc
plugins/password/localization/fr_FR.inc
plugins/password/localization/gl_ES.inc
plugins/password/localization/hr_HR.inc
plugins/password/localization/hu_HU.inc
plugins/password/localization/it_IT.inc
plugins/password/localization/ja_JP.inc
plugins/password/localization/lt_LT.inc
plugins/password/localization/lv_LV.inc
plugins/password/localization/nl_NL.inc
plugins/password/localization/pl_PL.inc
plugins/password/localization/pt_BR.inc
plugins/password/localization/pt_PT.inc
plugins/password/localization/ru_RU.inc
plugins/password/localization/sk_SK.inc
plugins/password/localization/sl_SI.inc
plugins/password/localization/sv_SE.inc
plugins/password/localization/tr_TR.inc
plugins/password/localization/zh_TW.inc
plugins/password/package.xml
plugins/password/password.js
plugins/password/password.php
plugins/redundant_attachments/config.inc.php.dist
plugins/redundant_attachments/redundant_attachments.php
plugins/show_additional_headers/show_additional_headers.php
plugins/squirrelmail_usercopy/config.inc.php.dist
plugins/squirrelmail_usercopy/squirrelmail_usercopy.php
plugins/subscriptions_option/localization/cs_CZ.inc
plugins/subscriptions_option/localization/de_CH.inc
plugins/subscriptions_option/localization/de_DE.inc
plugins/subscriptions_option/localization/en_US.inc
plugins/subscriptions_option/localization/es_ES.inc
plugins/subscriptions_option/localization/et_EE.inc
plugins/subscriptions_option/localization/gl_ES.inc
plugins/subscriptions_option/localization/ja_JP.inc
plugins/subscriptions_option/localization/pl_PL.inc
plugins/subscriptions_option/localization/ru_RU.inc
plugins/subscriptions_option/localization/sv_SE.inc
plugins/subscriptions_option/localization/zh_TW.inc
plugins/subscriptions_option/subscriptions_option.php
plugins/userinfo/localization/cs_CZ.inc
plugins/userinfo/localization/da_DK.inc
plugins/userinfo/localization/de_CH.inc
plugins/userinfo/localization/en_US.inc
plugins/userinfo/localization/es_ES.inc
plugins/userinfo/localization/et_EE.inc
plugins/userinfo/localization/gl_ES.inc
plugins/userinfo/localization/ja_JP.inc
plugins/userinfo/localization/pl_PL.inc
plugins/userinfo/localization/pt_BR.inc
plugins/userinfo/localization/pt_PT.inc
plugins/userinfo/localization/ru_RU.inc
plugins/userinfo/localization/sv_SE.inc
plugins/userinfo/localization/zh_TW.inc
plugins/userinfo/userinfo.js
plugins/userinfo/userinfo.php
plugins/vcard_attachments/localization/cs_CZ.inc
plugins/vcard_attachments/localization/de_CH.inc
plugins/vcard_attachments/localization/de_DE.inc
plugins/vcard_attachments/localization/en_US.inc
plugins/vcard_attachments/localization/es_ES.inc
plugins/vcard_attachments/localization/et_EE.inc
plugins/vcard_attachments/localization/gl_ES.inc
plugins/vcard_attachments/localization/it_IT.inc
plugins/vcard_attachments/localization/ja_JP.inc
plugins/vcard_attachments/localization/pl_PL.inc
plugins/vcard_attachments/localization/pt_BR.inc
plugins/vcard_attachments/localization/ru_RU.inc
plugins/vcard_attachments/localization/sv_SE.inc
plugins/vcard_attachments/localization/zh_TW.inc
plugins/vcard_attachments/package.xml
plugins/vcard_attachments/skins/default/vcard.png
plugins/vcard_attachments/skins/default/vcard_add_contact.png
plugins/vcard_attachments/vcard_attachments.php
plugins/vcard_attachments/vcardattach.js
plugins/virtuser_file/virtuser_file.php
plugins/virtuser_query/virtuser_query.php |