1<?php
2/**
3 * Copyright 2012-2017 Horde LLC (http://www.horde.org/)
4 *
5 * See the enclosed file LICENSE for license information (ASL).  If you
6 * did not receive this file, see http://www.horde.org/licenses/apache.
7 *
8 * @author  Michael Bunk <mb@computer-leipzig.com>
9 * @author  Jan Schneider <jan@horde.org>
10 * @package Ingo
11 */
12
13/**
14 * Ingo_Transport_Ispconfig implements an Ingo transport driver to allow
15 * scripts to be installed and set active on an ISPConfig server.
16 *
17 * Ingo_Transport_
18 *
19 * @author  Michael Bunk <mb@computer-leipzig.com>
20 * @author  Jan Schneider <jan@horde.org>
21 * @package Ingo
22 */
23class Ingo_Transport_Ispconfig extends Ingo_Transport_Base
24{
25    /**
26     * The SOAP connection
27     *
28     * @var SoapClient
29     */
30    protected $_soap;
31
32    /**
33     * The SOAP session id
34     *
35     * @var string
36     */
37    protected $_soap_session;
38
39    /**
40     * The current vacation details.
41     *
42     * @var array
43     */
44    protected $_details = null;
45
46
47    /**
48     * Sets a script running on the backend.
49     *
50     * @param array $script  The filter script information. Passed elements:
51     *                       - 'name': (string) the script name.
52     *                       - 'recipes': (array) the filter recipe objects.
53     *                       - 'script': (string) the filter script.
54     *
55     * @throws Ingo_Exception
56     */
57    public function setScriptActive($script)
58    {
59        $vacation = null;
60        foreach ($script['recipes'] as $recipe) {
61            if ($recipe['rule'] == Ingo::RULE_VACATION) {
62                $vacation = $recipe['object']->vacation;
63                break;
64            } else {
65                throw new Ingo_Exception('The ISPConfig transport driver only supports vacation rules.');
66            }
67        }
68
69        if (!$vacation) {
70            return;
71        }
72
73        // Fill mailuser_id and client_id.
74        $this->_getUserDetails($this->_params['password']);
75
76        try {
77            $user = $this->_soap->mail_user_get(
78                $this->_soap_session, $this->_details['mailuser_id']);
79
80            $user['autoresponder'] = $recipe['object']->disable ? 'n' : 'y';
81            // UNIX timestamp.
82            $start = $vacation->getVacationStart();
83            $end = $vacation->getVacationEnd();
84            if (empty($start)) {
85                $start = time();
86            }
87            if (empty($end)) {
88                $end = time();
89            }
90            $user['autoresponder_start_date'] = array(
91                'year' => date('Y', $start),
92                'month' => date('m', $start),
93                'day' => date('d', $start),
94                'hour' => date('H', $start),
95                'minute' => date('i', $start));
96            $user['autoresponder_end_date'] = array(
97                'year' => date('Y', $end),
98                'month' => date('m', $end),
99                'day' => date('d', $end),
100                'hour' => 23,
101                'minute' => 59);
102            // $vacation->getVacationSubject() not supported by ISPConfig
103            $user['autoresponder_text'] = $vacation->getVacationReason();
104            // otherwise ISPConfig calculates the hash of this hash... braindead
105            unset($user['password']);
106
107            $this->_soap->mail_user_update(
108                $this->_soap_session, $this->_details['client_id'],
109                $this->_details['mailuser_id'], $user);
110        } catch (SoapFault $e) {
111            throw new Ingo_Exception($e);
112        }
113    }
114
115    /**
116     * Retrieves the current vacation details for the user.
117     *
118     * @param string $password  The password for user.
119     *
120     * @return array  Vacation details
121     * @throws Ingo_Exception
122     */
123    protected function _getUserDetails($password)
124    {
125        if (!is_null($this->_details)) {
126            return $this->_details;
127        }
128
129        $this->_checkConfig();
130        $this->_connect();
131
132        try {
133            $users = $this->_soap->mail_user_get(
134                $this->_soap_session,
135                array('login' => $this->_params['username']));
136        } catch (SoapFault $e) {
137            throw new Ingo_Exception($e);
138        }
139        if (count($users) != 1) {
140            throw new Ingo_Exception(
141                sprintf(_("%d users with login %s found, one expected."),
142                        count($users),
143                        $this->_params['username']));
144        }
145
146        $user = $users[0];
147        $this->_details['vacation'] =
148            ($user['autoresponder'] === 'y') ? 'Y' : 'N';
149        $this->_details['message'] = $user['autoresponder_text'];
150        $this->_details['mailuser_id'] = $user['mailuser_id'];
151        // 0 == admin
152        $this->_details['client_id'] = 0;
153        $this->_details['autoresponder_start_date'] =
154            $user['autoresponder_start_date'];
155        $this->_details['autoresponder_end_date'] =
156            $user['autoresponder_end_date'];
157        return $this->_details;
158    }
159
160    /**
161     * Checks if the realm has a specific configuration. If not, tries to fall
162     * back on the default configuration. If still not a valid configuration
163     * then returns an exception.
164     *
165     * @throws Ingo_Exception
166     */
167    protected function _checkConfig()
168    {
169        if (empty($this->_params['soap_uri']) ||
170            empty($this->_params['soap_user']) ) {
171            throw new Ingo_Exception('The Ingo Ispconfig transport is not properly configured, edit your ingo/config/backends.local.php.');
172        }
173    }
174
175    /**
176     * Connects to the SOAP server.
177     *
178     * @throws Ingo_Exception
179     */
180    protected function _connect()
181    {
182        if ($this->_soap) {
183            return;
184        }
185
186        $soap_uri = $this->_params['soap_uri'];
187        $client = new SoapClient(null, array(
188            'location' => $soap_uri . 'index.php',
189            'uri'      => $soap_uri));
190
191        try {
192            if (!$session_id = $client->login(
193                $this->_params['soap_user'],
194                $this->_params['soap_pass'])) {
195                throw new Ingo_Exception(
196                    sprintf(_("Login to %s failed."), $soap_uri));
197            }
198        } catch (SoapFault $e) {
199            throw new Ingo_Exception($e);
200        }
201
202        $this->_soap = &$client;
203        $this->_soap_session = $session_id;
204    }
205}
206