This file is indexed.

/usr/share/php/Horde/SyncMl/Command/Sync.php is in php-horde-syncml 2.0.7-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
<?php
/**
 * The Horde_SyncMl_Command_Sync class provides a SyncML implementation of the
 * Sync command as defined in SyncML Representation Protocol, version 1.1,
 * section 5.5.15.
 *
 * The Sync command is used to indicate a data synchronization operation. The
 * command handler for the Sync command is the central class to dispatch sync
 * messages.
 *
 * During parsing of the received XML, the actual sync commands (Add, Replace,
 * Delete) from the client are stored in the $_syncElements attribute.  When
 * the output method of Horde_SyncMl_Command_Sync is called, these elements are
 * processed and the resulting status messages created.  Then the server
 * modifications are sent back to the client by the handleSync() method which
 * is called from within the output method.
 *
 * Copyright 2005-2016 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.horde.org/licenses/lgpl21.
 *
 * @author  Karsten Fourmont <karsten@horde.org>
 * @author  Jan Schneider <jan@horde.org>
 * @package SyncMl
 */
class Horde_SyncMl_Command_Sync extends Horde_SyncMl_Command
{
    /**
     * Name of the command.
     *
     * @var string
     */
    protected $_cmdName = 'Sync';

    /**
     * Source database of the <Sync> command.
     *
     * @var string
     */
    protected $_sourceURI;

    /**
     * Target database of the <Sync> command.
     *
     * @var string
     */
    protected $_targetURI;

    /**
     * Horde_SyncMl_SyncElement object for the currently parsed sync command.
     *
     * @var Horde_SyncMl_SyncElement
     */
    protected $_curItem;

    /**
     * List of all Horde_SyncMl_SyncElement objects that have parsed.
     *
     * @var array
     */
    protected $_syncElements = array();

    /**
     * The MIME content type of the currently parsed sync command as specified
     * by the <Type> element inside a <Meta> section.
     *
     * @var string
     */
    protected $_contentType = 'text/plain';

    /**
     * Encoding format of the content as specified in the <Meta><Format>
     * element, like 'b64'.
     *
     * @var string
     */
    protected $_contentFormat = 'chr';

    /**
     * The command ID (<CmdID>) of the currently parsed sync command.
     *
     * This is different from the command ID of the <Sync> command itself.
     *
     * @var integer
     */
    protected $_itemCmdID;

    /**
     * Name of the currently parsed sync command, like 'Add'.
     *
     * @var string
     */
    protected $_elementType;

    /**
     * Whether a <MoreData> element has indicated that the sync command is
     * split into several SyncML message chunks.
     *
     * @var boolean
     */
    protected $_itemMoreData;

    /**
     * The size of the data item of the currently parsed sync command in bytes
     * as specified by a <Size> element.
     *
     * @var integer
     */
    protected $_itemSize;

    /**
     * Start element handler for the XML parser, delegated from
     * Horde_SyncMl_ContentHandler::startElement().
     *
     * @param string $uri      The namespace URI of the element.
     * @param string $element  The element tag name.
     * @param array $attrs     A hash with the element's attributes.
     */
    public function startElement($uri, $element, $attrs)
    {
        parent::startElement($uri, $element, $attrs);
        $state = $GLOBALS['backend']->state;

        switch (count($this->_stack)) {
        case 2:
            if ($element == 'Replace' ||
                $element == 'Add' ||
                $element == 'Delete') {
                $this->_contentType = 'text/plain';
                $this->_elementType = $element;
                $this->_itemSize = null;
            }
            break;

        case 3:
            if ($element == 'Item') {
                if (isset($state->curSyncItem)) {
                    // Copy from state in case of <MoreData>.
                    $this->_curItem = $state->curSyncItem;
                    // Set CmdID to the current CmdId, not the initial one
                    // from the first message.
                    $this->_curItem->cmdID = $this->_itemCmdID;
                } else {
                    $this->_curItem = new Horde_SyncMl_SyncElement(
                        $state->getSync($this->_targetURI),
                        $this->_elementType,
                        $this->_itemCmdID,
                        $this->_itemSize);
                }
                $this->_itemMoreData = false;
            }
        }
    }

    /**
     * End element handler for the XML parser, delegated from
     * Horde_SyncMl_ContentHandler::endElement().
     *
     * @param string $uri      The namespace URI of the element.
     * @param string $element  The element tag name.
     */
    public function endElement($uri, $element)
    {
        switch (count($this->_stack)) {
        case 3:
            switch ($element) {
            case 'LocURI':
                if (!isset($this->_currentSyncElement)) {
                    if ($this->_stack[1] == 'Source') {
                        $this->_sourceURI = trim($this->_chars);
                    } elseif ($this->_stack[1] == 'Target') {
                        $this->_targetURI = trim($this->_chars);
                    }
                }
                break;

            case 'Item':
                if ($this->_itemMoreData) {
                    // Store to continue in next session.
                    $GLOBALS['backend']->state->curSyncItem = $this->_curItem;
                } else {
                    // Finished. Store to syncElements[].
                    if (empty($this->_curItem->contentType)) {
                        $this->_curItem->contentType = $this->_contentType;
                    }
                    if (empty($this->_curItem->contentFormat)) {
                        $this->_curItem->contentFormat = $this->_contentFormat;
                    }

                    $this->_syncElements[] = $this->_curItem;
                    // @todo: check if size matches strlen(content) when
                    // size>0, esp. in case of <MoreData>.

                    // Unset the saved state item if it was not unset in
                    // endElement().
                    if (isset($GLOBALS['backend']->state->curSyncItem)) {
                        unset($GLOBALS['backend']->state->curSyncItem);
                    }

                    unset($this->_curItem);
                }
                break;

            case 'CmdID':
                $this->_itemCmdID = trim($this->_chars);
                break;
            }
            break;

        case 4:
            switch ($element) {
            case 'Format':
                if ($this->_stack[2] == 'Meta') {
                    $this->_contentFormat = trim($this->_chars);
                }
                break;
            case 'Type':
                if ($this->_stack[2] == 'Meta') {
                    $this->_contentType = trim($this->_chars);
                }
                break;
            case 'Data':
                // Trim only if we had a MoreData tag before to not corrupt
                // pictures.
                if (isset($GLOBALS['backend']->state->curSyncItem)) {
                    $this->_curItem->content .= ltrim($this->_chars);
                    unset($GLOBALS['backend']->state->curSyncItem);
                } else {
                    // Don't trim, because we have to check the raw content's
                    // size.
                    $this->_curItem->content .= $this->_chars;
                }
                break;
            case 'MoreData':
                $this->_itemMoreData = true;
                break;
            case 'Size':
                $this->_itemSize = $this->_chars;
                break;
            }
            break;

        case 5:
            switch ($element) {
            case 'LocURI':
                if ($this->_stack[3] == 'Source') {
                    $this->_curItem->cuid = trim($this->_chars);
                } elseif ($this->_stack[3] == 'Target') {
                    // Not used: we ignore "suid proposals" from client.
                }
                break;

            case 'Format':
                if ($this->_stack[3] == 'Meta') {
                    $this->_curItem->contentFormat = trim($this->_chars);
                }
                break;

            case 'Type':
                $this->_curItem->contentType = trim($this->_chars);
                break;
            }
            break;

        case 6:
            if ($element == 'Type') {
                $this->_curItem->contentType = trim($this->_chars);
            }
            break;
        }

        parent::endElement($uri, $element);
    }

    /**
     * Implements the actual business logic of the Sync command.
     */
    public function handleCommand($debug = false)
    {
        $state = $GLOBALS['backend']->state;

        // Handle unauthenticated first.
        if (!$state->authenticated) {
            $this->_outputHandler->outputStatus($this->_cmdID, $this->_cmdName,
                                                Horde_SyncMl::RESPONSE_INVALID_CREDENTIALS);
            return;
        }

        if ($debug) {
            $sync = &$state->getSync($this->_targetURI);
            $sync = new Horde_SyncMl_Sync(Horde_SyncMl::ALERT_TWO_WAY,
                                    $this->_targetURI,
                                    $this->_sourceURI,
                                    0, 0, 0);
        } else {
            $sync = &$state->getSync($this->_targetURI);
            $sync->addSyncReceived();

            if (!is_object($sync)) {
                $GLOBALS['backend']->logMessage(
                    'No sync object found for URI ' . $this->_targetURI, 'ERR');
                // @todo: create meaningful status code here.
            }
        }

        /* @todo: Check: do we send a status for every sync or only once after
         * one sync is completed?
         * SE K750 expects Status response to be sent before Sync output
         * by server is produced. */
        $this->_outputHandler->outputStatus($this->_cmdID, $this->_cmdName,
                                            Horde_SyncMl::RESPONSE_OK,
                                            $this->_targetURI,
                                            $this->_sourceURI);

        // Here's where client modifications are processed.
        $device = $state->getDevice();
        $omit = $device->omitIndividualSyncStatus();
        foreach ($this->_syncElements as $item) {
            $result = $sync->handleClientSyncItem($this->_outputHandler, $item);
            if (!$omit) {
                $this->_outputStatus($item);
            }
        }

        if ($this->_itemMoreData) {
            // Last item had <MoreData> element, produce appropriate response.
            $this->_outputHandler->outputStatus(
                $state->curSyncItem->cmdID,
                $state->curSyncItem->elementType,
                Horde_SyncMl::RESPONSE_CHUNKED_ITEM_ACCEPTED_AND_BUFFERED,
                '',
                $state->curSyncItem->cuid);
            // @todo: check if we have to send Alert NEXT_MESSAGE here!
        }
    }

    /**
     * Creates the <Status> response for one Add|Replace|Delete SyncElement.
     *
     * @param Horde_SyncMl_SyncElement $element  The element for which the status is
     *                                     to be created.
     */
    protected function _outputStatus($element)
    {
        // @todo: produce valid status
        $this->_outputHandler->outputStatus($element->cmdID,
                                            $element->elementType,
                                            $element->responseCode,
                                            '',
                                            $element->cuid);
    }
}