1<?php
2/*********************************************************************
3    class.config.php
4
5    osTicket config info manager.
6
7    Peter Rotich <peter@osticket.com>
8    Copyright (c)  2006-2013 osTicket
9    http://www.osticket.com
10
11    Released under the GNU General Public License WITHOUT ANY WARRANTY.
12    See LICENSE.TXT for details.
13
14    vim: expandtab sw=4 ts=4 sts=4:
15**********************************************************************/
16require_once INCLUDE_DIR . 'class.orm.php';
17
18class Config {
19    var $config = array();
20
21    var $section = null;                    # Default namespace ('core')
22    var $table = CONFIG_TABLE;              # Table name (with prefix)
23    var $section_column = 'namespace';      # namespace column name
24
25    var $session = null;                    # Session-backed configuration
26
27    # Defaults for this configuration. If settings don't exist in the
28    # database yet, the ->getInfo() method will not include the (default)
29    # values in the returned array. $defaults allows developers to define
30    # new settings and the corresponding default values.
31    var $defaults = array();                # List of default values
32
33    function __construct($section=null, $defaults=array()) {
34        if ($section)
35            $this->section = $section;
36
37        if ($this->section === null)
38            return false;
39
40        if ($defaults)
41            $this->defaults = $defaults;
42
43        if (isset($_SESSION['cfg:'.$this->section]))
44            $this->session = &$_SESSION['cfg:'.$this->section];
45
46        $this->load();
47    }
48
49    function load() {
50        foreach ($this->items() as $I)
51            $this->config[$I->key] = $I;
52    }
53
54    function getNamespace() {
55        return $this->section;
56    }
57
58    function getInfo() {
59        $info = $this->defaults;
60        foreach ($this->config as $key=>$item)
61            $info[$key] = $item->value;
62        return $info;
63    }
64
65    function get($key, $default=null) {
66        if (isset($this->session) && isset($this->session[$key]))
67            return $this->session[$key];
68        elseif (isset($this->config[$key]))
69            return $this->config[$key]->value;
70        elseif (isset($this->defaults[$key]))
71            return $this->defaults[$key];
72
73        return $default;
74    }
75
76    function exists($key) {
77        return $this->get($key, null) ? true : false;
78    }
79
80    function set($key, $value) {
81        return ($this->update($key, $value)) ? $value : null;
82    }
83
84    function persist($key, $value) {
85        if (!isset($this->session)) {
86            $this->session = &$_SESSION['cfg:'.$this->section];
87            $this->session = array();
88        }
89        $this->session[$key] = $value;
90        return true;
91    }
92
93    function lastModified($key) {
94        if (isset($this->config[$key]))
95            return $this->config[$key]->updated;
96
97        return false;
98    }
99
100    function create($key, $value) {
101        $item = new ConfigItem([
102            $this->section_column => $this->section,
103            'key' => $key,
104            'value' => $value,
105        ]);
106        if (!$item->save())
107            return false;
108
109        return true;
110    }
111
112    function update($key, $value) {
113        if (!$key)
114            return false;
115        elseif (!isset($this->config[$key]))
116            return $this->create($key, $value);
117
118        $item = $this->config[$key];
119        $before = $item->value;
120        $item->value = $value;
121
122        if ($before != $item->value) {
123            $type = array('type' => 'edited', 'key' => $item->ht['key']);
124            Signal::send('object.edited', $item, $type);
125        }
126
127        return $item->save();
128    }
129
130    function updateAll($updates) {
131        foreach ($updates as $key=>$value)
132            if (!$this->update($key, $value))
133                return false;
134        return true;
135    }
136
137    function destroy() {
138        unset($this->session);
139        return $this->items()->delete() > 0;
140    }
141
142    function items() {
143        return ConfigItem::items($this->section, $this->section_column);
144    }
145}
146
147class ConfigItem
148extends VerySimpleModel {
149    static $meta = array(
150        'table' => CONFIG_TABLE,
151        'pk' => array('id'),
152    );
153
154    static function items($namespace, $column='namespace') {
155
156        $items = static::objects()
157            ->filter([$column => $namespace]);
158
159        try {
160            count($items);
161        }
162        catch (InconsistentModelException $ex) {
163            // Pending upgrade ??
164            $items = array();
165        }
166
167        return $items;
168    }
169
170    function save($refetch=false) {
171        if ($this->dirty)
172            $this->updated = SqlFunction::NOW();
173        return parent::save($this->dirty || $refetch);
174    }
175
176    // Clean password reset tokens that have expired
177    static function cleanPwResets() {
178        global $cfg;
179
180        if (!$cfg || !($period = $cfg->getPwResetWindow())) // In seconds
181            return false;
182
183        return ConfigItem::objects()
184             ->filter(array(
185                'namespace' => 'pwreset',
186                'updated__lt' => SqlFunction::NOW()->minus(SqlInterval::SECOND($period)),
187            ))->delete();
188    }
189
190    function getConfigsByNamespace($namespace=false, $key, $value=false) {
191        $filter = array();
192
193         $filter['key'] = $key;
194
195         if ($namespace)
196            $filter['namespace'] = $namespace;
197
198         if ($value)
199            $filter['value'] = $value;
200
201         $token = ConfigItem::objects()
202            ->filter($filter);
203
204         return $namespace ? $token[0] : $token;
205    }
206}
207
208class OsticketConfig extends Config {
209    var $table = CONFIG_TABLE;
210    var $section = 'core';
211
212    var $defaultDept;   //Default Department
213    var $defaultSLA;   //Default SLA
214    var $defaultSchedule; // Default Schedule
215    var $defaultEmail;  //Default Email
216    var $alertEmail;  //Alert Email
217    var $defaultSMTPEmail; //Default  SMTP Email
218
219    var $defaults = array(
220        'allow_pw_reset' =>     true,
221        'pw_reset_window' =>    30,
222        'enable_richtext' =>    true,
223        'enable_avatars' =>     true,
224        'allow_attachments' =>  true,
225        'agent_name_format' =>  'full', # First Last
226        'client_name_format' => 'original', # As entered
227        'auto_claim_tickets'=>  true,
228        'auto_refer_closed' => true,
229        'collaborator_ticket_visibility' =>  true,
230        'disable_agent_collabs' => false,
231        'require_topic_to_close' =>  false,
232        'system_language' =>    'en_US',
233        'default_storage_bk' => 'D',
234        'message_autoresponder_collabs' => true,
235        'add_email_collabs' => true,
236        'clients_only' => false,
237        'client_registration' => 'closed',
238        'accept_unregistered_email' => true,
239        'default_help_topic' => 0,
240        'help_topic_sort_mode' => 'a',
241        'client_verify_email' => 1,
242        'allow_auth_tokens' => 1,
243        'verify_email_addrs' => 1,
244        'client_avatar' => 'gravatar.mm',
245        'agent_avatar' => 'gravatar.mm',
246        'ticket_lock' => 2, // Lock on activity
247        'max_open_tickets' => 0,
248        'files_req_auth' => 1,
249        'force_https' => '',
250        'allow_external_images' => 0,
251    );
252
253    function __construct($section=null) {
254        parent::__construct($section);
255
256        if (count($this->config) == 0) {
257            // Fallback for osticket < 1.7@852ca89e
258            $sql='SELECT * FROM '.$this->table.' WHERE id = 1';
259            $meta = ConfigItem::getMeta();
260            if (($res=db_query($sql)) && db_num_rows($res))
261                foreach (db_fetch_array($res) as $key=>$value)
262                    $this->config[$key] = $meta->newInstance(array('value'=>$value));
263        }
264
265        return true;
266    }
267
268    function lastModified($key=false) {
269        return max(array_map(array('parent', 'lastModified'),
270            array_keys($this->config)));
271    }
272
273    function isHelpDeskOffline() {
274        return !$this->isOnline();
275    }
276
277    function isHelpDeskOnline() {
278        return $this->isOnline();
279    }
280
281    function isOnline() {
282        return ($this->get('isonline'));
283    }
284
285    function isKnowledgebaseEnabled() {
286        global $thisclient;
287
288        if ($this->get('restrict_kb', false)
289            && (!$thisclient || $thisclient->isGuest())
290        ) {
291            return false;
292        }
293        require_once(INCLUDE_DIR.'class.faq.php');
294        return ($this->get('enable_kb') && FAQ::countPublishedFAQs());
295    }
296
297    function isCannedResponseEnabled() {
298        return $this->get('enable_premade');
299    }
300
301    function getVersion() {
302        return THIS_VERSION;
303    }
304
305    function getSchemaSignature($section=null) {
306
307        if ((!$section || $section == $this->section)
308                && ($v=$this->get('schema_signature')))
309            return $v;
310
311        // 1.7 after namespaced configuration, other namespace
312        if ($section) {
313            $sql='SELECT value FROM '.$this->table
314                .' WHERE `key` = "schema_signature" and namespace='.db_input($section);
315            if (($res=db_query($sql, false)) && db_num_rows($res))
316                return db_result($res);
317        }
318
319        // 1.7 before namespaced configuration
320        $sql='SELECT `schema_signature` FROM '.$this->table
321            .' WHERE id=1';
322        if (($res=db_query($sql, false)) && db_num_rows($res))
323            return db_result($res);
324
325        // old version 1.6
326        return md5(self::getDBVersion());
327    }
328
329    function getDbTimezone() {
330        if (!$this->exists('db_timezone')) {
331            require_once INCLUDE_DIR . 'class.timezone.php';
332            $this->persist('db_timezone', DbTimezone::determine());
333        }
334        return $this->get('db_timezone');
335    }
336
337    function getDefaultTimezone() {
338        return $this->get('default_timezone');
339    }
340
341    function getTimezone($user=false) {
342        global $thisstaff, $thisclient;
343
344        $user = $user ?: $thisstaff;
345
346        if (!$user && $thisclient && is_callable(array($thisclient, 'getTimezone')))
347            $user = $thisclient;
348
349        if ($user)
350            $zone = $user->getTimezone();
351
352        if (!$zone)
353            $zone = $this->get('default_timezone');
354
355        if (!$zone)
356            $zone = ini_get('date.timezone');
357
358        return $zone;
359    }
360
361    function getDefaultLocale() {
362        return $this->get('default_locale');
363    }
364
365    /* Date & Time Formats */
366    function getTimeFormat($propogate=false) {
367        global $cfg;
368
369        if ($this->get('date_formats') == 'custom')
370            return $this->get('time_format');
371
372        if ($propogate) {
373            $format = 'h:i a'; // Default
374            if (class_exists('IntlDateFormatter')) {
375                $formatter = new IntlDateFormatter(
376                    Internationalization::getCurrentLocale(),
377                    IntlDateFormatter::NONE,
378                    IntlDateFormatter::SHORT,
379                    $this->getTimezone(),
380                    IntlDateFormatter::GREGORIAN
381                );
382                $format = $formatter->getPattern();
383            }
384            // Check if we're forcing 24 hrs format
385            if ($cfg && $cfg->isForce24HourTime() && $format)
386                $format = trim(str_replace(array('a', 'h'), array('', 'H'),
387                            $format));
388            return $format;
389        }
390
391        return '';
392    }
393
394    function isForce24HourTime() {
395        return $this->get('date_formats') == '24';
396    }
397
398    /**
399     * getDateFormat
400     *
401     * Retrieve the current date format for the system, as a string, and in
402     * the intl (icu) format.
403     *
404     * Parameters:
405     * $propogate - (boolean:default=false), if set and the configuration
406     *      indicates default date and time formats (ie. not custom), then
407     *      the intl date formatter will be queried to find the pattern used
408     *      internally for the current locale settings.
409     */
410    function getDateFormat($propogate=false) {
411        if ($this->get('date_formats') == 'custom')
412            return $this->get('date_format');
413        if ($propogate) {
414            if (class_exists('IntlDateFormatter')) {
415                $formatter = new IntlDateFormatter(
416                    Internationalization::getCurrentLocale(),
417                    IntlDateFormatter::SHORT,
418                    IntlDateFormatter::NONE,
419                    $this->getTimezone(),
420                    IntlDateFormatter::GREGORIAN
421                );
422                return $formatter->getPattern();
423            }
424            // Use a standard
425            return 'y-M-d';
426        }
427        return '';
428    }
429
430    function getDateTimeFormat() {
431        if ($this->get('date_formats') == 'custom')
432            return $this->get('datetime_format');
433
434        if (class_exists('IntlDateFormatter'))
435            return sprintf('%s %s', $this->getDateFormat(true),
436                    $this->getTimeFormat(true));
437
438        return '';
439    }
440
441    function getDayDateTimeFormat() {
442        if ($this->get('date_formats') == 'custom')
443            return $this->get('daydatetime_format');
444        return '';
445    }
446
447    function getConfigInfo() {
448        return $this->getInfo();
449    }
450
451    function getTitle() {
452        return $this->get('helpdesk_title');
453    }
454
455    function getUrl() {
456        return $this->get('helpdesk_url');
457    }
458
459    function getBaseUrl() { //Same as above with no trailing slash.
460        return rtrim($this->getUrl(),'/');
461    }
462
463    function getPageSize() {
464        return $this->get('max_page_size');
465    }
466
467    function getGracePeriod() {
468        return $this->get('overdue_grace_period');
469    }
470
471    // This is here for legacy reasons - default osTicket Password Policy
472    // uses it, if previously set.
473    function getPasswdResetPeriod() {
474        return $this->get('passwd_reset_period');
475    }
476
477
478    function getStaffPasswordPolicy() {
479        return $this->get('agent_passwd_policy');
480    }
481
482    function getClientPasswordPolicy() {
483        return $this->get('client_passwd_policy');
484    }
485
486    function require2FAForAgents() {
487         return $this->get('require_agent_2fa');
488    }
489
490    function isRichTextEnabled() {
491        return $this->get('enable_richtext');
492    }
493
494    function getAllowIframes() {
495        return str_replace(array(', ', ','), array(' ', ' '), $this->get('allow_iframes')) ?: "'self'";
496    }
497
498    function getIframeWhitelist() {
499        $whitelist = array_filter(explode(',', str_replace(' ', '', $this->get('embedded_domain_whitelist'))));
500
501        return !empty($whitelist) ? $whitelist : null;
502    }
503
504    function getACL() {
505        if (!($acl = $this->get('acl')))
506            return null;
507
508        return explode(',', str_replace(' ', '', $acl));
509    }
510
511    function getACLBackendOpts() {
512        return array(
513            0 => __('Disabled'),
514            1 => __('All'),
515            2 => __('Client Portal'),
516            3 => __('Staff Panel')
517        );
518    }
519
520    function getACLBackend() {
521        return $this->get('acl_backend') ?: 0;
522    }
523
524    function isAvatarsEnabled() {
525        return $this->get('enable_avatars');
526    }
527
528    function isTicketLockEnabled() {
529        return (($this->getTicketLockMode() != Lock::MODE_DISABLED)
530                && $this->getLockTime());
531    }
532
533    function getClientTimeout() {
534        return $this->getClientSessionTimeout();
535    }
536
537    function getClientSessionTimeout() {
538        return $this->get('client_session_timeout')*60;
539    }
540
541    function getClientLoginTimeout() {
542        return $this->get('client_login_timeout')*60;
543    }
544
545    function getClientMaxLogins() {
546        return $this->get('client_max_logins');
547    }
548
549    function getStaffTimeout() {
550        return $this->getStaffSessionTimeout();
551    }
552
553    function getStaffSessionTimeout() {
554        return $this->get('staff_session_timeout')*60;
555    }
556
557    function getStaffLoginTimeout() {
558        return $this->get('staff_login_timeout')*60;
559    }
560
561    function getStaffMaxLogins() {
562        return $this->get('staff_max_logins');
563    }
564
565    function getStaffAvatarSource() {
566        require_once INCLUDE_DIR . 'class.avatar.php';
567        list($source, $mode) = explode('.', $this->get('agent_avatar'), 2);
568        return AvatarSource::lookup($source, $mode);
569    }
570
571    function getClientAvatarSource() {
572        require_once INCLUDE_DIR . 'class.avatar.php';
573        list($source, $mode) = explode('.', $this->get('client_avatar'), 2);
574        return AvatarSource::lookup($source, $mode);
575    }
576
577    function getLockTime() {
578        return $this->get('autolock_minutes');
579    }
580
581    function getTicketLockMode() {
582        return $this->get('ticket_lock');
583    }
584
585    function getAgentNameFormat() {
586        return $this->get('agent_name_format');
587    }
588
589    function getClientNameFormat() {
590        return $this->get('client_name_format');
591    }
592
593    function getDefaultDeptId() {
594        return $this->get('default_dept_id');
595    }
596
597    function getDefaultDept() {
598
599        if(!$this->defaultDept && $this->getDefaultDeptId())
600            $this->defaultDept=Dept::lookup($this->getDefaultDeptId());
601
602        return $this->defaultDept;
603    }
604
605    function getDefaultEmailId() {
606        return $this->get('default_email_id');
607    }
608
609    function getDefaultEmail() {
610
611        if(!$this->defaultEmail && $this->getDefaultEmailId())
612            $this->defaultEmail = Email::lookup($this->getDefaultEmailId());
613
614        return $this->defaultEmail;
615    }
616
617    function getDefaultEmailAddress() {
618        return ($email=$this->getDefaultEmail()) ? $email->getAddress() : null;
619    }
620
621    function getDefaultTicketStatusId() {
622        return $this->get('default_ticket_status_id', 1);
623    }
624
625    function getDefaultSLAId() {
626        return $this->get('default_sla_id');
627    }
628
629    function getDefaultSLA() {
630
631        if(!$this->defaultSLA && $this->getDefaultSLAId())
632            $this->defaultSLA = SLA::lookup($this->getDefaultSLAId());
633
634        return $this->defaultSLA;
635    }
636
637    function getDefaultScheduleId() {
638        return $this->get('schedule_id');
639    }
640
641    function getDefaultSchedule() {
642        if (!isset($this->defaultSchedule) && $this->getDefaultScheduleId())
643            $this->defaultSchedule = BusinessHoursSchedule::lookup(
644                    $this->getDefaultScheduleId());
645
646        return $this->defaultSchedule;
647    }
648
649    function getAlertEmailId() {
650        return $this->get('alert_email_id');
651    }
652
653    function getAlertEmail() {
654
655        if(!$this->alertEmail)
656            if(!($this->alertEmail = Email::lookup($this->getAlertEmailId())))
657                $this->alertEmail = $this->getDefaultEmail();
658
659        return $this->alertEmail;
660    }
661
662    function getDefaultSMTPEmail() {
663
664        if(!$this->defaultSMTPEmail && $this->get('default_smtp_id'))
665            $this->defaultSMTPEmail = Email::lookup($this->get('default_smtp_id'));
666
667        return $this->defaultSMTPEmail;
668    }
669
670    function getDefaultPriorityId() {
671        return $this->get('default_priority_id');
672    }
673
674    function getDefaultPriority() {
675        if (!isset($this->defaultPriority))
676            $this->defaultPriority = Priority::lookup($this->getDefaultPriorityId());
677
678        return $this->defaultPriority;
679    }
680
681    function getDefaultTopicId() {
682        return $this->get('default_help_topic');
683    }
684
685    function getDefaultTopic() {
686        return Topic::lookup($this->getDefaultTopicId());
687    }
688
689    function getTopicSortMode() {
690        return $this->get('help_topic_sort_mode');
691    }
692
693    function forceHttps() {
694        return $this->get('force_https') == 'on';
695    }
696
697    function setTopicSortMode($mode) {
698        $modes = static::allTopicSortModes();
699        if (!isset($modes[$mode]))
700            throw new InvalidArgumentException(sprintf(
701                '%s: Unsupported help topic sort mode', $mode));
702
703        $this->update('help_topic_sort_mode', $mode);
704    }
705
706    static function allTopicSortModes() {
707        return array(
708            Topic::SORT_ALPHA   => __('Alphabetically'),
709            Topic::SORT_MANUAL  => __('Manually'),
710        );
711    }
712
713    function getDefaultTemplateId() {
714        return $this->get('default_template_id');
715    }
716
717    function getDefaultTemplate() {
718
719        if(!$this->defaultTemplate && $this->getDefaultTemplateId())
720            $this->defaultTemplate = EmailTemplateGroup::lookup($this->getDefaultTemplateId());
721
722        return $this->defaultTemplate;
723    }
724
725    function getLandingPageId() {
726        return $this->get('landing_page_id');
727    }
728
729    function getLandingPage() {
730
731        if(!$this->landing_page && $this->getLandingPageId())
732            $this->landing_page = Page::lookup($this->getLandingPageId());
733
734        return $this->landing_page;
735    }
736
737    function getOfflinePageId() {
738        return $this->get('offline_page_id');
739    }
740
741    function getOfflinePage() {
742
743        if(!$this->offline_page && $this->getOfflinePageId())
744            $this->offline_page = Page::lookup($this->getOfflinePageId());
745
746        return $this->offline_page;
747    }
748
749    function getThankYouPageId() {
750        return $this->get('thank-you_page_id');
751    }
752
753    function getThankYouPage() {
754
755        if(!$this->thankyou_page && $this->getThankYouPageId())
756            $this->thankyou_page = Page::lookup($this->getThankYouPageId());
757
758        return $this->thankyou_page;
759    }
760
761    function getDefaultPages() {
762        /* Array of ids...as opposed to objects */
763        return array(
764                $this->getLandingPageId(),
765                $this->getOfflinePageId(),
766                $this->getThankYouPageId(),
767                );
768    }
769
770    function getMaxOpenTickets() {
771         return $this->get('max_open_tickets');
772    }
773
774    function getMaxFileSize() {
775        return $this->get('max_file_size');
776    }
777
778    function getLogLevel() {
779        return $this->get('log_level');
780    }
781
782    function getLogGracePeriod() {
783        return $this->get('log_graceperiod');
784    }
785
786    function enableStaffIPBinding() {
787        return ($this->get('staff_ip_binding'));
788    }
789
790    /**
791     * Configuration: allow_pw_reset
792     *
793     * TRUE if the <a>Forgot my password</a> link and system should be
794     * enabled, and FALSE otherwise.
795     */
796    function allowPasswordReset() {
797        return $this->get('allow_pw_reset');
798    }
799
800    /**
801     * Configuration: pw_reset_window
802     *
803     * Number of minutes for which the password reset token is valid.
804     *
805     * Returns: Number of seconds the password reset token is valid. The
806     *      number of minutes from the database is automatically converted
807     *      to seconds here.
808     */
809    function getPwResetWindow() {
810        // pw_reset_window is stored in minutes. Return value in seconds
811        return $this->get('pw_reset_window') * 60;
812    }
813
814    function isClientLoginRequired() {
815        return $this->get('clients_only');
816    }
817
818    function isClientRegistrationEnabled() {
819        return in_array($this->getClientRegistrationMode(),
820            array('public', 'auto'));
821    }
822
823    function getClientRegistrationMode() {
824        return $this->get('client_registration');
825    }
826
827    function isClientRegistrationMode($modes) {
828        if (!is_array($modes))
829            $modes = array($modes);
830
831        return in_array($this->getClientRegistrationMode(), $modes);
832    }
833
834    function isClientEmailVerificationRequired() {
835        return $this->get('client_verify_email');
836    }
837
838    function isAuthTokenEnabled() {
839        return $this->get('allow_auth_tokens');
840    }
841
842    function isCaptchaEnabled() {
843        return (extension_loaded('gd') && function_exists('gd_info') && $this->get('enable_captcha'));
844    }
845
846    function isAutoCronEnabled() {
847        return ($this->get('enable_auto_cron'));
848    }
849
850    function isEmailPollingEnabled() {
851        return ($this->get('enable_mail_polling'));
852    }
853
854    function useEmailPriority() {
855        return ($this->get('use_email_priority'));
856    }
857
858    function acceptUnregisteredEmail() {
859        return $this->get('accept_unregistered_email');
860    }
861
862    function addCollabsViaEmail() {
863        return ($this->get('add_email_collabs'));
864    }
865
866    function getAdminEmail() {
867         return $this->get('admin_email');
868    }
869
870    function verifyEmailAddrs() {
871        return (bool) $this->get('verify_email_addrs');
872    }
873
874    function getReplySeparator() {
875        return $this->get('reply_separator');
876    }
877
878    function stripQuotedReply() {
879        return ($this->get('strip_quoted_reply'));
880    }
881
882    function saveEmailHeaders() {
883        return true; //No longer an option...hint: big plans for headers coming!!
884    }
885
886    function getDefaultTicketSequence() {
887        if ($this->get('ticket_sequence_id'))
888            $sequence = Sequence::lookup($this->get('ticket_sequence_id'));
889        if (!$sequence)
890            $sequence = new RandomSequence();
891        return $sequence;
892    }
893
894    function showTopLevelTicketCounts() {
895        return ($this->get('queue_bucket_counts'));
896    }
897
898    function getDefaultTicketNumberFormat() {
899        return $this->get('ticket_number_format');
900    }
901
902    function getNewTicketNumber() {
903        $s = $this->getDefaultTicketSequence();
904        return $s->next($this->getDefaultTicketNumberFormat(),
905            array('Ticket', 'isTicketNumberUnique'));
906    }
907
908    // Task sequence
909    function getDefaultTaskSequence() {
910        if ($this->get('task_sequence_id'))
911            $sequence = Sequence::lookup($this->get('task_sequence_id'));
912        if (!$sequence)
913            $sequence = new RandomSequence();
914
915        return $sequence;
916    }
917
918    function getDefaultTaskNumberFormat() {
919        return $this->get('task_number_format');
920    }
921
922    function getNewTaskNumber() {
923        $s = $this->getDefaultTaskSequence();
924        return $s->next($this->getDefaultTaskNumberFormat(),
925            array('Task', 'isNumberUnique'));
926    }
927
928    /* autoresponders  & Alerts */
929    function autoRespONNewTicket() {
930        return ($this->get('ticket_autoresponder'));
931    }
932
933    function autoRespONNewMessage() {
934        return ($this->get('message_autoresponder'));
935    }
936
937    function notifyCollabsONNewMessage() {
938        return ($this->get('message_autoresponder_collabs'));
939    }
940
941    function notifyONNewStaffTicket() {
942        return ($this->get('ticket_notice_active'));
943    }
944
945    function alertONNewMessage() {
946        return ($this->get('message_alert_active'));
947    }
948
949    function alertLastRespondentONNewMessage() {
950        return ($this->get('message_alert_laststaff'));
951    }
952
953    function alertAssignedONNewMessage() {
954        return ($this->get('message_alert_assigned'));
955    }
956
957    function alertDeptManagerONNewMessage() {
958        return ($this->get('message_alert_dept_manager'));
959    }
960
961    function alertAcctManagerONNewMessage() {
962        return ($this->get('message_alert_acct_manager'));
963    }
964
965    //TODO: change note_alert to activity_alert
966    function alertONNewActivity() {
967        return ($this->get('note_alert_active'));
968    }
969
970    function alertLastRespondentONNewActivity() {
971        return ($this->get('note_alert_laststaff'));
972    }
973
974    function alertAssignedONNewActivity() {
975        return ($this->get('note_alert_assigned'));
976    }
977
978    function alertDeptManagerONNewActivity() {
979        return ($this->get('note_alert_dept_manager'));
980    }
981
982    function alertONNewTicket() {
983        return ($this->get('ticket_alert_active'));
984    }
985
986    function alertAdminONNewTicket() {
987        return ($this->get('ticket_alert_admin'));
988    }
989
990    function alertDeptManagerONNewTicket() {
991        return ($this->get('ticket_alert_dept_manager'));
992    }
993
994    function alertDeptMembersONNewTicket() {
995        return ($this->get('ticket_alert_dept_members'));
996    }
997
998    function alertAcctManagerONNewTicket() {
999        return ($this->get('ticket_alert_acct_manager'));
1000    }
1001
1002    function alertONTransfer() {
1003        return ($this->get('transfer_alert_active'));
1004    }
1005
1006    function alertAssignedONTransfer() {
1007        return ($this->get('transfer_alert_assigned'));
1008    }
1009
1010    function alertDeptManagerONTransfer() {
1011        return ($this->get('transfer_alert_dept_manager'));
1012    }
1013
1014    function alertDeptMembersONTransfer() {
1015        return ($this->get('transfer_alert_dept_members'));
1016    }
1017
1018    function alertONAssignment() {
1019        return ($this->get('assigned_alert_active'));
1020    }
1021
1022    function alertStaffONAssignment() {
1023        return ($this->get('assigned_alert_staff'));
1024    }
1025
1026    function alertTeamLeadONAssignment() {
1027        return ($this->get('assigned_alert_team_lead'));
1028    }
1029
1030    function alertTeamMembersONAssignment() {
1031        return ($this->get('assigned_alert_team_members'));
1032    }
1033
1034
1035    function alertONOverdueTicket() {
1036        return ($this->get('overdue_alert_active'));
1037    }
1038
1039    function alertAssignedONOverdueTicket() {
1040        return ($this->get('overdue_alert_assigned'));
1041    }
1042
1043    function alertDeptManagerONOverdueTicket() {
1044        return ($this->get('overdue_alert_dept_manager'));
1045    }
1046
1047    function alertDeptMembersONOverdueTicket() {
1048        return ($this->get('overdue_alert_dept_members'));
1049    }
1050
1051    function autoClaimTickets() {
1052        return $this->get('auto_claim_tickets');
1053    }
1054
1055    function autoReferTicketsOnClose() {
1056         return $this->get('auto_refer_closed');
1057    }
1058
1059    function collaboratorTicketsVisibility() {
1060        return $this->get('collaborator_ticket_visibility');
1061    }
1062
1063    function disableAgentCollaborators() {
1064        return $this->get('disable_agent_collabs');
1065    }
1066
1067    function requireTopicToClose() {
1068        return $this->get('require_topic_to_close');
1069    }
1070
1071    function allowExternalImages() {
1072        return ($this->get('allow_external_images'));
1073    }
1074
1075    function getDefaultTicketQueueId() {
1076        return $this->get('default_ticket_queue', 1);
1077    }
1078
1079    function hideStaffName() {
1080        return ($this->get('hide_staff_name'));
1081    }
1082
1083    function sendOverLimitNotice() {
1084        return ($this->get('overlimit_notice_active'));
1085    }
1086
1087    /* Tasks */
1088
1089    function alertONNewTask() {
1090        return ($this->get('task_alert_active'));
1091    }
1092
1093    function alertAdminONNewTask() {
1094        return ($this->get('task_alert_admin'));
1095    }
1096
1097    function alertDeptManagerONNewTask() {
1098        return ($this->get('task_alert_dept_manager'));
1099    }
1100
1101    function alertDeptMembersONNewTask() {
1102        return ($this->get('task_alert_dept_members'));
1103    }
1104
1105    function alertONTaskActivity() {
1106        return ($this->get('task_activity_alert_active'));
1107    }
1108
1109    function alertLastRespondentONTaskActivity() {
1110        return ($this->get('task_activity_alert_laststaff'));
1111    }
1112
1113    function alertAssignedONTaskActivity() {
1114        return ($this->get('task_activity_alert_assigned'));
1115    }
1116
1117    function alertDeptManagerONTaskActivity() {
1118        return ($this->get('task_activity_alert_dept_manager'));
1119    }
1120
1121    function alertONTaskTransfer() {
1122        return ($this->get('task_transfer_alert_active'));
1123    }
1124
1125    function alertAssignedONTaskTransfer() {
1126        return ($this->get('task_transfer_alert_assigned'));
1127    }
1128
1129    function alertDeptManagerONTaskTransfer() {
1130        return ($this->get('task_transfer_alert_dept_manager'));
1131    }
1132
1133    function alertDeptMembersONTaskTransfer() {
1134        return ($this->get('task_transfer_alert_dept_members'));
1135    }
1136
1137    function alertONTaskAssignment() {
1138        return ($this->get('task_assignment_alert_active'));
1139    }
1140
1141    function alertStaffONTaskAssignment() {
1142        return ($this->get('task_assignment_alert_staff'));
1143    }
1144
1145    function alertTeamLeadONTaskAssignment() {
1146        return ($this->get('task_assignment_alert_team_lead'));
1147    }
1148
1149    function alertTeamMembersONTaskAssignment() {
1150        return ($this->get('task_assignment_alert_team_members'));
1151    }
1152
1153    function alertONOverdueTask() {
1154        return ($this->get('task_overdue_alert_active'));
1155    }
1156
1157    function alertAssignedONOverdueTask() {
1158        return ($this->get('task_overdue_alert_assigned'));
1159    }
1160
1161    function alertDeptManagerONOverdueTask() {
1162        return ($this->get('task_overdue_alert_dept_manager'));
1163    }
1164
1165    function alertDeptMembersONOverdueTask() {
1166        return ($this->get('task_overdue_alert_dept_members'));
1167    }
1168
1169    /* Error alerts sent to admin email when enabled */
1170    function alertONSQLError() {
1171        return ($this->get('send_sql_errors'));
1172    }
1173    function alertONLoginError() {
1174        return ($this->get('send_login_errors'));
1175    }
1176
1177
1178
1179    /* Attachments */
1180    function getAllowedFileTypes() {
1181        return trim($this->get('allowed_filetypes'));
1182    }
1183
1184    function emailAttachments() {
1185        return ($this->get('email_attachments'));
1186    }
1187
1188    function allowAttachments() {
1189        return ($this->get('allow_attachments'));
1190    }
1191
1192    function getPrimaryLanguage() {
1193        return $this->get('system_language');
1194    }
1195
1196    function getSecondaryLanguages() {
1197        $langs = $this->get('secondary_langs');
1198        $langs = (is_string($langs)) ? explode(',', $langs) : array();
1199        return array_filter($langs);
1200    }
1201
1202    /* Needed by upgrader on 1.6 and older releases upgrade - not not remove */
1203    function getUploadDir() {
1204        return $this->get('upload_dir');
1205    }
1206
1207    function getDefaultStorageBackendChar() {
1208        return $this->get('default_storage_bk');
1209    }
1210
1211    function getVar($name) {
1212        return $this->get($name);
1213    }
1214
1215    function updateSettings($vars, &$errors) {
1216
1217        if(!$vars || $errors)
1218            return false;
1219
1220        switch(strtolower($vars['t'])) {
1221            case 'system':
1222                return $this->updateSystemSettings($vars, $errors);
1223                break;
1224            case 'tickets':
1225                return $this->updateTicketsSettings($vars, $errors);
1226                break;
1227            case 'tasks':
1228                return $this->updateTasksSettings($vars, $errors);
1229                break;
1230            case 'emails':
1231                return $this->updateEmailsSettings($vars, $errors);
1232                break;
1233            case 'pages':
1234                return $this->updatePagesSettings($vars, $errors);
1235                break;
1236            case 'agents':
1237                return $this->updateAgentsSettings($vars, $errors);
1238                break;
1239            case 'users':
1240                return $this->updateUsersSettings($vars, $errors);
1241                break;
1242            case 'kb':
1243                return $this->updateKBSettings($vars, $errors);
1244                break;
1245            default:
1246                $errors['err']=sprintf('%s - %s', __('Unknown setting option'), __('Get technical help!'));
1247        }
1248
1249        return false;
1250    }
1251
1252    function updateSystemSettings($vars, &$errors) {
1253
1254        $f=array();
1255        $f['helpdesk_url']=array('type'=>'string',   'required'=>1, 'error'=>__('Helpdesk URL is required'));
1256        $f['helpdesk_title']=array('type'=>'string',   'required'=>1, 'error'=>__('Helpdesk title is required'));
1257        $f['default_dept_id']=array('type'=>'int',   'required'=>1, 'error'=>__('Default Department is required'));
1258        $f['autolock_minutes']=array('type'=>'int',   'required'=>1, 'error'=>__('Enter lock time in minutes'));
1259        $f['allow_iframes']=array('type'=>'cs-url',   'required'=>0, 'error'=>__('Enter comma separated list of urls'));
1260        $f['embedded_domain_whitelist']=array('type'=>'cs-domain',   'required'=>0, 'error'=>__('Enter comma separated list of domains'));
1261        $f['acl']=array('type'=>'ipaddr',   'required'=>0, 'error'=>__('Enter comma separated list of IP addresses'));
1262        //Date & Time Options
1263        $f['time_format']=array('type'=>'string',   'required'=>1, 'error'=>__('Time format is required'));
1264        $f['date_format']=array('type'=>'string',   'required'=>1, 'error'=>__('Date format is required'));
1265        $f['datetime_format']=array('type'=>'string',   'required'=>1, 'error'=>__('Datetime format is required'));
1266        $f['daydatetime_format']=array('type'=>'string',   'required'=>1, 'error'=>__('Day, Datetime format is required'));
1267        $f['default_timezone']=array('type'=>'string',   'required'=>1, 'error'=>__('Default Timezone is required'));
1268        $f['system_language']=array('type'=>'string',   'required'=>1, 'error'=>__('A primary system language is required'));
1269
1270        $vars = Format::htmlchars($vars, true);
1271
1272        // ACL Checks
1273        if ($vars['acl']) {
1274            // Check if Admin's IP is in the list, if not, return error
1275            // to avoid locking self out
1276            if (!in_array($vars['acl_backend'], array(0,2))) {
1277                $acl = explode(',', str_replace(' ', '', $vars['acl']));
1278                if (!in_array(osTicket::get_client_ip(), $acl))
1279                    $errors['acl'] = __('Cowardly refusing to lock out active administrator');
1280            }
1281        } elseif ((int) $vars['acl_backend'] !== 0)
1282            $errors['acl'] = __('IP address required when selecting panel');
1283
1284        // Make sure the selected backend is valid
1285        $storagebk = null;
1286        if (isset($vars['default_storage_bk'])) {
1287            try {
1288                $storagebk = FileStorageBackend::lookup($vars['default_storage_bk']);
1289
1290            } catch (Exception $ex) {
1291                $errors['default_storage_bk'] = $ex->getMessage();
1292            }
1293        }
1294
1295        if(!Validator::process($f, $vars, $errors) || $errors)
1296            return false;
1297
1298        // Manage secondard languages
1299        $vars['secondary_langs'][] = $vars['add_secondary_language'];
1300        foreach ($vars['secondary_langs'] as $i=>$lang) {
1301            if (!$lang || !Internationalization::isLanguageInstalled($lang))
1302                unset($vars['secondary_langs'][$i]);
1303        }
1304        $secondary_langs = implode(',', $vars['secondary_langs']);
1305
1306        if ($storagebk)
1307            $this->update('default_storage_bk', $storagebk->getBkChar());
1308
1309
1310        return $this->updateAll(array(
1311            'isonline'=>$vars['isonline'],
1312            'helpdesk_title'=>$vars['helpdesk_title'],
1313            'helpdesk_url'=>$vars['helpdesk_url'],
1314            'default_dept_id'=>$vars['default_dept_id'],
1315            'force_https'=>$vars['force_https'] ? 'on' : '',
1316            'max_page_size'=>$vars['max_page_size'],
1317            'log_level'=>$vars['log_level'],
1318            'log_graceperiod'=>$vars['log_graceperiod'],
1319            'time_format'=>$vars['time_format'],
1320            'date_format'=>$vars['date_format'],
1321            'datetime_format'=>$vars['datetime_format'],
1322            'daydatetime_format'=>$vars['daydatetime_format'],
1323            'date_formats'=>$vars['date_formats'],
1324            'default_timezone'=>$vars['default_timezone'],
1325            'schedule_id' => $vars['schedule_id'],
1326            'default_locale'=>$vars['default_locale'],
1327            'system_language'=>$vars['system_language'],
1328            'secondary_langs'=>$secondary_langs,
1329            'max_file_size' => $vars['max_file_size'],
1330            'autolock_minutes' => $vars['autolock_minutes'],
1331            'enable_avatars' => isset($vars['enable_avatars']) ? 1 : 0,
1332            'enable_richtext' => isset($vars['enable_richtext']) ? 1 : 0,
1333            'files_req_auth' => isset($vars['files_req_auth']) ? 1 : 0,
1334            'allow_iframes' => Format::sanitize($vars['allow_iframes']),
1335            'embedded_domain_whitelist' => Format::sanitize($vars['embedded_domain_whitelist']),
1336            'acl' => Format::sanitize($vars['acl']),
1337            'acl_backend' => Format::sanitize((int) $vars['acl_backend']) ?: 0,
1338        ));
1339    }
1340
1341    function updateAgentsSettings($vars, &$errors) {
1342        $f=array();
1343        $f['staff_session_timeout']=array('type'=>'int',   'required'=>1, 'error'=>'Enter idle time in minutes');
1344        $f['pw_reset_window']=array('type'=>'int', 'required'=>1, 'min'=>1,
1345            'error'=>__('Valid password reset window required'));
1346
1347        require_once INCLUDE_DIR.'class.avatar.php';
1348        list($avatar_source) = explode('.', $vars['agent_avatar']);
1349        if (!AvatarSource::lookup($avatar_source))
1350            $errors['agent_avatar'] = __('Select a value from the list');
1351
1352        if(!Validator::process($f, $vars, $errors) || $errors)
1353            return false;
1354
1355        return $this->updateAll(array(
1356            'agent_passwd_policy'=>$vars['agent_passwd_policy'],
1357            'staff_max_logins'=>$vars['staff_max_logins'],
1358            'staff_login_timeout'=>$vars['staff_login_timeout'],
1359            'staff_session_timeout'=>$vars['staff_session_timeout'],
1360            'staff_ip_binding'=>isset($vars['staff_ip_binding'])?1:0,
1361            'allow_pw_reset'=>isset($vars['allow_pw_reset'])?1:0,
1362            'pw_reset_window'=>$vars['pw_reset_window'],
1363            'require_agent_2fa'=> isset($vars['require_agent_2fa']) ? 1 : 0,
1364            'agent_name_format'=>$vars['agent_name_format'],
1365            'hide_staff_name'=>isset($vars['hide_staff_name']) ? 1 : 0,
1366            'agent_avatar'=>$vars['agent_avatar'],
1367            'disable_agent_collabs'=>isset($vars['disable_agent_collabs'])?1:0,
1368        ));
1369    }
1370
1371    function updateUsersSettings($vars, &$errors) {
1372        $f=array();
1373        $f['client_session_timeout']=array('type'=>'int',   'required'=>1, 'error'=>'Enter idle time in minutes');
1374
1375        require_once INCLUDE_DIR.'class.avatar.php';
1376        list($avatar_source) = explode('.', $vars['client_avatar']);
1377        if (!AvatarSource::lookup($avatar_source))
1378            $errors['client_avatar'] = __('Select a value from the list');
1379
1380        if(!Validator::process($f, $vars, $errors) || $errors)
1381            return false;
1382
1383        return $this->updateAll(array(
1384            'client_passwd_policy'=>$vars['client_passwd_policy'],
1385            'client_max_logins'=>$vars['client_max_logins'],
1386            'client_login_timeout'=>$vars['client_login_timeout'],
1387            'client_session_timeout'=>$vars['client_session_timeout'],
1388            'clients_only'=>isset($vars['clients_only'])?1:0,
1389            'client_registration'=>$vars['client_registration'],
1390            'client_verify_email'=>isset($vars['client_verify_email'])?1:0,
1391            'allow_auth_tokens' => isset($vars['allow_auth_tokens']) ? 1 : 0,
1392            'client_name_format'=>$vars['client_name_format'],
1393            'client_avatar'=>$vars['client_avatar'],
1394        ));
1395    }
1396
1397    function updateTicketsSettings($vars, &$errors) {
1398        $f=array();
1399        $f['default_sla_id']=array('type'=>'int',   'required'=>1, 'error'=>__('Selection required'));
1400        $f['default_ticket_status_id'] = array('type'=>'int', 'required'=>1, 'error'=>__('Selection required'));
1401        $f['default_priority_id']=array('type'=>'int',   'required'=>1, 'error'=>__('Selection required'));
1402        $f['max_open_tickets']=array('type'=>'int',   'required'=>1, 'error'=>__('Enter valid numeric value'));
1403
1404
1405        if($vars['enable_captcha']) {
1406            if (!extension_loaded('gd'))
1407                $errors['enable_captcha']=__('The GD extension is required');
1408            elseif(!function_exists('imagepng'))
1409                $errors['enable_captcha']=__('PNG support is required for Image Captcha');
1410        }
1411
1412        if ($vars['default_help_topic']
1413                && ($T = Topic::lookup($vars['default_help_topic']))
1414                && !$T->isActive()) {
1415            $errors['default_help_topic'] = __('Default help topic must be set to active');
1416        }
1417
1418        if (!preg_match('`(?!<\\\)#`', $vars['ticket_number_format']))
1419            $errors['ticket_number_format'] = 'Ticket number format requires at least one hash character (#)';
1420
1421        if (!isset($vars['default_ticket_queue']))
1422            $errors['default_ticket_queue'] = __("Select a default ticket queue");
1423        elseif (!CustomQueue::lookup($vars['default_ticket_queue']))
1424            $errors['default_ticket_queue'] = __("Select a default ticket queue");
1425
1426        $this->updateAutoresponderSettings($vars, $errors);
1427        $this->updateAlertsSettings($vars, $errors);
1428
1429        if(!Validator::process($f, $vars, $errors) || $errors)
1430            return false;
1431
1432        // Sort ticket queues
1433        $queues = CustomQueue::queues()->getIterator();
1434        foreach ($vars['qsort'] as $queue_id => $sort) {
1435            if ($q = $queues->findFirst(array('id' => $queue_id))) {
1436                $q->sort = $sort;
1437                $q->save();
1438            }
1439        }
1440
1441        return $this->updateAll(array(
1442            'ticket_number_format'=>$vars['ticket_number_format'] ?: '######',
1443            'ticket_sequence_id'=>$vars['ticket_sequence_id'] ?: 0,
1444            'queue_bucket_counts'=>isset($vars['queue_bucket_counts'])?1:0,
1445            'default_priority_id'=>$vars['default_priority_id'],
1446            'default_help_topic'=>$vars['default_help_topic'],
1447            'default_ticket_status_id'=>$vars['default_ticket_status_id'],
1448            'default_sla_id'=>$vars['default_sla_id'],
1449            'max_open_tickets'=>$vars['max_open_tickets'],
1450            'enable_captcha'=>isset($vars['enable_captcha'])?1:0,
1451            'auto_claim_tickets'=>isset($vars['auto_claim_tickets'])?1:0,
1452            'auto_refer_closed' => isset($vars['auto_refer_closed']) ? 1 : 0,
1453            'collaborator_ticket_visibility'=>isset($vars['collaborator_ticket_visibility'])?1:0,
1454            'require_topic_to_close'=>isset($vars['require_topic_to_close'])?1:0,
1455            'show_related_tickets'=>isset($vars['show_related_tickets'])?1:0,
1456            'allow_client_updates'=>isset($vars['allow_client_updates'])?1:0,
1457            'ticket_lock' => $vars['ticket_lock'],
1458            'default_ticket_queue'=>$vars['default_ticket_queue'],
1459            'allow_external_images'=>isset($vars['allow_external_images'])?1:0,
1460        ));
1461    }
1462
1463    function updateTasksSettings($vars, &$errors) {
1464        $f=array();
1465        $f['default_task_priority_id']=array('type'=>'int',   'required'=>1, 'error'=>__('Selection required'));
1466
1467        if (!preg_match('`(?!<\\\)#`', $vars['task_number_format']))
1468            $errors['task_number_format'] = 'Task number format requires at least one hash character (#)';
1469
1470        Validator::process($f, $vars, $errors);
1471
1472        if ($vars['task_alert_active']
1473                && (!isset($vars['task_alert_admin'])
1474                    && !isset($vars['task_alert_dept_manager'])
1475                    && !isset($vars['task_alert_dept_members'])
1476                    && !isset($vars['task_alert_acct_manager']))) {
1477            $errors['task_alert_active'] = __('Select recipient(s)');
1478        }
1479
1480        if ($vars['task_activity_alert_active']
1481                && (!isset($vars['task_activity_alert_laststaff'])
1482                    && !isset($vars['task_activity_alert_assigned'])
1483                    && !isset($vars['task_activity_alert_dept_manager']))) {
1484            $errors['task_activity_alert_active'] = __('Select recipient(s)');
1485        }
1486
1487        if ($vars['task_transfer_alert_active']
1488                && (!isset($vars['task_transfer_alert_assigned'])
1489                    && !isset($vars['task_transfer_alert_dept_manager'])
1490                    && !isset($vars['task_transfer_alert_dept_members']))) {
1491            $errors['task_transfer_alert_active'] = __('Select recipient(s)');
1492        }
1493
1494        if ($vars['task_overdue_alert_active']
1495                && (!isset($vars['task_overdue_alert_assigned'])
1496                    && !isset($vars['task_overdue_alert_dept_manager'])
1497                    && !isset($vars['task_overdue_alert_dept_members']))) {
1498            $errors['task_overdue_alert_active'] = __('Select recipient(s)');
1499        }
1500
1501        if ($vars['task_assignment_alert_active']
1502                && (!isset($vars['task_assignment_alert_staff'])
1503                    && !isset($vars['task_assignment_alert_team_lead'])
1504                    && !isset($vars['task_assignment_alert_team_members']))) {
1505            $errors['task_assignment_alert_active'] = __('Select recipient(s)');
1506        }
1507
1508        if ($errors)
1509            return false;
1510
1511        return $this->updateAll(array(
1512            'task_number_format'=>$vars['task_number_format'] ?: '######',
1513            'task_sequence_id'=>$vars['task_sequence_id'] ?: 0,
1514            'default_task_priority_id'=>$vars['default_task_priority_id'],
1515            'default_task_sla_id'=>$vars['default_task_sla_id'],
1516            'task_alert_active'=>$vars['task_alert_active'],
1517            'task_alert_admin'=>isset($vars['task_alert_admin']) ? 1 : 0,
1518            'task_alert_dept_manager'=>isset($vars['task_alert_dept_manager']) ? 1 : 0,
1519            'task_alert_dept_members'=>isset($vars['task_alert_dept_members']) ? 1 : 0,
1520            'task_activity_alert_active'=>$vars['task_activity_alert_active'],
1521            'task_activity_alert_laststaff'=>isset($vars['task_activity_alert_laststaff']) ? 1 : 0,
1522            'task_activity_alert_assigned'=>isset($vars['task_activity_alert_assigned']) ? 1 : 0,
1523            'task_activity_alert_dept_manager'=>isset($vars['task_activity_alert_dept_manager']) ? 1 : 0,
1524            'task_assignment_alert_active'=>$vars['task_assignment_alert_active'],
1525            'task_assignment_alert_staff'=>isset($vars['task_assignment_alert_staff']) ? 1 : 0,
1526            'task_assignment_alert_team_lead'=>isset($vars['task_assignment_alert_team_lead']) ? 1 : 0,
1527            'task_assignment_alert_team_members'=>isset($vars['task_assignment_alert_team_members']) ? 1 : 0,
1528            'task_transfer_alert_active'=>$vars['task_transfer_alert_active'],
1529            'task_transfer_alert_assigned'=>isset($vars['task_transfer_alert_assigned']) ? 1 : 0,
1530            'task_transfer_alert_dept_manager'=>isset($vars['task_transfer_alert_dept_manager']) ? 1 : 0,
1531            'task_transfer_alert_dept_members'=>isset($vars['task_transfer_alert_dept_members']) ? 1 : 0,
1532            'task_overdue_alert_active'=>$vars['task_overdue_alert_active'],
1533            'task_overdue_alert_assigned'=>isset($vars['task_overdue_alert_assigned']) ? 1 : 0,
1534            'task_overdue_alert_dept_manager'=>isset($vars['task_overdue_alert_dept_manager']) ? 1 : 0,
1535            'task_overdue_alert_dept_members'=>isset($vars['task_overdue_alert_dept_members']) ? 1 : 0,
1536        ));
1537    }
1538
1539    function updateEmailsSettings($vars, &$errors) {
1540        $f=array();
1541        $f['default_template_id']=array('type'=>'int',   'required'=>1, 'error'=>__('You must select template'));
1542        $f['default_email_id']=array('type'=>'int',   'required'=>1, 'error'=>__('Default email is required'));
1543        $f['alert_email_id']=array('type'=>'int',   'required'=>1, 'error'=>__('Selection required'));
1544        $f['admin_email']=array('type'=>'email',   'required'=>1, 'error'=>__('System admin email is required'));
1545
1546        if($vars['strip_quoted_reply'] && !trim($vars['reply_separator']))
1547            $errors['reply_separator']=__('Reply separator is required to strip quoted reply.');
1548
1549        if($vars['admin_email'] && Email::getIdByEmail($vars['admin_email'])) //Make sure admin email is not also a system email.
1550            $errors['admin_email']=__('Email already setup as system email');
1551
1552        if(!Validator::process($f,$vars,$errors) || $errors)
1553            return false;
1554
1555        return $this->updateAll(array(
1556            'default_template_id'=>$vars['default_template_id'],
1557            'default_email_id'=>$vars['default_email_id'],
1558            'alert_email_id'=>$vars['alert_email_id'],
1559            'default_smtp_id'=>$vars['default_smtp_id'],
1560            'admin_email'=>$vars['admin_email'],
1561            'verify_email_addrs'=>isset($vars['verify_email_addrs']) ? 1 : 0,
1562            'enable_auto_cron'=>isset($vars['enable_auto_cron'])?1:0,
1563            'enable_mail_polling'=>isset($vars['enable_mail_polling'])?1:0,
1564            'strip_quoted_reply'=>isset($vars['strip_quoted_reply'])?1:0,
1565            'use_email_priority'=>isset($vars['use_email_priority'])?1:0,
1566            'accept_unregistered_email'=>isset($vars['accept_unregistered_email'])?1:0,
1567            'add_email_collabs'=>isset($vars['add_email_collabs'])?1:0,
1568            'reply_separator'=>$vars['reply_separator'],
1569            'email_attachments'=>isset($vars['email_attachments'])?1:0,
1570         ));
1571    }
1572
1573    function getLogo($site) {
1574        $id = $this->get("{$site}_logo_id", false);
1575        return ($id) ? AttachmentFile::lookup((int) $id) : null;
1576    }
1577    function getClientLogo() {
1578        return $this->getLogo('client');
1579    }
1580    function getLogoId($site) {
1581        return $this->get("{$site}_logo_id", false);
1582    }
1583    function getClientLogoId() {
1584        return $this->getLogoId('client');
1585    }
1586
1587    function getStaffLogoId() {
1588        return $this->getLogoId('staff');
1589    }
1590    function getStaffLogo() {
1591        return $this->getLogo('staff');
1592    }
1593
1594    function getStaffLoginBackdropId() {
1595        return $this->get("staff_backdrop_id", false);
1596    }
1597    function getStaffLoginBackdrop() {
1598        $id = $this->getStaffLoginBackdropId();
1599        return ($id) ? AttachmentFile::lookup((int) $id) : null;
1600    }
1601
1602    function isAuthRequiredForFiles() {
1603        return $this->get('files_req_auth');
1604    }
1605
1606    function updatePagesSettings($vars, &$errors) {
1607        global $ost;
1608
1609        $f=array();
1610        $f['landing_page_id'] = array('type'=>'int',   'required'=>1, 'error'=>'required');
1611        $f['offline_page_id'] = array('type'=>'int',   'required'=>1, 'error'=>'required');
1612        $f['thank-you_page_id'] = array('type'=>'int',   'required'=>1, 'error'=>'required');
1613
1614        if ($_FILES['logo']) {
1615            $error = false;
1616            list($logo) = AttachmentFile::format($_FILES['logo']);
1617            if (!$logo)
1618                ; // Pass
1619            elseif ($logo['error'])
1620                $errors['logo'] = $logo['error'];
1621            elseif (!AttachmentFile::uploadLogo($logo, $error))
1622                $errors['logo'] = sprintf(__('Unable to upload logo image: %s'), $error);
1623        }
1624
1625        if ($_FILES['backdrop']) {
1626            $error = false;
1627            list($backdrop) = AttachmentFile::format($_FILES['backdrop']);
1628            if (!$backdrop)
1629                ; // Pass
1630            elseif ($backdrop['error'])
1631                $errors['backdrop'] = $backdrop['error'];
1632            elseif (!AttachmentFile::uploadBackdrop($backdrop, $error))
1633                $errors['backdrop'] = sprintf(__('Unable to upload backdrop image: %s'), $error);
1634        }
1635
1636        $company = $ost->company;
1637        $company_form = $company->getForm();
1638        $company_form->setSource($_POST);
1639        if (!$company_form->isValid())
1640            $errors += $company_form->errors();
1641
1642        if(!Validator::process($f, $vars, $errors) || $errors)
1643            return false;
1644
1645        $company_form->save();
1646
1647        if (isset($vars['delete-logo']))
1648            foreach ($vars['delete-logo'] as $id)
1649                if (($vars['selected-logo'] != $id)
1650                        && ($f = AttachmentFile::lookup((int) $id)))
1651                    $f->delete();
1652
1653        if (isset($vars['delete-backdrop']))
1654            foreach ($vars['delete-backdrop'] as $id)
1655                if (($vars['selected-backdrop'] != $id)
1656                        && ($f = AttachmentFile::lookup((int) $id)))
1657                    $f->delete();
1658
1659        return $this->updateAll(array(
1660            'landing_page_id' => $vars['landing_page_id'],
1661            'offline_page_id' => $vars['offline_page_id'],
1662            'thank-you_page_id' => $vars['thank-you_page_id'],
1663            'client_logo_id' => (
1664                (is_numeric($vars['selected-logo']) && $vars['selected-logo'])
1665                ? $vars['selected-logo'] : false),
1666            'staff_logo_id' => (
1667                (is_numeric($vars['selected-logo-scp']) && $vars['selected-logo-scp'])
1668                ? $vars['selected-logo-scp'] : false),
1669            'staff_backdrop_id' => (
1670                (is_numeric($vars['selected-backdrop']) && $vars['selected-backdrop'])
1671                ? $vars['selected-backdrop'] : false),
1672           ));
1673    }
1674
1675    function updateAutoresponderSettings($vars, &$errors) {
1676
1677        if($errors) return false;
1678
1679        return $this->updateAll(array(
1680            'ticket_autoresponder'=>isset($vars['ticket_autoresponder']) ? 1 : 0,
1681            'message_autoresponder'=>isset($vars['message_autoresponder']) ? 1 : 0,
1682            'message_autoresponder_collabs'=>isset($vars['message_autoresponder_collabs']) ? 1 : 0,
1683            'ticket_notice_active'=>isset($vars['ticket_notice_active']) ? 1 : 0,
1684            'overlimit_notice_active'=>isset($vars['overlimit_notice_active']) ? 1 : 0,
1685        ));
1686    }
1687
1688
1689    function updateKBSettings($vars, &$errors) {
1690        if ($errors) return false;
1691
1692        return $this->updateAll(array(
1693            'enable_kb'=>isset($vars['enable_kb'])?1:0,
1694            'restrict_kb'=>isset($vars['restrict_kb'])?1:0,
1695            'enable_premade'=>isset($vars['enable_premade'])?1:0,
1696        ));
1697    }
1698
1699
1700    function updateAlertsSettings($vars, &$errors) {
1701
1702       if($vars['ticket_alert_active']
1703                && (!isset($vars['ticket_alert_admin'])
1704                    && !isset($vars['ticket_alert_dept_manager'])
1705                    && !isset($vars['ticket_alert_dept_members'])
1706                    && !isset($vars['ticket_alert_acct_manager']))) {
1707            $errors['ticket_alert_active']=__('Select recipient(s)');
1708        }
1709        if($vars['message_alert_active']
1710                && (!isset($vars['message_alert_laststaff'])
1711                    && !isset($vars['message_alert_assigned'])
1712                    && !isset($vars['message_alert_dept_manager'])
1713                    && !isset($vars['message_alert_acct_manager']))) {
1714            $errors['message_alert_active']=__('Select recipient(s)');
1715        }
1716
1717        if($vars['note_alert_active']
1718                && (!isset($vars['note_alert_laststaff'])
1719                    && !isset($vars['note_alert_assigned'])
1720                    && !isset($vars['note_alert_dept_manager']))) {
1721            $errors['note_alert_active']=__('Select recipient(s)');
1722        }
1723
1724        if($vars['transfer_alert_active']
1725                && (!isset($vars['transfer_alert_assigned'])
1726                    && !isset($vars['transfer_alert_dept_manager'])
1727                    && !isset($vars['transfer_alert_dept_members']))) {
1728            $errors['transfer_alert_active']=__('Select recipient(s)');
1729        }
1730
1731        if($vars['overdue_alert_active']
1732                && (!isset($vars['overdue_alert_assigned'])
1733                    && !isset($vars['overdue_alert_dept_manager'])
1734                    && !isset($vars['overdue_alert_dept_members']))) {
1735            $errors['overdue_alert_active']=__('Select recipient(s)');
1736        }
1737
1738        if($vars['assigned_alert_active']
1739                && (!isset($vars['assigned_alert_staff'])
1740                    && !isset($vars['assigned_alert_team_lead'])
1741                    && !isset($vars['assigned_alert_team_members']))) {
1742            $errors['assigned_alert_active']=__('Select recipient(s)');
1743        }
1744
1745        if($errors) return false;
1746
1747        return $this->updateAll(array(
1748            'ticket_alert_active'=>$vars['ticket_alert_active'],
1749            'ticket_alert_admin'=>isset($vars['ticket_alert_admin'])?1:0,
1750            'ticket_alert_dept_manager'=>isset($vars['ticket_alert_dept_manager'])?1:0,
1751            'ticket_alert_dept_members'=>isset($vars['ticket_alert_dept_members'])?1:0,
1752            'ticket_alert_acct_manager'=>isset($vars['ticket_alert_acct_manager'])?1:0,
1753            'message_alert_active'=>$vars['message_alert_active'],
1754            'message_alert_laststaff'=>isset($vars['message_alert_laststaff'])?1:0,
1755            'message_alert_assigned'=>isset($vars['message_alert_assigned'])?1:0,
1756            'message_alert_dept_manager'=>isset($vars['message_alert_dept_manager'])?1:0,
1757            'message_alert_acct_manager'=>isset($vars['message_alert_acct_manager'])?1:0,
1758            'note_alert_active'=>$vars['note_alert_active'],
1759            'note_alert_laststaff'=>isset($vars['note_alert_laststaff'])?1:0,
1760            'note_alert_assigned'=>isset($vars['note_alert_assigned'])?1:0,
1761            'note_alert_dept_manager'=>isset($vars['note_alert_dept_manager'])?1:0,
1762            'assigned_alert_active'=>$vars['assigned_alert_active'],
1763            'assigned_alert_staff'=>isset($vars['assigned_alert_staff'])?1:0,
1764            'assigned_alert_team_lead'=>isset($vars['assigned_alert_team_lead'])?1:0,
1765            'assigned_alert_team_members'=>isset($vars['assigned_alert_team_members'])?1:0,
1766            'transfer_alert_active'=>$vars['transfer_alert_active'],
1767            'transfer_alert_assigned'=>isset($vars['transfer_alert_assigned'])?1:0,
1768            'transfer_alert_dept_manager'=>isset($vars['transfer_alert_dept_manager'])?1:0,
1769            'transfer_alert_dept_members'=>isset($vars['transfer_alert_dept_members'])?1:0,
1770            'overdue_alert_active'=>$vars['overdue_alert_active'],
1771            'overdue_alert_assigned'=>isset($vars['overdue_alert_assigned'])?1:0,
1772            'overdue_alert_dept_manager'=>isset($vars['overdue_alert_dept_manager'])?1:0,
1773            'overdue_alert_dept_members'=>isset($vars['overdue_alert_dept_members'])?1:0,
1774            'send_sys_errors'=>isset($vars['send_sys_errors'])?1:0,
1775            'send_sql_errors'=>isset($vars['send_sql_errors'])?1:0,
1776            'send_login_errors'=>isset($vars['send_login_errors'])?1:0,
1777        ));
1778    }
1779
1780    //Used to detect version prior to 1.7 (useful during upgrade)
1781    /* static */ function getDBVersion() {
1782        $sql='SELECT `ostversion` FROM '.TABLE_PREFIX.'config '
1783            .'WHERE id=1';
1784        return db_result(db_query($sql));
1785    }
1786}
1787?>
1788