? SyncML/ResultsSender.php
? SyncML/Device/Synthesis.php
Index: package.xml
===================================================================
RCS file: /repository/framework/SyncML/package.xml,v
retrieving revision 1.8
diff -u -r1.8 package.xml
--- package.xml	12 Jun 2005 20:10:06 -0000	1.8
+++ package.xml	16 Jun 2005 11:40:16 -0000
@@ -38,9 +38,12 @@
            <file name="P800.php"/>
            <file name="Sync4j.php"/>
            <file name="Template.php"/>
+           <file name="Synthesis.php"/>
         </dir>
         <file name="Constants.php"/>
         <file name="DeviceInfo.php"/>
+        
+        <file name="ResultsSender.php"/>
 
         <file name="Command.php"/>
         <dir name="Command">
Index: SyncML/Device.php
===================================================================
RCS file: /repository/framework/SyncML/SyncML/Device.php,v
retrieving revision 1.4
diff -u -r1.4 Device.php
--- SyncML/Device.php	28 May 2005 04:24:53 -0000	1.4
+++ SyncML/Device.php	16 Jun 2005 11:40:16 -0000
@@ -59,7 +59,10 @@
             && stristr($di->_Man, 'Sony Ericsson') !== false) {
             include_once 'Horde/SyncML/Device/P800.php';
             $cmd = &new SyncML_Device_P800();
-
+        } else if (!empty($di->_Man)
+            && stristr($di->_Man, 'synthesis') !== false ) {
+            include_once 'Horde/SyncML/Device/Synthesis.php';
+            $cmd = &new SyncML_Device_Synthesis();
         } else {
             $cmd = &new SyncML_Device();
         }
@@ -170,7 +173,7 @@
         if (DEBUGLOG_ICALENDARDATA == true) {
             $fp = @fopen('/tmp/sync/log.txt', 'a');
             if ($fp) {
-                @fwrite($fp, "\ninput received from client\n");
+                @fwrite($fp, "\ninput received from client ($contentType)\n");
                 if (strstr($contentType,'sif/') !== false) {
                     // sync4fj sif/* data is base64_encoded
                     @fwrite ($fp, base64_decode($content) . "\n");
Index: SyncML/State.php
===================================================================
RCS file: /repository/framework/SyncML/SyncML/State.php,v
retrieving revision 1.24
diff -u -r1.24 State.php
--- SyncML/State.php	1 May 2005 18:06:56 -0000	1.24
+++ SyncML/State.php	16 Jun 2005 11:40:16 -0000
@@ -62,7 +62,10 @@
     
     var $_deviceInfo; // deviceInfo provided by the SyncML DevInf data.
                       // mainly used by the SyncML_Device class
-    
+
+    var $_expectedResponse = array(); // If we are expecting a response packet,
+                                      // this stores where to route it
+				      
     /**
      * Creates a new instance of Horde_SyncML_State.
      */
@@ -280,4 +283,43 @@
         return SyncML_Device::singleton();
     }
 
+    /** 
+     * Returns the expected result type for a Results tag, used
+     * to redirect the incoming command somewhere special.  For 
+     * example, if we have requested device info, the Results tag
+     * should be sent to the Put command so we can read it in.
+     *
+     * Clears the hash of this Command Reference before returning
+     * a value.
+     *
+     * @access public
+     *
+     * @param integer $cmdRef  The CmdRef of the incoming command
+     *
+     * @return string         The command type to redirect to, or
+     *                        undefined if no redirect registered.
+     */
+    function getExpectedResultType($cmdRef)
+    {
+        if ( isset($this->_expectedResponse[$cmdRef]) ) {
+            $cmdType = $this->_expectedResponse[$cmdRef];
+            unset($this->_expectedResponse[$cmdRef]);
+        }
+        return $cmdType;
+    }
+
+    /**
+     * Sets up a command redirection for a future Result command.
+     * 
+     * @access public
+     *
+     * @param integer $cmdID    The CmdID of the command we are sending to
+     *                          the client.
+     * @param string  $cmdType  The type of command to redirect to when
+     *                          the Results command is received.
+     */
+    function setExpectedResultType($cmdID, $cmdType)
+    {
+        $this->_expectedResponse[$cmdID] = $cmdType;
+    }
 }
Index: SyncML/Command/Final.php
===================================================================
RCS file: /repository/framework/SyncML/SyncML/Command/Final.php,v
retrieving revision 1.13
diff -u -r1.13 Final.php
--- SyncML/Command/Final.php	24 Apr 2005 12:09:02 -0000	1.13
+++ SyncML/Command/Final.php	16 Jun 2005 11:40:16 -0000
@@ -22,8 +22,50 @@
     function output($currentCmdID, &$output)
     {
         $state = & $_SESSION['SyncML.state'];
-
         $attrs = array();
+
+        //Nathan P Sharp: If the client hasn't sent us device info,
+        //Request it now.
+        $di = SyncML_Device::deviceInfo();
+        if ((!isset($di)) ||  (empty($di->_Man))) {
+            $output->startElement($state->getURI(), 'Get', $attrs);
+
+            $output->startElement($state->getURI(), 'CmdID', $attrs);
+            $chars = $currentCmdID;
+            $output->characters($chars);
+            $output->endElement($state->getURI(), 'CmdID');
+
+
+            $output->startElement($state->getURI(), 'Meta', $attrs);
+            $attrs[] = array(
+                'attribute'=>'xmlns',
+                'value'    =>'syncml:metinf'
+            );
+            $output->startElement($state->getURI(), 'Type', $attrs);
+            $attrs = array();
+            $chars = 'application/vnd.syncml-devinf+xml';
+            $output->characters($chars);
+            $output->endElement($state->getURI(), 'Type');
+            $output->endElement($state->getURI(), 'Meta');
+
+            $output->startElement($state->getURI(), 'Item', $attrs);
+            $output->startElement($state->getURI(), 'Target', $attrs);
+            $output->startElement($state->getURI(), 'LocURI', $attrs);
+            $chars = './devinf11';
+            $output->characters($chars);
+            $output->endElement($state->getURI(), 'LocURI');
+            $output->endElement($state->getURI(), 'Target');
+            $output->endElement($state->getURI(), 'Item');
+
+            $output->endElement($state->getURI(), 'Get');
+
+            //Mark this id down as needing a results packet
+            //routed to the Put command.
+            $state->setExpectedResultType($currentCmdID, 'Put');
+
+            $currentCmdID++;
+        }
+
         $output->startElement($state->getURI(), 'Final', $attrs);
 
         $output->endElement($state->getURI(), 'Final');
Index: SyncML/Command/Get.php
===================================================================
RCS file: /repository/framework/SyncML/SyncML/Command/Get.php,v
retrieving revision 1.17
diff -u -r1.17 Get.php
--- SyncML/Command/Get.php	24 Apr 2005 12:09:02 -0000	1.17
+++ SyncML/Command/Get.php	16 Jun 2005 11:40:16 -0000
@@ -2,7 +2,7 @@
 
 include_once 'Horde/SyncML/State.php';
 include_once 'Horde/SyncML/Command.php';
-include_once 'Horde/SyncML/Command/Results.php';
+include_once 'Horde/SyncML/ResultsSender.php';
 
 define('DEFAULT_DEFINF', '<DevInf xmlns="syncml:devinf"><VerDTD>1.0</VerDTD><Man>The Horde Framework</Man><DevID>4711</DevID><DevTyp>workstation</DevTyp><DataStore><SourceRef>addressbook</SourceRef><Rx-Pref><CTType>text/x-vcard</CTType><VerCT>2.1</VerCT></Rx-Pref><Tx-Pref><CTType>text/x-vcard</CTType><VerCT>2.1</VerCT></Tx-Pref><SyncCap><SyncType>1</SyncType><SyncType>7</SyncType></SyncCap></DataStore><DataStore><SourceRef>calendar</SourceRef><Rx-Pref><CTType>text/calendar</CTType><VerCT>2.0</VerCT></Rx-Pref><Rx><CTType>text/x-vcalendar</CTType><VerCT>1.0</VerCT></Rx><Tx-Pref><CTType>text/calendar</CTType><VerCT>2.0</VerCT></Tx-Pref><Tx><CTType>text/x-vcalendar</CTType><VerCT>1.0</VerCT></Tx><SyncCap><SyncType>1</SyncType><SyncType>7</SyncType></SyncCap></DataStore><CTCap><CTType>text/x-vcalendar</CTType><PropName>BEGIN</PropName><ValEnum>VCALENDAR</ValEnum><ValEnum>VEVENT</ValEnum><ValEnum>VTODO</ValEnum><PropName>DTSTART</PropName><PropName>DTEND</PropName><PropName>DTSTAMP</PropName><PropName>SEQUENCE</PropName><PropName>END</PropName><ValEnum>VCALENDAR</ValEnum><ValEnum>VEVENT</ValEnum><ValEnum>VTODO</ValEnum><PropName>UID</PropName><PropName>SUMMARY</PropName><PropName>VERSION</PropName><ValEnum>1.0</ValEnum><PropName>AALARM</PropName><PropName>CATEGORIES</PropName><PropName>CLASS</PropName><PropName>DALARM</PropName><PropName>EXDATE</PropName><PropName>RESOURCES</PropName><PropName>STATUS</PropName><PropName>ATTACH</PropName><PropName>ATTENDEE</PropName><PropName>DCREATED</PropName><PropName>COMPLETED</PropName><PropName>DESCRIPTION</PropName><PropName>DUE</PropName><PropName>LAST-MODIFIED</PropName><PropName>LOCATION</PropName><PropName>PRIORITY</PropName><PropName>RELATED-TO</PropName><PropName>RRULE</PropName><PropName>TRANSP</PropName><PropName>URL</PropName></CTCap><CTCap><CTType>text/calendar</CTType><PropName>BEGIN</PropName><ValEnum>VCALENDAR</ValEnum><ValEnum>VEVENT</ValEnum><ValEnum>VTODO</ValEnum><ValEnum>VALARM</ValEnum><PropName>DTSTART</PropName><PropName>DTEND</PropName><PropName>DTSTAMP</PropName><PropName>SEQUENCE</PropName><PropName>END</PropName><ValEnum>VCALENDAR</ValEnum><ValEnum>VEVENT</ValEnum><ValEnum>VTODO</ValEnum><ValEnum>VALARM</ValEnum><PropName>UID</PropName><PropName>SUMMARY</PropName><PropName>VERSION</PropName><ValEnum>2.0</ValEnum><PropName>CATEGORIES</PropName><PropName>CLASS</PropName><PropName>DALARM</PropName><PropName>EXDATE</PropName><PropName>RESOURCES</PropName><PropName>STATUS</PropName><PropName>ATTACH</PropName><PropName>ATTENDEE</PropName><PropName>DCREATED</PropName><PropName>COMPLETED</PropName><PropName>DESCRIPTION</PropName><PropName>DUE</PropName><PropName>LAST-MODIFIED</PropName><PropName>LOCATION</PropName><PropName>PRIORITY</PropName><PropName>RELATED-TO</PropName><PropName>TRANSP</PropName><PropName>URL</PropName><PropName>RRULE</PropName><PropName>COMMMENT</PropName><PropName>ACTION</PropName><PropName>TRIGGER</PropName><PropName>DURATION</PropName><PropName>REPEAT</PropName></CTCap><CTCap><CTType>text/x-vcard</CTType><PropName>BEGIN</PropName><ValEnum>VCARD</ValEnum><PropName>END</PropName><ValEnum>VCARD</ValEnum><PropName>VERSION</PropName><ValEnum>2.1</ValEnum><PropName>ENCODING</PropName><PropName>VALUE</PropName><PropName>CHARSET</PropName><PropName>FN</PropName><PropName>N</PropName><PropName>NAME</PropName><PropName>NICKNAME</PropName><PropName>PHOTO</PropName><PropName>BDAY</PropName><PropName>ADR</PropName><PropName>LABEL</PropName><PropName>TEL</PropName><PropName>EMAIL</PropName><PropName>MAILER</PropName><PropName>TZ</PropName><PropName>GEO</PropName><PropName>TITLE</PropName><PropName>ROLE</PropName><PropName>LOGO</PropName><PropName>AGENT</PropName><PropName>ORG</PropName><PropName>CATEGORIES</PropName><PropName>NOTE</PropName><PropName>PRODID</PropName><PropName>REV</PropName><PropName>SORT-STRING</PropName><PropName>SOUND</PropName><PropName>URL</PropName><PropName>UID</PropName><PropName>CLASS</PropName><PropName>KEY</PropName></CTCap></DevInf>');
 
@@ -40,7 +40,7 @@
         if ($state->isAuthorized() && $state->getVersion() == 0) {
             // Synthesis does not like this one.
 
-            $results = &new Horde_SyncML_Command_Results();
+            $results = &new ResultsSender();
             $results->setCmdRef($this->_cmdID);
             $results->setType("application/vnd.syncml-devinf+xml");
             $results->setlocSourceURI($ref);
Index: SyncML/Command/Results.php
===================================================================
RCS file: /repository/framework/SyncML/SyncML/Command/Results.php,v
retrieving revision 1.14
diff -u -r1.14 Results.php
--- SyncML/Command/Results.php	24 Apr 2005 12:09:02 -0000	1.14
+++ SyncML/Command/Results.php	16 Jun 2005 11:40:16 -0000
@@ -11,108 +11,106 @@
  * See the enclosed file COPYING for license information (LGPL). If you
  * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  *
- * @author  Anthony Mills <amills@pyramid6.com>
+ * @author  Nathan P Sharp
  * @since   Horde 3.0
  * @package Horde_SyncML
  */
 class Horde_SyncML_Command_Results extends Horde_SyncML_Command
 {
+    var $_subCommand;
+    var $_savedUri;
+    var $_savedElement;
+    var $_savedAttrs;
+    var $_savedCmdID;
 
-    var $_cmdRef;
-    var $_type;
-    var $_data;
-    var $_locSourceURI;
+    var $_chars;
 
-    function output($currentCmdID, &$output)
+    function startElement($uri, $element, $attrs)
     {
-        $state = & $_SESSION['SyncML.state'];
-
-        $attrs = array();
-        $output->startElement($state->getURI(), 'Results', $attrs);
-
-        $output->startElement($state->getURI(), 'CmdID', $attrs);
-        $chars = $currentCmdID;
-        $output->characters($chars);
-        $output->endElement($state->getURI(), 'CmdID');
-
-        $output->startElement($state->getURI(), 'MsgRef', $attrs);
-        $chars = $state->getMsgID();
-        $output->characters($chars);
-        $output->endElement($state->getURI(), 'MsgRef');
-
-        $output->startElement($state->getURI(), 'CmdRef', $attrs);
-        $chars = $this->_cmdRef;
-        $output->characters($chars);
-        $output->endElement($state->getURI(), 'CmdRef');
-
-        $output->startElement($state->getURI(), 'Meta', $attrs);
-        $output->startElement($state->getURIMeta(), 'Type', $attrs);
-        $output->characters($this->_type);
-        $output->endElement($state->getURIMeta(), 'Type');
-        $output->endElement($state->getURI(), 'Meta');
-
-        $output->startElement($state->getURI(), 'Item', $attrs);
-        $output->startElement($state->getURI(), 'Source', $attrs);
-        $output->startElement($state->getURI(), 'LocURI', $attrs);
-        $chars = $this->_locSourceURI;
-        $output->characters($chars);
-        $output->endElement($state->getURI(), 'LocURI');
-        $output->endElement($state->getURI(), 'Source');
-
-        $output->startElement($state->getURI(), 'Data', $attrs);
-
-        // Need to send this information as opaque data so the WBXML
-        // will understand it.
-        $output->opaque($this->_data);
-
-        $output->endElement($state->getURI(), 'Data');
-        $output->endElement($state->getURI(), 'Item');
-
-        $output->endElement($state->getURI(), 'Results');
-
-        $currentCmdID++;
+        parent::startElement($uri, $element, $attrs);
 
-        return $currentCmdID;
+        switch (count($this->_Stack)) {
+        case 1:
+            //Save the info, we may have to re-send this startElement
+            //to the sub-command later
+            $this->_savedUri = $uri;
+            $this->_savedElement = $element;
+            $this->_savedAttrs = $attrs;
+            break;
+        }
+        if ( isset($this->_subCommand) ) {
+            $this->_subCommand->startElement($uri, $element, $attrs);
+        }
     }
 
-    /**
-     * Setter for property cmdRef.
-     *
-     * @param string $cmdRef  New value of property cmdRef.
-     */
-    function setCmdRef($cmdRef)
+    function endElement($uri, $element)
     {
-        $this->_cmdRef = $cmdRef;
-    }
+        switch (count($this->_Stack)) {
+        case 2:
+            if ($element == 'CmdID' && ! isset($this->_subCommand)) {
+                $this->_savedCmdID = intval(trim($this->_chars));
+            }
+            if ($element == 'CmdRef') {
+                $cmdRef = intval(trim($this->_chars));
+                $state = & $_SESSION['SyncML.state'];
+                //If this result packet is related to something
+                //and needs to be routed to a particular command
+                //object, do it now.
+                $cmdType = $state->getExpectedResultType($cmdRef);
+                if ( ! empty($cmdType) ) {
+                    $this->_subCommand =
+                           Horde_SyncML_Command::factory($cmdType);
+                    //NPS: This really isn't totally technically correct
+                    //because the XML could have been out of order and
+                    //we might have missed some stuff, but in reality,
+                    //I doubt it'll happen.
+                    $this->_subCommand->startElement(
+                              $this->_savedUri,
+                              $this->_savedElement,
+                              $this->_savedAttrs);
+                    if ( isset($this->_savedCmdID) ) {
+                        //NPS: Shouldn't be accessing this private member
+                        $this->_subCommand->_cmdID = $this->_savedCmdID;
+                        break;
+                    }
+                }
+            }
+            //NPS: Intentional non-standard use of a switch statement.  It 
+            //should  fall through to default in all cases except where the
+            //break statement is above.
+        default:
+            if ( isset($this->_subCommand) ) {
+                $this->_subCommand->endElement($uri, $element);
+            }
+            break;
+        }
 
-    /**
-     * Setter for property Type.
-     *
-     * @param string $type  New value of property type.
-     */
-    function setType($type)
-    {
-        $this->_type = $type;
+        parent::endElement($uri, $element);
     }
 
-    /**
-     * Setter for property data.
-     *
-     * @param string $data  New value of property data.
-     */
-    function setData($data)
+    function characters($str)
     {
-        $this->_data = $data;
+    	   parent::characters($str);
+    	   if ( isset($this->_subCommand) ) {
+    	       $this->_subCommand->characters($str);
+         }
     }
 
-    /**
-     * Setter for property locSourceURI.
-     *
-     * @param string $locSourceURI  New value of property locSourceURI.
-     */
-    function setlocSourceURI($locSourceURI)
+    function output($currentCmdID, &$output )
     {
-        $this->_locSourceURI = $locSourceURI;
-    }
+        $state = & $_SESSION['SyncML.state'];
+
+        if ( isset ($this->_subCommand) ) {
+            //NPS: Note that the status packet the sub command will
+            //send will be technically incorrect due to this redirection.
+            return $this->_subCommand->output($currentCmdID, $output);
+        } else {
+            //NPS: I guess this might as well be in here, it is a results
+            //packet we didn't save any info on.
+            $status = &new Horde_SyncML_Command_Status(RESPONSE_OK, 'Results');
+            $status->setCmdRef($this->_cmdID);
 
+            return $status->output($currentCmdID, $output);
+        }
+    }
 }
