source: contrib/z-push/request.php @ 4898

Revision 4898, 56.5 KB checked in by thiagoaos, 13 years ago (diff)

Ticket #2180 - Adicionado código fonte completo do zpush

Line 
1<?php
2/***********************************************
3* File      :   request.php
4* Project   :   Z-Push
5* Descr     :   This file contains the actual
6*               request handling routines.
7*               The request handlers are optimised
8*               so that as little as possible
9*               data is kept-in-memory, and all
10*               output data is directly streamed
11*               to the client, while also streaming
12*               input data from the client.
13*
14* Created   :   01.10.2007
15*
16*  Zarafa Deutschland GmbH, www.zarafaserver.de
17* This file is distributed under GPL v2.
18* Consult LICENSE file for details
19************************************************/
20
21include_once("proto.php");
22include_once("wbxml.php");
23include_once("statemachine.php");
24include_once("backend/backend.php");
25include_once("memimporter.php");
26include_once("streamimporter.php");
27include_once("zpushdtd.php");
28include_once("zpushdefs.php");
29include_once("include/utils.php");
30
31function GetObjectClassFromFolderClass($folderclass)
32{
33    $classes = array ( "Email" => "syncmail", "Contacts" => "synccontact", "Calendar" => "syncappointment", "Tasks" => "synctask" );
34
35    return $classes[$folderclass];
36}
37
38function HandleMoveItems($backend, $protocolversion) {
39    global $zpushdtd;
40    global $input, $output;
41
42    $decoder = new WBXMLDecoder($input, $zpushdtd);
43    $encoder = new WBXMLEncoder($output, $zpushdtd);
44
45    if(!$decoder->getElementStartTag(SYNC_MOVE_MOVES))
46        return false;
47
48    $moves = array();
49    while($decoder->getElementStartTag(SYNC_MOVE_MOVE)) {
50        $move = array();
51        if($decoder->getElementStartTag(SYNC_MOVE_SRCMSGID)) {
52            $move["srcmsgid"] = $decoder->getElementContent();
53            if(!$decoder->getElementEndTag())
54                break;
55        }
56        if($decoder->getElementStartTag(SYNC_MOVE_SRCFLDID)) {
57            $move["srcfldid"] = $decoder->getElementContent();
58            if(!$decoder->getElementEndTag())
59                break;
60        }
61        if($decoder->getElementStartTag(SYNC_MOVE_DSTFLDID)) {
62            $move["dstfldid"] = $decoder->getElementContent();
63            if(!$decoder->getElementEndTag())
64                break;
65        }
66        array_push($moves, $move);
67
68        if(!$decoder->getElementEndTag())
69            return false;
70    }
71
72    if(!$decoder->getElementEndTag())
73        return false;
74
75    $encoder->StartWBXML();
76
77    $encoder->startTag(SYNC_MOVE_MOVES);
78
79    foreach($moves as $move) {
80        $encoder->startTag(SYNC_MOVE_RESPONSE);
81        $encoder->startTag(SYNC_MOVE_SRCMSGID);
82        $encoder->content($move["srcmsgid"]);
83        $encoder->endTag();
84
85        $importer = $backend->GetContentsImporter($move["srcfldid"]);
86        $result = $importer->ImportMessageMove($move["srcmsgid"], $move["dstfldid"]);
87        // We discard the importer state for now.
88
89        $encoder->startTag(SYNC_MOVE_STATUS);
90        $encoder->content($result ? 3 : 1);
91        $encoder->endTag();
92
93        $encoder->startTag(SYNC_MOVE_DSTMSGID);
94        $encoder->content(is_string($result)?$result:$move["srcmsgid"]);
95        $encoder->endTag();
96        $encoder->endTag();
97    }
98
99    $encoder->endTag();
100    return true;
101}
102
103function HandleNotify($backend, $protocolversion) {
104    global $zpushdtd;
105    global $input, $output;
106
107    $decoder = new WBXMLDecoder($input, $zpushdtd);
108    $encoder = new WBXMLEncoder($output, $zpushdtd);
109
110    if(!$decoder->getElementStartTag(SYNC_AIRNOTIFY_NOTIFY))
111        return false;
112
113    if(!$decoder->getElementStartTag(SYNC_AIRNOTIFY_DEVICEINFO))
114        return false;
115
116    if(!$decoder->getElementEndTag())
117        return false;
118
119    if(!$decoder->getElementEndTag())
120        return false;
121
122    $encoder->StartWBXML();
123
124    $encoder->startTag(SYNC_AIRNOTIFY_NOTIFY);
125    {
126        $encoder->startTag(SYNC_AIRNOTIFY_STATUS);
127        $encoder->content(1);
128        $encoder->endTag();
129
130        $encoder->startTag(SYNC_AIRNOTIFY_VALIDCARRIERPROFILES);
131        $encoder->endTag();
132    }
133
134    $encoder->endTag();
135
136    return true;
137
138}
139
140// Handle GetHierarchy method - simply returns current hierarchy of all folders
141function HandleGetHierarchy($backend, $protocolversion, $devid) {
142    global $zpushdtd;
143    global $output;
144
145    // Input is ignored, no data is sent by the PIM
146    $encoder = new WBXMLEncoder($output, $zpushdtd);
147
148    $folders = $backend->GetHierarchy();
149
150    if(!$folders)
151        return false;
152
153    // save folder-ids for fourther syncing
154    _saveFolderData($devid, $folders);
155
156    $encoder->StartWBXML();
157    $encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERS);
158
159    foreach ($folders as $folder) {
160        $encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDER);
161        $folder->encode($encoder);
162        $encoder->endTag();
163    }
164
165    $encoder->endTag();
166    return true;
167}
168
169// Handles a 'FolderSync' method - receives folder updates, and sends reply with
170// folder changes on the server
171function HandleFolderSync($backend, $protocolversion) {
172    global $zpushdtd;
173    global $input, $output;
174
175    // Maps serverid -> clientid for items that are received from the PIM
176    $map = array();
177
178    $decoder = new WBXMLDecoder($input, $zpushdtd);
179    $encoder = new WBXMLEncoder($output, $zpushdtd);
180
181    // Parse input
182
183    if(!$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC))
184        return false;
185
186    if(!$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY))
187        return false;
188
189    $synckey = $decoder->getElementContent();
190
191    if(!$decoder->getElementEndTag())
192        return false;
193
194    // First, get the syncstate that is associated with this synckey
195    $statemachine = new StateMachine();
196
197    // The state machine will discard any sync states before this one, as they are no
198    // longer required
199    $syncstate = $statemachine->getSyncState($synckey);
200
201    // additional information about already seen folders
202    $sfolderstate = $statemachine->getSyncState("s".$synckey);
203   
204    if (!$sfolderstate) {
205        $foldercache = array();
206        if ($sfolderstate === false)
207            debugLog("Error: FolderChacheState for state 's". $synckey ."' not found. Reinitializing...");
208    }
209    else {
210        $foldercache = unserialize($sfolderstate);
211
212        // transform old seenfolder array
213        if (array_key_exists("0", $foldercache)) {
214                $tmp = array();
215                foreach($foldercache as $s) $tmp[$s] = new SyncFolder();
216                $foldercache = $tmp;
217        }
218    }
219       
220    // We will be saving the sync state under 'newsynckey'
221    $newsynckey = $statemachine->getNewSyncKey($synckey);
222    $changes = false;
223   
224    if($decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_CHANGES)) {
225        // Ignore <Count> if present
226        if($decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_COUNT)) {
227            $decoder->getElementContent();
228            if(!$decoder->getElementEndTag())
229                return false;
230        }
231
232        // Process the changes (either <Add>, <Modify>, or <Remove>)
233        $element = $decoder->getElement();
234
235        if($element[EN_TYPE] != EN_TYPE_STARTTAG)
236            return false;
237
238        while(1) {
239            $folder = new SyncFolder();
240            if(!$folder->decode($decoder))
241                break;
242
243            // Configure importer with last state
244            $importer = $backend->GetHierarchyImporter();
245            $importer->Config($syncstate);
246
247
248            switch($element[EN_TAG]) {
249                case SYNC_ADD:
250                case SYNC_MODIFY:
251                    $serverid = $importer->ImportFolderChange($folder);
252                    // add folder to the serverflags
253                    $foldercache[$serverid] = $folder;
254                    $changes = true;
255                    break;
256                case SYNC_REMOVE:
257                    $serverid = $importer->ImportFolderDeletion($folder);
258                    $changes = true;
259                    // remove folder from the folderchache
260                    if (array_key_exists($serverid, $foldercache))
261                        unset($foldercache[$serverid]);
262                    break;
263            }
264
265            if($serverid)
266                $map[$serverid] = $folder->clientid;
267        }
268
269        if(!$decoder->getElementEndTag())
270            return false;
271    }
272
273    if(!$decoder->getElementEndTag())
274        return false;
275
276    // We have processed incoming foldersync requests, now send the PIM
277    // our changes
278
279    // The MemImporter caches all imports in-memory, so we can send a change count
280    // before sending the actual data. As the amount of data done in this operation
281    // is rather low, this is not memory problem. Note that this is not done when
282    // sync'ing messages - we let the exporter write directly to WBXML.
283    $importer = new ImportHierarchyChangesMem($foldercache);
284
285    // Request changes from backend, they will be sent to the MemImporter passed as the first
286    // argument, which stores them in $importer. Returns the new sync state for this exporter.
287    $exporter = $backend->GetExporter();
288
289    $exporter->Config($importer, false, false, $syncstate, 0, 0);
290
291    while(is_array($exporter->Synchronize()));
292
293    // Output our WBXML reply now
294    $encoder->StartWBXML();
295
296    $encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERSYNC);
297    {
298        $encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
299        $encoder->content(1);
300        $encoder->endTag();
301
302        $encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
303        // only send new synckey if changes were processed or there are outgoing changes
304        $encoder->content((($changes || $importer->count > 0)?$newsynckey:$synckey));
305        $encoder->endTag();
306
307        $encoder->startTag(SYNC_FOLDERHIERARCHY_CHANGES);
308        {
309            $encoder->startTag(SYNC_FOLDERHIERARCHY_COUNT);
310            $encoder->content($importer->count);
311            $encoder->endTag();
312
313            if(count($importer->changed) > 0) {
314                foreach($importer->changed as $folder) {
315                        // send a modify flag if the folder is already known on the device
316                        if (isset($folder->serverid) && array_key_exists($folder->serverid, $foldercache) !== false)
317                        $encoder->startTag(SYNC_FOLDERHIERARCHY_UPDATE);
318                        else
319                        $encoder->startTag(SYNC_FOLDERHIERARCHY_ADD);
320                    $foldercache[$folder->serverid] = $folder;
321                   
322                    $folder->encode($encoder);
323                    $encoder->endTag();
324                }
325            }
326
327            if(count($importer->deleted) > 0) {
328                foreach($importer->deleted as $folder) {
329                    $encoder->startTag(SYNC_FOLDERHIERARCHY_REMOVE);
330                        $encoder->startTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID);
331                            $encoder->content($folder);
332                        $encoder->endTag();
333                    $encoder->endTag();
334
335                    // remove folder from the folderchache
336                    if (array_key_exists($folder, $foldercache))
337                        unset($foldercache[$folder]);
338                }
339            }
340        }
341        $encoder->endTag();
342    }
343    $encoder->endTag();
344
345    // Save the sync state for the next time
346    $syncstate = $exporter->GetState();
347    $statemachine->setSyncState($newsynckey, $syncstate);
348    $statemachine->setSyncState("s".$newsynckey, serialize($foldercache));
349
350
351    return true;
352}
353
354function HandleSync($backend, $protocolversion, $devid) {
355    global $zpushdtd;
356    global $input, $output;
357
358    // Contains all containers requested
359    $collections = array();
360
361    // Init WBXML decoder
362    $decoder = new WBXMLDecoder($input, $zpushdtd);
363
364    // Init state machine
365    $statemachine = new StateMachine();
366
367    // Start decode
368    if(!$decoder->getElementStartTag(SYNC_SYNCHRONIZE))
369        return false;
370
371    if(!$decoder->getElementStartTag(SYNC_FOLDERS))
372        return false;
373
374    while($decoder->getElementStartTag(SYNC_FOLDER))
375    {
376        $collection = array();
377        $collection["truncation"] = SYNC_TRUNCATION_ALL;
378        $collection["clientids"] = array();
379        $collection["fetchids"] = array();
380
381        if(!$decoder->getElementStartTag(SYNC_FOLDERTYPE))
382            return false;
383
384        $collection["class"] = $decoder->getElementContent();
385        debugLog("Sync folder:{$collection["class"]}");
386
387        if(!$decoder->getElementEndTag())
388            return false;
389
390        if(!$decoder->getElementStartTag(SYNC_SYNCKEY))
391            return false;
392
393        $collection["synckey"] = $decoder->getElementContent();
394
395        if(!$decoder->getElementEndTag())
396            return false;
397
398        if($decoder->getElementStartTag(SYNC_FOLDERID)) {
399            $collection["collectionid"] = $decoder->getElementContent();
400
401            if(!$decoder->getElementEndTag())
402                return false;
403        }
404
405        if($decoder->getElementStartTag(SYNC_SUPPORTED)) {
406            while(1) {
407                $el = $decoder->getElement();
408                if($el[EN_TYPE] == EN_TYPE_ENDTAG)
409                    break;
410            }
411        }
412
413        if($decoder->getElementStartTag(SYNC_DELETESASMOVES))
414            $collection["deletesasmoves"] = true;
415
416        if($decoder->getElementStartTag(SYNC_GETCHANGES))
417            $collection["getchanges"] = true;
418
419        if($decoder->getElementStartTag(SYNC_MAXITEMS)) {
420            $collection["maxitems"] = $decoder->getElementContent();
421            if(!$decoder->getElementEndTag())
422                return false;
423        }
424
425        if($decoder->getElementStartTag(SYNC_OPTIONS)) {
426            while(1) {
427                if($decoder->getElementStartTag(SYNC_FILTERTYPE)) {
428                    $collection["filtertype"] = $decoder->getElementContent();
429                    if(!$decoder->getElementEndTag())
430                        return false;
431                }
432                if($decoder->getElementStartTag(SYNC_TRUNCATION)) {
433                    $collection["truncation"] = $decoder->getElementContent();
434                    if(!$decoder->getElementEndTag())
435                        return false;
436                }
437                if($decoder->getElementStartTag(SYNC_RTFTRUNCATION)) {
438                    $collection["rtftruncation"] = $decoder->getElementContent();
439                    if(!$decoder->getElementEndTag())
440                        return false;
441                }
442
443                if($decoder->getElementStartTag(SYNC_MIMESUPPORT)) {
444                    $collection["mimesupport"] = $decoder->getElementContent();
445                    if(!$decoder->getElementEndTag())
446                        return false;
447                }
448
449                if($decoder->getElementStartTag(SYNC_MIMETRUNCATION)) {
450                    $collection["mimetruncation"] = $decoder->getElementContent();
451                    if(!$decoder->getElementEndTag())
452                        return false;
453                }
454
455                if($decoder->getElementStartTag(SYNC_CONFLICT)) {
456                    $collection["conflict"] = $decoder->getElementContent();
457                    if(!$decoder->getElementEndTag())
458                        return false;
459                }
460                $e = $decoder->peek();
461                if($e[EN_TYPE] == EN_TYPE_ENDTAG) {
462                    $decoder->getElementEndTag();
463                    break;
464                }
465            }
466        }
467
468        // compatibility mode - get folderid from the state directory
469        if (!isset($collection["collectionid"])) {
470            $collection["collectionid"] = _getFolderID($devid, $collection["class"]);
471        }
472
473        // compatibility mode - set default conflict behavior if no conflict resolution algorithm is set (OVERWRITE_PIM)
474        if (!isset($collection["conflict"])) {
475            $collection["conflict"] = 1;
476        }
477
478        //compatibility mode - set maxitems if the client doesn't send it as it breaks some devices
479        if (!isset($collection["maxitems"])) {
480            $collection["maxitems"] = 100;
481        }
482
483        // Get our sync state for this collection
484        $collection["syncstate"] = $statemachine->getSyncState($collection["synckey"]);
485        if($decoder->getElementStartTag(SYNC_PERFORM)) {
486
487            // Configure importer with last state
488            $importer = $backend->GetContentsImporter($collection["collectionid"]);
489            $importer->Config($collection["syncstate"], $collection["conflict"]);
490
491            $nchanges = 0;
492            while(1) {
493                $element = $decoder->getElement(); // MODIFY or REMOVE or ADD or FETCH
494
495                if($element[EN_TYPE] != EN_TYPE_STARTTAG) {
496                    $decoder->ungetElement($element);
497                    break;
498                }
499
500                $nchanges++;
501
502                if($decoder->getElementStartTag(SYNC_SERVERENTRYID)) {
503                    $serverid = $decoder->getElementContent();
504
505                    if(!$decoder->getElementEndTag()) // end serverid
506                        return false;
507                } else {
508                    $serverid = false;
509                }
510
511                if($decoder->getElementStartTag(SYNC_CLIENTENTRYID)) {
512                    $clientid = $decoder->getElementContent();
513
514                    if(!$decoder->getElementEndTag()) // end clientid
515                        return false;
516                } else {
517                    $clientid = false;
518                }
519
520                // Get application data if available
521                if($decoder->getElementStartTag(SYNC_DATA)) {
522                    switch($collection["class"]) {
523                        case "Email":
524                            $appdata = new SyncMail();
525                            $appdata->decode($decoder);
526                            break;
527                        case "Contacts":
528                            $appdata = new SyncContact($protocolversion);
529                            $appdata->decode($decoder);
530                            break;
531                        case "Calendar":
532                            $appdata = new SyncAppointment();
533                            $appdata->decode($decoder);
534                            break;
535                        case "Tasks":
536                            $appdata = new SyncTask();
537                            $appdata->decode($decoder);
538                            break;
539                    }
540                    if(!$decoder->getElementEndTag()) // end applicationdata
541                        return false;
542
543                }
544
545                switch($element[EN_TAG]) {
546                    case SYNC_MODIFY:
547                        if(isset($appdata)) {
548                            if(isset($appdata->read)) // Currently, 'read' is only sent by the PDA when it is ONLY setting the read flag.
549                                $importer->ImportMessageReadFlag($serverid, $appdata->read);
550                            else
551                                $importer->ImportMessageChange($serverid, $appdata);
552                            $collection["importedchanges"] = true;
553                        }
554                        break;
555                    case SYNC_ADD:
556                        if(isset($appdata)) {
557                            $id = $importer->ImportMessageChange(false, $appdata);
558
559                            if($clientid && $id) {
560                                $collection["clientids"][$clientid] = $id;
561                                $collection["importedchanges"] = true;
562                            }
563                        }
564                        break;
565                    case SYNC_REMOVE:
566                        if(isset($collection["deletesasmoves"])) {
567                            $folderid = $backend->GetWasteBasket();
568
569                            if($folderid) {
570                                $importer->ImportMessageMove($serverid, $folderid);
571                                $collection["importedchanges"] = true;
572                                break;
573                            }
574                        }
575
576                        $importer->ImportMessageDeletion($serverid);
577                        $collection["importedchanges"] = true;
578                        break;
579                    case SYNC_FETCH:
580                        array_push($collection["fetchids"], $serverid);
581                        break;
582                }
583
584                if(!$decoder->getElementEndTag()) // end change/delete/move
585                    return false;
586            }
587
588            debugLog("Processed $nchanges incoming changes");
589
590            // Save the updated state, which is used for the exporter later
591            $collection["syncstate"] = $importer->getState();
592
593
594            if(!$decoder->getElementEndTag()) // end commands
595                return false;
596        }
597
598        if(!$decoder->getElementEndTag()) // end collection
599            return false;
600
601        array_push($collections, $collection);
602    }
603
604    if(!$decoder->getElementEndTag()) // end collections
605        return false;
606
607    if(!$decoder->getElementEndTag()) // end sync
608        return false;
609
610    $encoder = new WBXMLEncoder($output, $zpushdtd);
611    $encoder->startWBXML();
612
613    $encoder->startTag(SYNC_SYNCHRONIZE);
614    {
615        $encoder->startTag(SYNC_FOLDERS);
616        {
617            foreach($collections as $collection) {
618                // initialize exporter to get changecount
619                $changecount = 0;
620                if(isset($collection["getchanges"])) {
621                    // Use the state from the importer, as changes may have already happened
622                    $exporter = $backend->GetExporter($collection["collectionid"]);
623
624                    $filtertype = isset($collection["filtertype"]) ? $collection["filtertype"] : false;
625                    $exporter->Config($importer, $collection["class"], $filtertype, $collection["syncstate"], 0, $collection["truncation"]);
626
627                    $changecount = $exporter->GetChangeCount();
628                }
629               
630                // Get a new sync key to output to the client if any changes have been requested or will be send
631                if (isset($collection["importedchanges"]) || $changecount > 0 || $collection["synckey"] == "0")
632                    $collection["newsynckey"] = $statemachine->getNewSyncKey($collection["synckey"]);
633
634                $encoder->startTag(SYNC_FOLDER);
635
636                $encoder->startTag(SYNC_FOLDERTYPE);
637                $encoder->content($collection["class"]);
638                $encoder->endTag();
639
640                $encoder->startTag(SYNC_SYNCKEY);
641
642                if(isset($collection["newsynckey"]))
643                    $encoder->content($collection["newsynckey"]);
644                else
645                    $encoder->content($collection["synckey"]);
646
647                $encoder->endTag();
648
649                $encoder->startTag(SYNC_FOLDERID);
650                $encoder->content($collection["collectionid"]);
651                $encoder->endTag();
652
653                $encoder->startTag(SYNC_STATUS);
654                $encoder->content(1);
655                $encoder->endTag();
656
657                //check the mimesupport because we need it for advanced emails
658                $mimesupport = isset($collection['mimesupport']) ? $collection['mimesupport'] : 0;
659
660                // Output server IDs for new items we received from the PDA
661                if(isset($collection["clientids"]) || count($collection["fetchids"]) > 0) {
662                    $encoder->startTag(SYNC_REPLIES);
663                    foreach($collection["clientids"] as $clientid => $serverid) {
664                        $encoder->startTag(SYNC_ADD);
665                        $encoder->startTag(SYNC_CLIENTENTRYID);
666                        $encoder->content($clientid);
667                        $encoder->endTag();
668                        $encoder->startTag(SYNC_SERVERENTRYID);
669                        $encoder->content($serverid);
670                        $encoder->endTag();
671                        $encoder->startTag(SYNC_STATUS);
672                        $encoder->content(1);
673                        $encoder->endTag();
674                        $encoder->endTag();
675                    }
676                    foreach($collection["fetchids"] as $id) {
677                        $data = $backend->Fetch($collection["collectionid"], $id, $mimesupport);
678                        if($data !== false) {
679                            $encoder->startTag(SYNC_FETCH);
680                            $encoder->startTag(SYNC_SERVERENTRYID);
681                            $encoder->content($id);
682                            $encoder->endTag();
683                            $encoder->startTag(SYNC_STATUS);
684                            $encoder->content(1);
685                            $encoder->endTag();
686                            $encoder->startTag(SYNC_DATA);
687                            $data->encode($encoder);
688                            $encoder->endTag();
689                            $encoder->endTag();
690                        } else {
691                            debugLog("unable to fetch $id");
692                        }
693                    }
694                    $encoder->endTag();
695                }
696
697                if(isset($collection["getchanges"])) {
698                    // exporter already intialized
699
700                    if($changecount > $collection["maxitems"]) {
701                        $encoder->startTag(SYNC_MOREAVAILABLE, false, true);
702                    }
703
704                    // Output message changes per folder
705                    $encoder->startTag(SYNC_PERFORM);
706
707                    // Stream the changes to the PDA
708                    $importer = new ImportContentsChangesStream($encoder, GetObjectClassFromFolderClass($collection["class"]));
709
710                    $filtertype = isset($collection["filtertype"]) ? $collection["filtertype"] : 0;
711
712                    $n = 0;
713                    while(1) {
714                        $progress = $exporter->Synchronize();
715                        if(!is_array($progress))
716                            break;
717                        $n++;
718
719                        if($n >= $collection["maxitems"]) {
720                                debugLog("Exported maxItems of messages: ". $collection["maxitems"] . " - more available");
721                            break;
722                        }
723
724                    }
725                    $encoder->endTag();
726                }
727
728                $encoder->endTag();
729
730                // Save the sync state for the next time
731                if(isset($collection["newsynckey"])) {
732                    if (isset($exporter) && $exporter)
733                        $state = $exporter->GetState();
734
735                    // nothing exported, but possible imported
736                    else if (isset($importer) && $importer)
737                        $state = $importer->GetState();
738
739                    // if a new request without state information (hierarchy) save an empty state
740                    else if ($collection["synckey"] == "0")
741                        $state = "";
742
743                    if (isset($state)) $statemachine->setSyncState($collection["newsynckey"], $state);
744                    else debugLog("error saving " . $collection["newsynckey"] . " - no state information available");
745                }
746            }
747        }
748        $encoder->endTag();
749    }
750    $encoder->endTag();
751
752    return true;
753}
754
755function HandleGetItemEstimate($backend, $protocolversion, $devid) {
756    global $zpushdtd;
757    global $input, $output;
758
759    $collections = array();
760
761    $decoder = new WBXMLDecoder($input, $zpushdtd);
762    $encoder = new WBXMLEncoder($output, $zpushdtd);
763
764    if(!$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE))
765        return false;
766
767    if(!$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERS))
768        return false;
769
770    while($decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDER)) {
771        $collection = array();
772
773        if(!$decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERTYPE))
774            return false;
775
776        $class = $decoder->getElementContent();
777
778        if(!$decoder->getElementEndTag())
779            return false;
780
781        if($decoder->getElementStartTag(SYNC_GETITEMESTIMATE_FOLDERID)) {
782            $collectionid = $decoder->getElementContent();
783
784            if(!$decoder->getElementEndTag())
785                return false;
786        }
787
788        if(!$decoder->getElementStartTag(SYNC_FILTERTYPE))
789            return false;
790
791        $filtertype = $decoder->getElementContent();
792
793        if(!$decoder->getElementEndTag())
794            return false;
795
796        if(!$decoder->getElementStartTag(SYNC_SYNCKEY))
797            return false;
798
799        $synckey = $decoder->getElementContent();
800
801        if(!$decoder->getElementEndTag())
802            return false;
803        if(!$decoder->getElementEndTag())
804            return false;
805
806        // compatibility mode - get folderid from the state directory
807        if (!isset($collectionid)) {
808            $collectionid = _getFolderID($devid, $class);
809        }
810
811        $collection = array();
812        $collection["synckey"] = $synckey;
813        $collection["class"] = $class;
814        $collection["filtertype"] = $filtertype;
815        $collection["collectionid"] = $collectionid;
816
817        array_push($collections, $collection);
818    }
819
820    $encoder->startWBXML();
821
822    $encoder->startTag(SYNC_GETITEMESTIMATE_GETITEMESTIMATE);
823    {
824        foreach($collections as $collection) {
825            $encoder->startTag(SYNC_GETITEMESTIMATE_RESPONSE);
826            {
827                $encoder->startTag(SYNC_GETITEMESTIMATE_STATUS);
828                $encoder->content(1);
829                $encoder->endTag();
830
831                $encoder->startTag(SYNC_GETITEMESTIMATE_FOLDER);
832                {
833                    $encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERTYPE);
834                    $encoder->content($collection["class"]);
835                    $encoder->endTag();
836
837                    $encoder->startTag(SYNC_GETITEMESTIMATE_FOLDERID);
838                    $encoder->content($collection["collectionid"]);
839                    $encoder->endTag();
840
841                    $encoder->startTag(SYNC_GETITEMESTIMATE_ESTIMATE);
842
843                    $importer = new ImportContentsChangesMem();
844
845                    $statemachine = new StateMachine();
846                    $syncstate = $statemachine->getSyncState($collection["synckey"]);
847
848                    $exporter = $backend->GetExporter($collection["collectionid"]);
849                    $exporter->Config($importer, $collection["class"], $collection["filtertype"], $syncstate, 0, 0);
850
851                    $encoder->content($exporter->GetChangeCount());
852
853                    $encoder->endTag();
854                }
855                $encoder->endTag();
856            }
857            $encoder->endTag();
858        }
859    }
860    $encoder->endTag();
861
862    return true;
863}
864
865function HandleGetAttachment($backend, $protocolversion) {
866    $attname = $_GET["AttachmentName"];
867
868    if(!isset($attname))
869        return false;
870
871    header("Content-Type: application/octet-stream");
872
873    $backend->GetAttachmentData($attname);
874
875    return true;
876}
877
878function HandlePing($backend, $devid) {
879    global $zpushdtd, $input, $output;
880    global $user, $auth_pw;
881    $timeout = 5;
882
883    debugLog("Ping received");
884
885    $decoder = new WBXMLDecoder($input, $zpushdtd);
886    $encoder = new WBXMLEncoder($output, $zpushdtd);
887
888    $collections = array();
889    $lifetime = 0;
890
891    // Get previous defaults if they exist
892    $file = BASE_PATH . STATE_DIR . "/" . $devid;
893    if (file_exists($file)) {
894        $ping = unserialize(file_get_contents($file));
895        $collections = $ping["collections"];
896        $lifetime = $ping["lifetime"];
897    }
898
899    if($decoder->getElementStartTag(SYNC_PING_PING)) {
900        debugLog("Ping init");
901        if($decoder->getElementStartTag(SYNC_PING_LIFETIME)) {
902            $lifetime = $decoder->getElementContent();
903            $decoder->getElementEndTag();
904        }
905
906        if($decoder->getElementStartTag(SYNC_PING_FOLDERS)) {
907            // avoid ping init if not necessary
908            $saved_collections = $collections;
909
910            $collections = array();
911
912            while($decoder->getElementStartTag(SYNC_PING_FOLDER)) {
913                $collection = array();
914
915                if($decoder->getElementStartTag(SYNC_PING_SERVERENTRYID)) {
916                    $collection["serverid"] = $decoder->getElementContent();
917                    $decoder->getElementEndTag();
918                }
919                if($decoder->getElementStartTag(SYNC_PING_FOLDERTYPE)) {
920                    $collection["class"] = $decoder->getElementContent();
921                    $decoder->getElementEndTag();
922                }
923
924                $decoder->getElementEndTag();
925
926                // initialize empty state
927                $collection["state"] = "";
928
929                // try to find old state in saved states
930                foreach ($saved_collections as $saved_col) {
931                    if ($saved_col["serverid"] == $collection["serverid"] && $saved_col["class"] == $collection["class"]) {
932                        $collection["state"] = $saved_col["state"];
933                        debugLog("reusing saved state for ". $collection["class"]);
934                        break;
935                    }
936                }
937
938                if ($collection["state"] == "")
939                    debugLog("empty state for ". $collection["class"]);
940
941                // Create start state for this collection
942                $exporter = $backend->GetExporter($collection["serverid"]);
943                $importer = false;
944                $exporter->Config($importer, false, false, $collection["state"], BACKEND_DISCARD_DATA, 0);
945                while(is_array($exporter->Synchronize()));
946                $collection["state"] = $exporter->GetState();
947                array_push($collections, $collection);
948            }
949
950            if(!$decoder->getElementEndTag())
951                return false;
952        }
953
954        if(!$decoder->getElementEndTag())
955            return false;
956    }
957
958    $changes = array();
959    $dataavailable = false;
960
961    debugLog("Waiting for changes... (lifetime $lifetime)");
962    // Wait for something to happen
963    for($n=0;$n<$lifetime / $timeout; $n++ ) {
964        //check the remote wipe status
965        if (PROVISIONING === true) {
966                $rwstatus = $backend->getDeviceRWStatus($user, $auth_pw, $devid);
967                if ($rwstatus == SYNC_PROVISION_RWSTATUS_PENDING || $rwstatus == SYNC_PROVISION_RWSTATUS_WIPED) {
968                    //return 7 because it forces folder sync
969                    $pingstatus = 7;
970                    break;
971                }
972        }
973
974        if(count($collections) == 0) {
975            $error = 1;
976            break;
977        }
978
979        for($i=0;$i<count($collections);$i++) {
980            $collection = $collections[$i];
981
982            $exporter = $backend->GetExporter($collection["serverid"]);
983            $state = $collection["state"];
984            $importer = false;
985            $ret = $exporter->Config($importer, false, false, $state, BACKEND_DISCARD_DATA, 0);
986
987            // stop ping if exporter can not be configured (e.g. after Zarafa-server restart)
988            if ($ret === false ) {
989                // force "ping" to stop
990                $n = $lifetime / $timeout;
991                debugLog("Ping error: Exporter can not be configured. Waiting 30 seconds before ping is retried.");
992                sleep(30);
993                break;
994            }
995
996            $changecount = $exporter->GetChangeCount();
997
998            if($changecount > 0) {
999                $dataavailable = true;
1000                $changes[$collection["serverid"]] = $changecount;
1001            }
1002
1003            // Discard any data
1004            while(is_array($exporter->Synchronize()));
1005
1006            // Record state for next Ping
1007            $collections[$i]["state"] = $exporter->GetState();
1008        }
1009
1010        if($dataavailable) {
1011            debugLog("Found change");
1012            break;
1013        }
1014
1015        sleep($timeout);
1016    }
1017
1018    $encoder->StartWBXML();
1019
1020    $encoder->startTag(SYNC_PING_PING);
1021    {
1022        $encoder->startTag(SYNC_PING_STATUS);
1023        if(isset($error))
1024            $encoder->content(3);
1025        elseif (isset($pingstatus))
1026            $encoder->content($pingstatus);
1027        else
1028            $encoder->content(count($changes) > 0 ? 2 : 1);
1029        $encoder->endTag();
1030
1031        $encoder->startTag(SYNC_PING_FOLDERS);
1032        foreach($collections as $collection) {
1033            if(isset($changes[$collection["serverid"]])) {
1034                $encoder->startTag(SYNC_PING_FOLDER);
1035                $encoder->content($collection["serverid"]);
1036                $encoder->endTag();
1037            }
1038        }
1039        $encoder->endTag();
1040    }
1041    $encoder->endTag();
1042
1043    // Save the ping request state for this device
1044    file_put_contents(BASE_PATH . "/" . STATE_DIR . "/" . $devid, serialize(array("lifetime" => $lifetime, "collections" => $collections)));
1045
1046    return true;
1047}
1048
1049function HandleSendMail($backend, $protocolversion) {
1050    // All that happens here is that we receive an rfc822 message on stdin
1051    // and just forward it to the backend. We provide no output except for
1052    // an OK http reply
1053
1054    global $input;
1055
1056    $rfc822 = readStream($input);
1057
1058    return $backend->SendMail($rfc822);
1059}
1060
1061function HandleSmartForward($backend, $protocolversion) {
1062    global $input;
1063    // SmartForward is a normal 'send' except that you should attach the
1064    // original message which is specified in the URL
1065
1066    $rfc822 = readStream($input);
1067
1068    if(isset($_GET["ItemId"]))
1069        $orig = $_GET["ItemId"];
1070    else
1071        $orig = false;
1072
1073    if(isset($_GET["CollectionId"]))
1074        $parent = $_GET["CollectionId"];
1075    else
1076        $parent = false;
1077
1078    return $backend->SendMail($rfc822, $orig, false, $parent);
1079}
1080
1081function HandleSmartReply($backend, $protocolversion) {
1082    global $input;
1083    // Smart reply should add the original message to the end of the message body
1084
1085    $rfc822 = readStream($input);
1086
1087    if(isset($_GET["ItemId"]))
1088        $orig = $_GET["ItemId"];
1089    else
1090        $orig = false;
1091
1092    if(isset($_GET["CollectionId"]))
1093        $parent = $_GET["CollectionId"];
1094    else
1095        $parent = false;
1096
1097    return $backend->SendMail($rfc822, false, $orig, $parent);
1098}
1099
1100function HandleFolderCreate($backend, $protocolversion) {
1101    global $zpushdtd;
1102    global $input, $output;
1103
1104    $decoder = new WBXMLDecoder($input, $zpushdtd);
1105    $encoder = new WBXMLEncoder($output, $zpushdtd);
1106
1107    $el = $decoder->getElement();
1108
1109    if($el[EN_TYPE] != EN_TYPE_STARTTAG)
1110        return false;
1111
1112    $create = $update = $delete = false;
1113
1114    if($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERCREATE)
1115        $create = true;
1116    else if($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERUPDATE)
1117        $update = true;
1118    else if($el[EN_TAG] == SYNC_FOLDERHIERARCHY_FOLDERDELETE)
1119        $delete = true;
1120
1121    if(!$create && !$update && !$delete)
1122        return false;
1123
1124    // SyncKey
1125    if(!$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SYNCKEY))
1126        return false;
1127    $synckey = $decoder->getElementContent();
1128    if(!$decoder->getElementEndTag())
1129        return false;
1130
1131    // ServerID
1132    $serverid = false;
1133    if($decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID)) {
1134        $serverid = $decoder->getElementContent();
1135        if(!$decoder->getElementEndTag())
1136            return false;
1137    }
1138
1139    // when creating or updating more information is necessary
1140    if (!$delete) {
1141            // Parent
1142            $parentid = false;
1143            if($decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_PARENTID)) {
1144                $parentid = $decoder->getElementContent();
1145                if(!$decoder->getElementEndTag())
1146                    return false;
1147            }
1148
1149            // Displayname
1150            if(!$decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_DISPLAYNAME))
1151                return false;
1152            $displayname = $decoder->getElementContent();
1153            if(!$decoder->getElementEndTag())
1154                return false;
1155
1156            // Type
1157            $type = false;
1158            if($decoder->getElementStartTag(SYNC_FOLDERHIERARCHY_TYPE)) {
1159                $type = $decoder->getElementContent();
1160                if(!$decoder->getElementEndTag())
1161                    return false;
1162            }
1163    }
1164
1165    if(!$decoder->getElementEndTag())
1166        return false;
1167
1168    // Get state of hierarchy
1169    $statemachine = new StateMachine();
1170    $syncstate = $statemachine->getSyncState($synckey);
1171    $newsynckey = $statemachine->getNewSyncKey($synckey);
1172
1173    // additional information about already seen folders
1174    $seenfolders = unserialize($statemachine->getSyncState("s".$synckey));
1175    if (!$seenfolders) $seenfolders = array();
1176
1177    // Configure importer with last state
1178    $importer = $backend->GetHierarchyImporter();
1179    $importer->Config($syncstate);
1180
1181    if (!$delete) {
1182            // Send change
1183            $serverid = $importer->ImportFolderChange($serverid, $parentid, $displayname, $type);
1184    }
1185    else {
1186        // delete folder
1187        $deletedstat = $importer->ImportFolderDeletion($serverid, 0);
1188    }
1189
1190    $encoder->startWBXML();
1191    if ($create) {
1192        // add folder id to the seen folders
1193        $seenfolders[] = $serverid;
1194
1195        $encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERCREATE);
1196        {
1197            {
1198                $encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
1199                $encoder->content(1);
1200                $encoder->endTag();
1201
1202                $encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
1203                $encoder->content($newsynckey);
1204                $encoder->endTag();
1205
1206                $encoder->startTag(SYNC_FOLDERHIERARCHY_SERVERENTRYID);
1207                $encoder->content($serverid);
1208                $encoder->endTag();
1209            }
1210            $encoder->endTag();
1211        }
1212        $encoder->endTag();
1213    }
1214
1215    elseif ($update) {
1216
1217        $encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERUPDATE);
1218        {
1219            {
1220                $encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
1221                $encoder->content(1);
1222                $encoder->endTag();
1223
1224                $encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
1225                $encoder->content($newsynckey);
1226                $encoder->endTag();
1227            }
1228            $encoder->endTag();
1229        }
1230    }
1231    elseif ($delete) {
1232
1233        $encoder->startTag(SYNC_FOLDERHIERARCHY_FOLDERDELETE);
1234        {
1235            {
1236                $encoder->startTag(SYNC_FOLDERHIERARCHY_STATUS);
1237                $encoder->content($deletedstat);
1238                $encoder->endTag();
1239
1240                $encoder->startTag(SYNC_FOLDERHIERARCHY_SYNCKEY);
1241                $encoder->content($newsynckey);
1242                $encoder->endTag();
1243            }
1244            $encoder->endTag();
1245        }
1246
1247        // remove folder from the folderflags array
1248        if (($sid = array_search($serverid, $seenfolders)) !== false) {
1249            unset($seenfolders[$sid]);
1250            $seenfolders = array_values($seenfolders);
1251            debugLog("deleted from seenfolders: ". $serverid);
1252        }
1253    }
1254
1255    $encoder->endTag();
1256    // Save the sync state for the next time
1257    $statemachine->setSyncState($newsynckey, $importer->GetState());
1258    $statemachine->setSyncState("s".$newsynckey, serialize($seenfolders));
1259
1260    return true;
1261}
1262
1263// Handle meetingresponse method
1264function HandleMeetingResponse($backend, $protocolversion) {
1265    global $zpushdtd;
1266    global $output, $input;
1267
1268    $requests = Array();
1269
1270    $decoder = new WBXMLDecoder($input, $zpushdtd);
1271    $encoder = new WBXMLEncoder($output, $zpushdtd);
1272
1273    if(!$decoder->getElementStartTag(SYNC_MEETINGRESPONSE_MEETINGRESPONSE))
1274        return false;
1275
1276    while($decoder->getElementStartTag(SYNC_MEETINGRESPONSE_REQUEST)) {
1277        $req = Array();
1278
1279        if($decoder->getElementStartTag(SYNC_MEETINGRESPONSE_USERRESPONSE)) {
1280            $req["response"] = $decoder->getElementContent();
1281            if(!$decoder->getElementEndTag())
1282                return false;
1283        }
1284
1285        if($decoder->getElementStartTag(SYNC_MEETINGRESPONSE_FOLDERID)) {
1286            $req["folderid"] = $decoder->getElementContent();
1287            if(!$decoder->getElementEndTag())
1288                return false;
1289        }
1290
1291        if($decoder->getElementStartTag(SYNC_MEETINGRESPONSE_REQUESTID)) {
1292            $req["requestid"] = $decoder->getElementContent();
1293            if(!$decoder->getElementEndTag())
1294                return false;
1295        }
1296
1297        if(!$decoder->getElementEndTag())
1298            return false;
1299
1300        array_push($requests, $req);
1301    }
1302
1303    if(!$decoder->getElementEndTag())
1304        return false;
1305
1306
1307    // Start output, simply the error code, plus the ID of the calendar item that was generated by the
1308    // accept of the meeting response
1309
1310    $encoder->StartWBXML();
1311
1312    $encoder->startTag(SYNC_MEETINGRESPONSE_MEETINGRESPONSE);
1313
1314    foreach($requests as $req) {
1315        $calendarid = "";
1316        $ok = $backend->MeetingResponse($req["requestid"], $req["folderid"], $req["response"], $calendarid);
1317        $encoder->startTag(SYNC_MEETINGRESPONSE_RESULT);
1318            $encoder->startTag(SYNC_MEETINGRESPONSE_REQUESTID);
1319                $encoder->content($req["requestid"]);
1320            $encoder->endTag();
1321
1322            $encoder->startTag(SYNC_MEETINGRESPONSE_STATUS);
1323                $encoder->content($ok ? 1 : 2);
1324            $encoder->endTag();
1325
1326            if($ok) {
1327                $encoder->startTag(SYNC_MEETINGRESPONSE_CALENDARID);
1328                    $encoder->content($calendarid);
1329                $encoder->endTag();
1330            }
1331
1332        $encoder->endTag();
1333    }
1334
1335    $encoder->endTag();
1336
1337    return true;
1338}
1339
1340
1341function HandleFolderUpdate($backend, $protocolversion) {
1342    return HandleFolderCreate($backend, $protocolversion);
1343}
1344
1345function HandleFolderDelete($backend, $protocolversion) {
1346    return HandleFolderCreate($backend, $protocolversion);
1347}
1348
1349function HandleProvision($backend, $devid, $protocolversion) {
1350    global $user, $auth_pw, $policykey;
1351
1352    global $zpushdtd, $policies;
1353    global $output, $input;
1354
1355    $status = SYNC_PROVISION_STATUS_SUCCESS;
1356
1357    $phase2 = true;
1358
1359    $decoder = new WBXMLDecoder($input, $zpushdtd);
1360    $encoder = new WBXMLEncoder($output, $zpushdtd);
1361
1362    if(!$decoder->getElementStartTag(SYNC_PROVISION_PROVISION))
1363        return false;
1364
1365    //handle android remote wipe.
1366    if ($decoder->getElementStartTag(SYNC_PROVISION_REMOTEWIPE)) {
1367        if(!$decoder->getElementStartTag(SYNC_PROVISION_STATUS))
1368            return false;
1369
1370        $status = $decoder->getElementContent();
1371
1372        if(!$decoder->getElementEndTag())
1373            return false;
1374
1375        if(!$decoder->getElementEndTag())
1376            return false;
1377    }
1378
1379    else {
1380
1381        if(!$decoder->getElementStartTag(SYNC_PROVISION_POLICIES))
1382            return false;
1383
1384        if(!$decoder->getElementStartTag(SYNC_PROVISION_POLICY))
1385            return false;
1386
1387        if(!$decoder->getElementStartTag(SYNC_PROVISION_POLICYTYPE))
1388            return false;
1389
1390        $policytype = $decoder->getElementContent();
1391        if ($policytype != 'MS-WAP-Provisioning-XML') {
1392            $status = SYNC_PROVISION_STATUS_SERVERERROR;
1393        }
1394        if(!$decoder->getElementEndTag()) //policytype
1395            return false;
1396
1397        if ($decoder->getElementStartTag(SYNC_PROVISION_POLICYKEY)) {
1398            $devpolicykey = $decoder->getElementContent();
1399
1400            if(!$decoder->getElementEndTag())
1401                return false;
1402
1403            if(!$decoder->getElementStartTag(SYNC_PROVISION_STATUS))
1404                return false;
1405
1406            $status = $decoder->getElementContent();
1407            //do status handling
1408            $status = SYNC_PROVISION_STATUS_SUCCESS;
1409
1410            if(!$decoder->getElementEndTag())
1411                return false;
1412
1413            $phase2 = false;
1414        }
1415
1416        if(!$decoder->getElementEndTag()) //policy
1417            return false;
1418
1419        if(!$decoder->getElementEndTag()) //policies
1420            return false;
1421
1422        if ($decoder->getElementStartTag(SYNC_PROVISION_REMOTEWIPE)) {
1423            if(!$decoder->getElementStartTag(SYNC_PROVISION_STATUS))
1424                return false;
1425
1426            $status = $decoder->getElementContent();
1427
1428            if(!$decoder->getElementEndTag())
1429                return false;
1430
1431            if(!$decoder->getElementEndTag())
1432                return false;
1433        }
1434    }
1435    if(!$decoder->getElementEndTag()) //provision
1436        return false;
1437
1438    $encoder->StartWBXML();
1439
1440    //set the new final policy key in the backend
1441    if (!$phase2) {
1442        $policykey = $backend->generatePolicyKey();
1443        $backend->setPolicyKey($policykey, $devid);
1444    }
1445
1446    $encoder->startTag(SYNC_PROVISION_PROVISION);
1447    {
1448        $encoder->startTag(SYNC_PROVISION_STATUS);
1449            $encoder->content($status);
1450        $encoder->endTag();
1451
1452        $encoder->startTag(SYNC_PROVISION_POLICIES);
1453            $encoder->startTag(SYNC_PROVISION_POLICY);
1454
1455            $encoder->startTag(SYNC_PROVISION_POLICYTYPE);
1456                   $encoder->content($policytype);
1457            $encoder->endTag();
1458
1459            $encoder->startTag(SYNC_PROVISION_STATUS);
1460                $encoder->content($status);
1461            $encoder->endTag();
1462
1463            $encoder->startTag(SYNC_PROVISION_POLICYKEY);
1464                   $encoder->content($policykey);
1465            $encoder->endTag();
1466
1467            if ($phase2) {
1468                $encoder->startTag(SYNC_PROVISION_DATA);
1469                if ($policytype == 'MS-WAP-Provisioning-XML') {
1470                    $encoder->content('<wap-provisioningdoc><characteristic type="SecurityPolicy"><parm name="4131" value="1"/><parm name="4133" value="1"/></characteristic></wap-provisioningdoc>');
1471                }
1472                else {
1473                    debugLog("Wrong policy type");
1474                    return false;
1475                }
1476
1477                $encoder->endTag();//data
1478            }
1479            $encoder->endTag();//policy
1480        $encoder->endTag(); //policies
1481    }
1482    $rwstatus = $backend->getDeviceRWStatus($user, $auth_pw, $devid);
1483
1484
1485    //wipe data if status is pending or wiped
1486    if ($rwstatus == SYNC_PROVISION_RWSTATUS_PENDING || $rwstatus == SYNC_PROVISION_RWSTATUS_WIPED) {
1487        $encoder->startTag(SYNC_PROVISION_REMOTEWIPE, false, true);
1488        $backend->setDeviceRWStatus($user, $auth_pw, $devid, SYNC_PROVISION_RWSTATUS_WIPED);
1489        //$rwstatus = SYNC_PROVISION_RWSTATUS_WIPED;
1490    }
1491
1492    $encoder->endTag();//provision
1493
1494    return true;
1495}
1496
1497
1498function HandleSearch($backend, $devid, $protocolversion) {
1499    global $zpushdtd;
1500    global $input, $output;
1501
1502    $searchrange = '0';
1503
1504    $decoder = new WBXMLDecoder($input, $zpushdtd);
1505    $encoder = new WBXMLEncoder($output, $zpushdtd);
1506
1507    if(!$decoder->getElementStartTag(SYNC_SEARCH_SEARCH))
1508        return false;
1509
1510    if(!$decoder->getElementStartTag(SYNC_SEARCH_STORE))
1511        return false;
1512
1513    if(!$decoder->getElementStartTag(SYNC_SEARCH_NAME))
1514        return false;
1515    $searchname = $decoder->getElementContent();
1516    if(!$decoder->getElementEndTag())
1517        return false;
1518
1519    if(!$decoder->getElementStartTag(SYNC_SEARCH_QUERY))
1520        return false;
1521    $searchquery = $decoder->getElementContent();
1522    if(!$decoder->getElementEndTag())
1523        return false;
1524
1525    if($decoder->getElementStartTag(SYNC_SEARCH_OPTIONS)) {
1526        while(1) {
1527            if($decoder->getElementStartTag(SYNC_SEARCH_RANGE)) {
1528                $searchrange = $decoder->getElementContent();
1529                if(!$decoder->getElementEndTag())
1530                    return false;
1531                }
1532                $e = $decoder->peek();
1533                if($e[EN_TYPE] == EN_TYPE_ENDTAG) {
1534                    $decoder->getElementEndTag();
1535                    break;
1536                }
1537            }
1538        //if(!$decoder->getElementEndTag())
1539            //return false;
1540    }
1541    if(!$decoder->getElementEndTag()) //store
1542        return false;
1543
1544    if(!$decoder->getElementEndTag()) //search
1545        return false;
1546
1547
1548    if (strtoupper($searchname) != "GAL") {
1549        debugLog("Searchtype $searchname is not supported");
1550        return false;
1551    }
1552    //get search results from backend
1553    $rows = $backend->getSearchResults($searchquery, $searchrange);
1554
1555    $encoder->startWBXML();
1556
1557    $encoder->startTag(SYNC_SEARCH_SEARCH);
1558
1559        $encoder->startTag(SYNC_SEARCH_STATUS);
1560        $encoder->content(1);
1561        $encoder->endTag();
1562
1563        $encoder->startTag(SYNC_SEARCH_RESPONSE);
1564            $encoder->startTag(SYNC_SEARCH_STORE);
1565
1566                $encoder->startTag(SYNC_SEARCH_STATUS);
1567                $encoder->content(1);
1568                $encoder->endTag();
1569
1570                if (is_array($rows) && !empty($rows)) {
1571                    $searchrange = $rows['range'];
1572                    unset($rows['range']);
1573                    foreach ($rows as $u) {
1574                        $encoder->startTag(SYNC_SEARCH_RESULT);
1575                            $encoder->startTag(SYNC_SEARCH_PROPERTIES);
1576
1577                                $encoder->startTag(SYNC_GAL_DISPLAYNAME);
1578                                $encoder->content($u["fullname"]);
1579                                $encoder->endTag();
1580
1581                                $encoder->startTag(SYNC_GAL_PHONE);
1582                                $encoder->content($u["businessphone"]);
1583                                $encoder->endTag();
1584
1585                                $encoder->startTag(SYNC_GAL_ALIAS);
1586                                $encoder->content($u["username"]);
1587                                $encoder->endTag();
1588
1589                                //it's not possible not get first and last name of an user
1590                                //from the gab and user functions, so we just set fullname
1591                                //to lastname and leave firstname empty because nokia needs
1592                                //first and lastname in order to display the search result
1593                                $encoder->startTag(SYNC_GAL_FIRSTNAME);
1594                                $encoder->content("");
1595                                $encoder->endTag();
1596
1597                                $encoder->startTag(SYNC_GAL_LASTNAME);
1598                                $encoder->content($u["fullname"]);
1599                                $encoder->endTag();
1600
1601                                $encoder->startTag(SYNC_GAL_EMAILADDRESS);
1602                                $encoder->content($u["emailaddress"]);
1603                                $encoder->endTag();
1604
1605                            $encoder->endTag();//result
1606                        $encoder->endTag();//properties
1607                    }
1608                    $encoder->startTag(SYNC_SEARCH_RANGE);
1609                    $encoder->content($searchrange);
1610                    $encoder->endTag();
1611
1612                    $encoder->startTag(SYNC_SEARCH_TOTAL);
1613                    $encoder->content(count($rows));
1614                    $encoder->endTag();
1615                }
1616
1617            $encoder->endTag();//store
1618        $encoder->endTag();//response
1619    $encoder->endTag();//search
1620
1621
1622    return true;
1623}
1624
1625function HandleRequest($backend, $cmd, $devid, $protocolversion) {
1626    switch($cmd) {
1627        case 'Sync':
1628            $status = HandleSync($backend, $protocolversion, $devid);
1629            break;
1630        case 'SendMail':
1631            $status = HandleSendMail($backend, $protocolversion);
1632            break;
1633        case 'SmartForward':
1634            $status = HandleSmartForward($backend, $protocolversion);
1635            break;
1636        case 'SmartReply':
1637            $status = HandleSmartReply($backend, $protocolversion);
1638            break;
1639        case 'GetAttachment':
1640            $status = HandleGetAttachment($backend, $protocolversion);
1641            break;
1642        case 'GetHierarchy':
1643            $status = HandleGetHierarchy($backend, $protocolversion, $devid);
1644            break;
1645        case 'CreateCollection':
1646            $status = HandleCreateCollection($backend, $protocolversion);
1647            break;
1648        case 'DeleteCollection':
1649            $status = HandleDeleteCollection($backend, $protocolversion);
1650            break;
1651        case 'MoveCollection':
1652            $status = HandleMoveCollection($backend, $protocolversion);
1653            break;
1654        case 'FolderSync':
1655            $status = HandleFolderSync($backend, $protocolversion);
1656            break;
1657        case 'FolderCreate':
1658            $status = HandleFolderCreate($backend, $protocolversion);
1659            break;
1660        case 'FolderDelete':
1661            $status = HandleFolderDelete($backend, $protocolversion);
1662            break;
1663        case 'FolderUpdate':
1664            $status = HandleFolderUpdate($backend, $protocolversion);
1665            break;
1666        case 'MoveItems':
1667            $status = HandleMoveItems($backend, $protocolversion);
1668            break;
1669        case 'GetItemEstimate':
1670            $status = HandleGetItemEstimate($backend, $protocolversion, $devid);
1671            break;
1672        case 'MeetingResponse':
1673            $status = HandleMeetingResponse($backend, $protocolversion);
1674            break;
1675        case 'Notify': // Used for sms-based notifications (pushmail)
1676            $status = HandleNotify($backend, $protocolversion);
1677            break;
1678        case 'Ping': // Used for http-based notifications (pushmail)
1679            $status = HandlePing($backend, $devid, $protocolversion);
1680            break;
1681        case 'Provision':
1682            $status = (PROVISIONING === true) ? HandleProvision($backend, $devid, $protocolversion) : false;
1683            break;
1684        case 'Search':
1685            $status = HandleSearch($backend, $devid, $protocolversion);
1686            break;
1687
1688        default:
1689            debugLog("unknown command - not implemented");
1690            $status = false;
1691            break;
1692    }
1693
1694    return $status;
1695}
1696
1697function readStream(&$input) {
1698    $s = "";
1699
1700    while(1) {
1701        $data = fread($input, 4096);
1702        if(strlen($data) == 0)
1703            break;
1704        $s .= $data;
1705    }
1706
1707    return $s;
1708}
1709
1710?>
Note: See TracBrowser for help on using the repository browser.