2 * Funambol is a mobile platform developed by Funambol, Inc.
3 * Copyright (C) 2003 - 2007 Funambol, Inc.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Affero General Public License version 3 as published by
7 * the Free Software Foundation with the addition of the following permission
8 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
9 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
10 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program; if not, see http://www.gnu.org/licenses or write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
23 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU Affero General Public License version 3.
29 * In accordance with Section 7(b) of the GNU Affero General Public License
30 * version 3, these Appropriate Legal Notices must retain the display of the
31 * "Powered by Funambol" logo. If the display of the logo is not reasonably
32 * feasible for technical reasons, the Appropriate Legal Notices must display
33 * the words "Powered by Funambol".
38 #include "base/Log.h" // TBR
39 #include "base/util/ArrayList.h"
40 #include "base/util/utils.h"
41 #include "spds/constants.h"
42 #include "spds/SyncMLProcessor.h"
43 #include "spds/spdsutils.h"
45 #include "event/FireEvent.h"
46 #include "base/globalsdef.h"
51 * This class is responsible for the processing of the incoming messages.
56 SyncMLProcessor::SyncMLProcessor() : XMLProcessor() {
59 SyncML* SyncMLProcessor::processMsg(char* msg) {
60 SyncML* syncml = Parser::getSyncML(msg);
65 int SyncMLProcessor::processSyncHdrStatus(SyncML* syncml) {
66 int ret = getStatusCode(syncml->getSyncBody(), NULL, SYNC_HDR);
68 // Fire Sync Status Event: syncHdr status from server
69 fireSyncStatusEvent(SYNC_HDR, ret, NULL, NULL, NULL , SERVER_STATUS);
74 int SyncMLProcessor::processAlertStatus(SyncSource& source, SyncML* syncml, ArrayList* alerts) {
77 const char* name = NULL;
80 SourceRef* sourceRef = NULL;
83 ArrayList* list = syncml->getSyncBody()->getCommands();
85 for (int i = 0; i < list->size(); i++) {
86 // is returned the pointer to the element not a new element
87 name = ((AbstractCommand*)(list->get(i)))->getName();
88 if (name && strcmp(name, STATUS) == 0) {
89 s = (Status*)list->get(i);
90 if (strcmp(s->getCmd(), ALERT) == 0) {
91 sourceRef = (SourceRef*)(s->getSourceRef()->get(0));
94 if (strcmp(_wcc(source.getName()),
95 sourceRef->getValue()) == 0) {
96 ret = getAlertStatusCode(s, _wcc(source.getName()));
100 // Server did not include <SourceRef>, which
101 // is a violation of the standard for commands
102 // which were sent with <SourceRef>. Happens
103 // with Synthesis server if authentication
104 // failed, in which case we can simply ignore
112 // Fire a syncStatus event: Alert status from server
113 fireSyncStatusEvent(ALERT, ret, source.getConfig().getName(), source.getConfig().getURI(), NULL, SERVER_STATUS);
121 * Processes the initialization response. Returns 0 in case of success, an
122 * error code in case of error.
124 * @param msg the response from the server
126 int SyncMLProcessor::processServerAlert(SyncSource& source, SyncML* syncml) {
130 AbstractCommand* a = NULL;
136 a = getCommand(syncml->getSyncBody(), ALERT, iterator);
138 // This happens with the Synthesis server's reply:
139 // instead of sending SyncBody/Alert we get SyncBody/Put
140 // with device infos and a SyncBody/Get requesting our own
141 // device infos. Ignoring the request is not correct, but
142 // allows synchronization to proceed and complete eventually
143 // without any further errors. For that to work we must not
144 // set lastErrorCode here, as it will be checked at the end of
147 // lastErrorCode = ERR_REPRESENTATION;
148 // sprintf(lastErrorMsg, "SyncBody/Alert not found!");
151 Alert* alert = (Alert*)a;
153 ArrayList* itemList = alert->getItems();
155 for (int i = 0; i < itemList->size(); i++) {
156 item = (Item*)getArrayElement(itemList, i);
157 const char *locURI = ((Target*)item->getTarget())->getLocURI();
158 if (strcmp( locURI, _wcc(source.getName()) ) == 0) {
159 if (alert->getData() == NULL) {
160 //lastErrorCode = ERR_REPRESENTATION;
161 //sprintf(lastErrorMsg, "SyncBody/Alert/Data not found!");
162 setError(ERR_REPRESENTATION, "SyncBody/Alert/Data not found!");
166 source.setSyncMode((SyncMode)alert->getData());
184 char** SyncMLProcessor::getSortedSourcesFromServer(SyncML* syncml, int sourcesNumber) {
186 char** sourceList = new char*[sourcesNumber+1];
188 AbstractCommand* a = NULL;
192 a = getCommand(syncml->getSyncBody(), ALERT, iterator);
196 Alert* alert = (Alert*)a;
198 ArrayList* itemList = alert->getItems();
200 for (int i = 0; i < itemList->size(); i++) {
201 item = (Item*)getArrayElement(itemList, i);
202 const char *locURI = ((Target*)item->getTarget())->getLocURI();
203 sourceList[iterator] = stringdup(locURI);
210 sourceList[iterator] = NULL;
217 int SyncMLProcessor::processItemStatus(SyncSource& source, SyncBody* syncBody) {
219 ArrayList* items = NULL;
221 SourceRef* sourceRef = NULL;
223 const char* name = NULL;
227 ArrayList* list = getCommands(syncBody, STATUS);
229 for (int i = 0; i < list->size(); i++) {
230 s = (Status*)list->get(i);
233 if (strcmp(name, SYNC) == 0){
234 char *srcname = toMultibyte(source.getName());
235 int alertStatus = getAlertStatusCode(s, srcname);
239 * Try to find if the server send a message together the error code if any
240 * The items in the status message should be always one...
242 char *statusMessage = NULL;
243 items = s->getItems();
244 for (int k = 0; k < items->size(); k++) {
245 item = (Item*)items->get(k);
247 ComplexData* cd = item->getData();
249 statusMessage = stringdup(cd->getData());
253 // Fire Sync Status Event: sync status from server
254 fireSyncStatusEvent(SYNC, s->getStatusCode(), source.getConfig().getName(), source.getConfig().getURI(), NULL, SERVER_STATUS);
256 if(alertStatus < 0 || alertStatus >=300){
258 //strcpy(lastErrorMsg, statusMessage);
259 setError( alertStatus, statusMessage);
261 //strcpy(lastErrorMsg, "Error in sync status sent by server.");
262 setError( alertStatus, "Error in sync status sent by server.");
264 if ((ret = alertStatus) < 0)
265 LOG.error("processItemStatus: status not found in SYNC");
267 LOG.error("processItemStatus: server sent status %d in SYNC", alertStatus);
271 delete [] statusMessage;
275 else if (strcmp(name, ADD) == 0 ||
276 strcmp(name, REPLACE) == 0 ||
277 strcmp(name, DEL) == 0) {
281 items = s->getItems();
282 long val = strtol(data->getData() , NULL, 10);
283 for (k = 0; k < items->size(); k++) {
284 item = (Item*)items->get(k);
286 Source* itemSource = item->getSource();
288 WCHAR *uri = toWideChar(itemSource->getLocURI());
290 ComplexData* cd = item->getData();
291 WCHAR *statusMessage = NULL;
293 statusMessage = toWideChar(cd->getData());
296 // Fire Sync Status Event: item status from server
297 fireSyncStatusEvent(s->getCmd(), s->getStatusCode(), source.getConfig().getName(), source.getConfig().getURI(), uri, SERVER_STATUS);
299 source.getReport()->addItem(SERVER, s->getCmd(), uri, s->getStatusCode(), statusMessage);
301 source.setItemStatus(uri, val, name);
304 delete [] statusMessage;
306 // the item might consist of additional information, as in:
307 // <SourceRef>pas-id-44B544A600000092</SourceRef>
309 // <Item><Data>Conflict resolved by server</Data></Item>
313 items = s->getSourceRef();
314 for (k = 0; k < items->size(); k++) {
315 sourceRef = (SourceRef*)items->get(k);
317 WCHAR *srcref = toWideChar(sourceRef->getValue());
318 // Fire Sync Status Event: item status from server
319 fireSyncStatusEvent(s->getCmd(), s->getStatusCode(), source.getConfig().getName(), source.getConfig().getURI(), srcref, SERVER_STATUS);
321 source.getReport()->addItem(SERVER, s->getCmd(), srcref, s->getStatusCode(), NULL);
323 source.setItemStatus(srcref, val, name);
330 //deleteArrayList(&list);
339 * Processes the initialization response. Returns 0 in case of success, an
340 * error code in case of error.
342 * @param msg the response from the server
345 Sync* SyncMLProcessor::processSyncResponse(SyncSource& source, SyncML* syncml) {
347 int iterator = 0, ret = 0;
349 AbstractCommand* a = NULL;
352 ret = getStatusCode(syncml->getSyncBody(), &source, SYNC_HDR);
353 if ((ret < 200) || (ret > 299)) {
357 while((a = getCommand(syncml->getSyncBody(), SYNC, iterator)) != NULL){
359 const char *locuri = ((Target*)(sync->getTarget()))->getLocURI();
360 if (strcmp(locuri, _wcc(source.getName())) == 0) {
363 // To handle the NumberOfChanges. The default is -1 that means the server doesn't send
364 // any tag <NumberOfChanges>. Whit value >= 0 the value is correct
367 long noc = sync->getNumberOfChanges();
368 fireSyncSourceEvent(source.getConfig().getURI(), source.getConfig().getName(), source.getSyncMode(), noc, SYNC_SOURCE_TOTAL_SERVER_ITEMS);
383 * Processes the map message response. Returns 0 in case of success, an
384 * error code in case of error.
385 * It feeds the given source with the server side modifications
387 * @param source the source
388 * @param msg the response from the server
390 int SyncMLProcessor::processMapResponse(SyncSource& source, SyncBody* syncBody) {
394 // for now it is always ok
397 // First of all check the status for the SyncHead
400 ret = getStatusCode(syncBody, &source, SYNC_HDR);
402 // Fire Sync Status Event: map status from server (TBD)
403 //fireSyncStatusEvent(MAP, ret, source.getConfig().getURI(), NULL, SERVER_STATUS);
405 if ((ret < 200) || (ret >299)) {
417 * Returns the SyncHeader/RespURI element of the given message. If the element is not
418 * found it returns NULL. The returned respURI is allocated with the new operator
419 * and must be discarded with delete by the caller.
421 * @param SyncHdr - the SyncHdr object - NOT NULL
423 const char* SyncMLProcessor::getRespURI(SyncHdr* syncHdr) {
425 char* respURI = NULL;
427 if (syncHdr == NULL) {
430 respURI = stringdup(syncHdr->getRespURI());
438 Chal* SyncMLProcessor::getChal(SyncBody* syncBody) {
440 ArrayList* list = syncBody->getCommands();
441 const char* name = NULL;
445 for (int i = 0; i < list->size(); i++) {
446 name = ((AbstractCommand*)(list->get(i)))->getName(); // is returned the pointer to the element not a new element
447 if (name && strcmp(name, STATUS) == 0) {
448 s = (Status*)list->get(i);
449 if (strcmp(s->getCmd(), SYNC_HDR) == 0) {
450 if (strcmp(s->getCmdRef(), "0") != 0) {
452 //sprintf(lastErrorMsg, "Status/CmdRef either not found or not referring to SyncHeader!");
453 //lastErrorCode = ERR_REPRESENTATION;
454 setError(ERR_REPRESENTATION, "Status/CmdRef either not found or not referring to SyncHeader!");
476 * Return an array list of commands of the given command name. It return an ArrayList that have to be
477 * discarded by the caller
479 ArrayList* SyncMLProcessor::getCommands(SyncBody* syncBody, const char*commandName) {
481 ArrayList* ret = new ArrayList();
482 AbstractCommand* a = NULL;
484 for (int i = 0; i < syncBody->getCommands()->size(); i++) {
485 a = getCommand(syncBody, commandName, i);
492 // ------------------------------------------------------------- Private methods
495 * To get a generic array element. It returns the <index> arrayElement it founds.
498 ArrayElement* SyncMLProcessor::getArrayElement(ArrayList* list, int index) {
503 ArrayElement* a = NULL;
505 for (int i = 0; i < list->size(); i++) {
506 if (count == index) {
516 * Return the index number of occurrence of this command. If doesn't exists return NULL;
517 * The first command has number 0.
519 AbstractCommand* SyncMLProcessor::getCommand(SyncBody* syncBody, const char*commandName, int index) {
521 int iterator = 0, found = 0;
522 ArrayList* list = syncBody->getCommands();
523 int l = list->size();
524 AbstractCommand* a = NULL;
525 const char* name = NULL;
527 a = (AbstractCommand*)getArrayElement(list, iterator);
529 name = a->getName(); // is returned the pointer to the element not a new element
530 if (name && strcmp(name, commandName) == 0) {
544 int SyncMLProcessor::getStatusCode(SyncBody* syncBody, SyncSource* source, const char*commandName) {
547 ArrayList* list = syncBody->getCommands();
548 const char* name = NULL;
552 for (int i = 0; i < list->size(); i++) {
553 name = ((AbstractCommand*)(list->get(i)))->getName(); // is returned the pointer to the element not a new element
554 if (name && strcmp(name, STATUS) == 0) {
555 s = (Status*)list->get(i);
556 if (strcmp(s->getCmd(), commandName) == 0) {
557 if (strcmp(commandName, SYNC_HDR) == 0) {
558 ret = getSyncHeaderStatusCode(s);
559 } else if (strcmp(commandName, ALERT) == 0) {
560 ret = getAlertStatusCode(s, (char*)source->getName());
568 //sprintf(lastErrorMsg, "Error reading status code of command '%s'", commandName);
569 //lastErrorCode = ERR_REPRESENTATION;
570 setErrorF(ERR_REPRESENTATION, "Error reading status code of command '%s'", commandName);
577 * Returns the status code for the SyncHeader command included
578 * in the message sent by the client.
580 * @param syncBody - the SyncBody content
582 int SyncMLProcessor::getSyncHeaderStatusCode(Status* s) {
590 if (strcmp(s->getCmdRef(), "0") != 0) {
592 //sprintf(lastErrorMsg, "Status/CmdRef either not found or not referring to SyncHeader!");
593 //lastErrorCode = ERR_REPRESENTATION;
594 setError(ERR_REPRESENTATION, "Status/CmdRef either not found or not referring to SyncHeader!");
599 if (data->getData() == NULL) {
601 // It should not happen
603 //sprintf(lastErrorMsg, "Status/Data not found!");
604 //lastErrorCode = ERR_REPRESENTATION;
605 setError(ERR_REPRESENTATION, "Status/Data not found!");
608 ret = strtol(data->getData() , NULL, 10);
617 * Returns the status code for the Alert relative to the given source.
619 * @param syncBody - the SyncBody content
620 * @param sourceName - the name of the source
623 int SyncMLProcessor::getAlertStatusCode(Status* s, const char* sourceName) {
630 ArrayList* sourceRefs = s->getSourceRef();
632 if (strcmp(((SourceRef*)(sourceRefs->get(0)))->getValue(), sourceName) == 0) {
634 if (data->getData() == NULL) {
636 // It should not happen
638 //sprintf(lastErrorMsg, "Status/Data not found!");
639 //lastErrorCode = ERR_REPRESENTATION;
640 setError(ERR_REPRESENTATION, "Status/Data not found!");
643 ret = strtol(data->getData(), NULL, 10);
650 * Processes the initialization response. Returns 0 in case of success, an
651 * error code in case of error.
653 * @param msg the response from the server
656 Sync* SyncMLProcessor::getSyncResponse(SyncML* syncml, int index) {
658 AbstractCommand* a = NULL;
661 a = getCommand(syncml->getSyncBody(), SYNC, index);