/// <summary> /// Called by ProcessResponseForXXX in order to respond to Status returned by server /// </summary> /// <param name="status">SyncMLStatus object which is part of syncml.</param> protected override void HandleServerStatus(SyncMLStatus status) { string statusCode = status.Data.Content; switch (statusCode) { case "207": //The user updated the same record on more than 1 devices if (status.SourceRefCollection.Count > 0) { string localID = status.SourceRefCollection[0].Content; string contactName = Facade.LocalDataSource.GetItemName(localID); string m = String.Format("When updating for {0}, the sync server found conflicts. Though the conflicts were resolved by the sync server through data merge, please manually check to ensure everything is OK.", contactName); Facade.DisplayOperationMessage(m); } break; case "402": Facade.DisplayOperationMessage("The server requires payment."); Facade.SoFarOK = false; break; case "511": // this is with the status for Hdr Facade.DisplayOperationMessage("Serious error with SyncHdr."); Facade.SoFarOK = false; break; default: break; } Debug.WriteLine("Status " + statusCode + ": " + GetStatusReport(status)); }
public void TestStatus() { XElement nav = XElement.Load(CaseFile("Status.xml")); SyncMLStatus f = SyncMLStatus.Create(nav); Assert.IsTrue(CompareXml(nav, f.Xml), f.Xml.ToString()); }
/// <summary> /// Called by ProcessResponseForXXX in order to create status for Alert returned by server. /// </summary> /// <param name="alert"></param> protected void PrepareStatusForReturnedAlert(SyncMLAlert alert) { switch (alert.Data.Content) { case "200": case "201": case "202": case "203": case "204": case "205": SyncMLStatus responseStatus = SyncMLStatus.Create(); //status.CmdID is not defined here, but only defined right before sending next message responseStatus.MsgRef.Content = ServerSyncML.Hdr.MsgID.Content; responseStatus.Data.Content = "200"; responseStatus.Cmd.Content = "Alert"; responseStatus.CmdRef.Content = alert.CmdID.Content; responseStatus.TargetRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLTargetRef>(Facade.ContactDataSourceAtServer)); responseStatus.SourceRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLSourceRef>(Facade.LocalDataSource.DataSourceName)); //Get alert anchor next SyncMLItem alertItem = alert.ItemCollection[0]; //assuming there's always one. SyncMLMeta alertItemMeta = alertItem.Meta; // assuming there's always one. MetaParser metaParser = new MetaParser(alertItemMeta.Xml); MetaAnchor alertAnchor = metaParser.GetMetaAnchor(); string alertAnchorNext = alertAnchor.Next.Content; SyncMLItem statusItem = SyncMLItem.Create(); MetaAnchor statusAnchor = MetaAnchor.Create(); statusAnchor.Next = SyncMLSimpleElementFactory.Create <MetaNext>(alertAnchorNext); statusItem.Data.Xml.Add(statusAnchor.Xml); responseStatus.ItemCollection.Add(statusItem); Facade.ResponseCommandPool.Add(responseStatus); break; case "100": //Show. The Data element type contains content information that should be processed and displayed through the user agent. string serverStatusMessage = alert.ItemCollection[0].Data.Content; Facade.DisplayOperationMessage(serverStatusMessage); SyncMLStatus statusFor100 = SyncMLStatus.Create(); statusFor100.MsgRef.Content = ServerSyncML.Hdr.MsgID.Content; statusFor100.Data.Content = "200"; statusFor100.Cmd.Content = "Alert"; statusFor100.CmdRef.Content = alert.CmdID.Content; Facade.ResponseCommandPool.Add(statusFor100); break; default: Trace.TraceInformation("Do not know what to do in PrepareStatusForReturnedAlert:"); Trace.TraceInformation(alert.Xml.ToString()); break; } }
protected override void HandleServerStatus(SyncMLStatus status) { string statusCode = status.Data.Content; Debug.WriteLine("Status " + statusCode + ": " + GetStatusReport(status)); switch (status.CmdRef.Content) { case "0": //Handle header authentication switch (statusCode) { case "212": Facade.DisplayOperationMessage("Log on to SyncML server successfully."); LoggedOn = true; AuthenticationStatus = SyncMLAuthenticationStatus.LoggedOn; MetaParser parser2 = new MetaParser(status.Chal.Meta.Xml); MetaType metaType2 = parser2.GetMetaType(); if (metaType2 != null) { if (metaType2.Content == "syncml:auth-basic") { AuthenticationStatus = SyncMLAuthenticationStatus.Base64Chal; Facade.AuthenticationTypeOfNextMessage = SyncMLAuthenticationType.Base64; } else if (metaType2.Content == "syncml:auth-md5") { AuthenticationStatus = SyncMLAuthenticationStatus.MD5Chal; MetaNextNonce nextNonce = parser2.GetMetaNextNonce(); Facade.Md5NextNonceFromServer = Convert.FromBase64String(nextNonce.Content); Facade.AuthenticationTypeOfNextMessage = SyncMLAuthenticationType.MD5; } else { AuthenticationStatus = SyncMLAuthenticationStatus.UnknownChal; } } break; case "407": case "401": MetaParser parser = new MetaParser(status.Chal.Meta.Xml); MetaType metaType = parser.GetMetaType(); if (metaType != null) { if (metaType.Content == "syncml:auth-basic") { AuthenticationStatus = SyncMLAuthenticationStatus.Base64Chal; } else if (metaType.Content == "syncml:auth-md5") { AuthenticationStatus = SyncMLAuthenticationStatus.MD5Chal; MetaNextNonce nextNonce = parser.GetMetaNextNonce(); Facade.Md5NextNonceFromServer = Convert.FromBase64String(nextNonce.Content); } else { AuthenticationStatus = SyncMLAuthenticationStatus.UnknownChal; } } else { AuthenticationStatus = SyncMLAuthenticationStatus.FailedID; } Facade.DisplayOperationMessage("Authentication rejected. Please check user name and password."); break; default: AuthenticationStatus = SyncMLAuthenticationStatus.UnknownStatus; Facade.DisplayOperationMessage("The server sent back unexpected status code: " + statusCode); Facade.SoFarOK = false; break; } break; case "1": //server status to the sync alert command switch (statusCode) { case "508": Trace.TraceInformation("Server wants slown sync."); // Facade.ResponseCommandPool.Add(CreateSyncAlert(SyncType.Slow)); break; case "200": break; default: if (statusCode == "404") { Trace.TraceInformation("The server does not have requested data store."); Facade.DisplayOperationMessage("The server does not have requested data store."); } Trace.TraceInformation(String.Format("Sync request is rejected. The server said: {0}", Facade.StatusMessages.GetMessage(statusCode))); Facade.SoFarOK = false; break; } break; case "2": // Handle response to previous Get if (statusCode == "200") { Trace.TraceInformation("Received server device information successfully."); } else { Facade.SoFarOK = false; } break; case "3": // Handle response to previous Put. if (statusCode == "200") { Trace.TraceInformation("The server received local device information successfully."); } else { Facade.SoFarOK = false; } break; default: Trace.TraceInformation("Unexpected CmdRef in Status."); Facade.SoFarOK = false; break; } }
protected string GetStatusReport(SyncMLStatus status) { return(String.Format("Status: {0} CmdRef: {1} Cmd: {2} " + Environment.NewLine + "{3}", status.Data.Content, status.CmdRef.Content, status.Cmd.Content, Facade.StatusMessages.GetMessage(status.Data.Content))); }
/// <summary> /// Called by ProcessResponseForXXX in order to respond to some Status returned by server /// </summary> /// <param name="status">SyncMLStatus object which is part of syncml.</param> protected abstract void HandleServerStatus(SyncMLStatus status);
/// <summary> /// Generate status commands for received Sync command, and put the commands into the pool. /// </summary> /// <param name="syncCommand">Sync command from the server.</param> private void GenerateStatusCommandsForSyncCommand(SyncMLSync syncCommand) { SyncMLStatus syncStatus = SyncMLStatus.Create(); syncStatus.Cmd.Content = "Sync"; syncStatus.CmdRef.Content = syncCommand.CmdID.Content; syncStatus.Data.Content = "200"; syncStatus.MsgRef.Content = ServerSyncML.Hdr.MsgID.Content; syncStatus.TargetRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLTargetRef>(syncCommand.Target.LocURI.Content)); syncStatus.SourceRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLSourceRef>(syncCommand.Source.LocURI.Content)); Facade.ResponseCommandPool.Add(syncStatus); Collection <SyncMLCommand> commands = syncCommand.Commands; if (commands != null) { foreach (SyncMLCommand command in commands) { SyncMLAdd addCommand = command as SyncMLAdd; if (addCommand != null) { SyncMLStatus addStatus = SyncMLStatus.Create(); addStatus.Cmd.Content = "Add"; addStatus.CmdRef.Content = command.CmdID.Content; addStatus.Data.Content = "200"; addStatus.MsgRef.Content = syncStatus.MsgRef.Content; addStatus.SourceRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLSourceRef>(addCommand.ItemCollection[0].Source.LocURI.Content)); Facade.ResponseCommandPool.Add(addStatus); continue; } SyncMLReplace replaceCommand = command as SyncMLReplace; if (replaceCommand != null) { SyncMLStatus replaceStatus = SyncMLStatus.Create(); replaceStatus.Cmd.Content = "Replace"; replaceStatus.CmdRef.Content = command.CmdID.Content; replaceStatus.Data.Content = "200"; replaceStatus.MsgRef.Content = syncStatus.MsgRef.Content; replaceStatus.TargetRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLTargetRef>(replaceCommand.ItemCollection[0].Target.LocURI.Content)); Facade.ResponseCommandPool.Add(replaceStatus); continue; } SyncMLDelete deleteCommand = command as SyncMLDelete; if (deleteCommand != null) { SyncMLStatus deleteStatus = SyncMLStatus.Create(); deleteStatus.Cmd.Content = "Delete"; deleteStatus.CmdRef.Content = command.CmdID.Content; deleteStatus.Data.Content = "200"; deleteStatus.MsgRef.Content = syncStatus.MsgRef.Content; deleteStatus.SourceRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLSourceRef>(deleteCommand.ItemCollection[0].Target.LocURI.Content)); Facade.ResponseCommandPool.Add(deleteStatus); continue; } } } }
protected override bool ProcessResponse(string text) { if (!base.ProcessResponse(text)) { return(false); } // So now syncml model is created from text UpdateCurrentURI(ServerSyncML); //0: Always have a status response to the SyncHdr of the server message. However, this status may not be sent back if it is the only one in the queue. SyncMLStatus responseStatus = SyncMLStatus.Create(); responseStatus.MsgRef.Content = ServerSyncML.Hdr.MsgID.Content; responseStatus.Data.Content = "200"; responseStatus.Cmd.Content = "SyncHdr"; responseStatus.CmdRef.Content = "0"; responseStatus.TargetRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLTargetRef>(ServerSyncML.Hdr.Target.LocURI.Content)); responseStatus.SourceRefCollection.Add(SyncMLSimpleElementFactory.Create <SyncMLSourceRef>(ServerSyncML.Hdr.Source.LocURI.Content)); Facade.ResponseCommandPool.Add(responseStatus);//respond in next request. //1: Handle returned status commands Collection <SyncMLStatus> serverStatusCommands = AccessBody.GetStatusCommands(ServerSyncML); foreach (SyncMLStatus status in serverStatusCommands) { CommandAndStatusRegister.RegisterStatus(status.CmdRef.Content, status.Data.Content); HandleServerStatus(status); //this fn is still abstract here. Derived classes have different ways of handling. } //2: Prepare status commands for returned Alert commands. Derived classes then handle the alerts all the same way. Collection <SyncMLAlert> serverAlertCommands = AccessBody.GetAlertCommands(ServerSyncML); foreach (SyncMLAlert alert in serverAlertCommands) { Debug.WriteLine("Alert:" + alert.Xml.ToString()); PrepareStatusForReturnedAlert(alert); } //3: Handle returned Sync command. Derived classes handle sync commands the same way. SyncMLSync serverSyncCommand = AccessBody.GetSyncCommand(ServerSyncML); if (serverSyncCommand != null) { string numberOfChangesStr = serverSyncCommand.NumberOfChanges.Content; if (!String.IsNullOrEmpty(numberOfChangesStr)) {//where numberOfChanges > 0, display progress bar in GUI. Facade.totalNumberOfChangesReceiving = Convert.ToInt32(numberOfChangesStr); if (Facade.totalNumberOfChangesReceiving > 0) { Facade.DisplayOperationMessage(String.Format("Total number of changes received from the server: {0}", numberOfChangesStr)); Facade.InitProgressBarReceiving(0, Facade.totalNumberOfChangesReceiving, 1); Facade.DisplayStageMessageReceiving(String.Format("Receiving {0} updates ...", Facade.totalNumberOfChangesReceiving)); } } int numbersOfChangesThisMessage = serverSyncCommand.Commands.Count; // the server might send in multiple messages Facade.numberOfChangesReceived += numbersOfChangesThisMessage; if (Facade.numberOfChangesReceived == Facade.totalNumberOfChangesReceiving) { Facade.DisplayStageMessageReceiving("Receiving Done"); } GenerateStatusCommandsForSyncCommand(serverSyncCommand); if (Facade.GracefulStop) { return(true); // simply return, ture of false is meaningless. } Facade.IncrementProgressBarReceiving(numbersOfChangesThisMessage); ApplySyncCommandToLocal(serverSyncCommand); } //4: Verify if the server return all status codes to commands sent if (!CommandAndStatusRegister.IsAllCommandsReturnedWithStatus()) { Trace.TraceInformation("!!!! Not all commands got status code. Please check the log for details."); Trace.TraceInformation("Commands without status: " + CommandAndStatusRegister.CommandsXmlWithoutStatus); //It is expected CommandAndStatusRegister is not used any more, otherwise, should clear it here. } //5: At the end, do what the server ask to do, likely a new SyncML message to be sent ProcessServerAlertCommands(serverAlertCommands); return(true); }
protected override void HandleServerStatus(SyncMLStatus status) { //do nothing, as not more work needs to be done. }