Bugs and Solutions

Apr 2, 2008 at 1:51 PM
Edited Apr 2, 2008 at 1:52 PM
Error: Cannot add a recipient with an empty or null name to a recipient collection.
this is caused by an entry in Google Calendar that does not have a name associated with an attendee, I use Google Calendar Sync to push up my work calendar to my Google Calendar, then use GMobileSync to download it to my PDA. When pusing up events from my work calendar it only sends the email address not the name to google calendar, I resolved this by modifying the participants section to:
#region Participants

if (entry.Participants != null)
{
int recipientCount = appointment.Recipients.Count;

// Remove all previous recipients
for (int n = 0; n < recipientCount; n++)
appointment.Recipients.Remove(0);

foreach (Who who in entry.Participants)
{
string Name = string.IsNullOrEmpty(who.ValueString) ? who.Email : who.ValueString;
Recipient recipient = new Recipient(Name, who.Email);

appointment.Recipients.Add(recipient);
}
}

#endregion
This works fine as long as you have a clean calendar on your pda, if you have entries on your PDA already you will run into the next error I have here because my pda email address is not the organizer of my work appointments it throws a different error, the code to resolve this error is going to be a bit more complicated if not impossible since its really the google calendar enforcing and it would need to be the one that assoiates 2 different emails as the same person.

The offset saving/loading bug can be fixed by modifying the form:
// Load previous settings
TimeSpan ts = new TimeSpan(0, 0, Convert.ToInt32(gMobileSync.UtcOffset * 3600));
cboUtcOffset.Text = string.Format("{0:##}.{1:00}", ts.Hours, ts.Minutes);
// cboUtcOffset.Text = string.Format("{0:n2}", ts.Hours + "." + ts.Minutes);
cboTimezone.Text = gMobileSync.Timezone;
cboSyncPreviousDays.Text = gMobileSync.SyncPreviousDays.ToString();
cboSyncFutureDays.Text = gMobileSync.SyncFutureDays.ToString();
chkExitOnComplete.Checked = gMobileSync.ExitOnSyncComplete;

I also tweaked the size of the timezone drop down it was annoying not being able to read it:
//
// cboTimezone
//
this.cboTimezone.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cboTimezone.Location = new System.Drawing.Point(72, 40);
this.cboTimezone.Name = "cboTimezone";
this.cboTimezone.Size = new System.Drawing.Size(147, 22);
this.cboTimezone.TabIndex = 1;

There is also another bug that I hadn't seen, I had an all day reoccuring event (not meeting) that when published up had the rrule section as the last line of the recurence text, well this doesn't include a \r\n so the parser as written wouldn't find it, it worked on all other events because they had a line after the rrule section. I solved that by changing this:
#region Recurrence

if (entry.Recurrence == null)
{
if(appointment.RecurrencePattern != null)
appointment.RecurrencePattern.Clear();
}
else
{
try
{
// string gcalRule = entry.Recurrence.Value;
Regex Splitter = new Regex("\r\n");
string[] RuleSet = Splitter.Split(entry.Recurrence.Value);
// string gcalRuleStart = "RRULE:";
// string gcalRuleEnd = "\r\n";
//int gcalRuleStartPos = gcalRule.IndexOf(gcalRuleStart) +
// gcalRuleStart.Length;
string dtstartLine = string.Empty;
string dtendLine = string.Empty;
string recurrLine = string.Empty;
for (int i = 0; i < RuleSet.Length; i++)
{
if (RuleSeti.StartsWith("DTSTART")) dtstartLine = RuleSeti;
if (RuleSeti.StartsWith("DTEND")) dtendLine = RuleSeti;
if (RuleSeti.StartsWith("RRULE:")) recurrLine = RuleSeti;
}

// string dtstartLine = gcalRule.Substring(0, gcalRule.IndexOf("\r\n"));
//Commented by Sampath on 27Nov2007 as there is no Duration Element in the iCal string returned by GCal
//string durationLine = gcalRule.Substring(gcalRule.IndexOf("DURATION:"), (gcalRule.IndexOf("RRULE:") - 2) - gcalRule.IndexOf("DURATION:"));
//Added by Sampath to on 27Nov2007 to read the DTEND element returned by GCal
// string dtendLine = gcalRule.Substring(gcalRule.IndexOf("DTEND;"), (gcalRule.IndexOf("RRULE:") - 2) - gcalRule.IndexOf("DTEND;"));

string dtstartDateTime = dtstartLine.Substring(dtstartLine.LastIndexOf(":") + 1);
//Commented by Sampath on 27Nov2007 as there is no Duration Element in the iCal string returned by GCal
//string dtstartDuration = durationLine.Substring("DURATION:PT".Length, durationLine.Length - "DURATION:PT".Length - 1);
//Added by Sampath to on 27Nov2007 to read the End Date element returned by GCal
string dtendDateTime = dtendLine.Substring(dtendLine.LastIndexOf(":") + 1);
string[] formats = new string[] { "r", "s", "u", "yyyyMMdd", "yyyyMMddTHHmmss" };

appointment.Start = DateTime.ParseExact(dtstartDateTime, formats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
appointment.End = DateTime.ParseExact(dtendDateTime, formats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
//Commented by Sampath on 27Nov2007 as there is no Duration Element in the iCal string returned by GCal
//appointment.Duration = new TimeSpan(0, 0, Convert.ToInt32(dtstartDuration));
//Added by Sampath on 27Nov2007 to calculate the duration from the start and end times
appointment.Duration = appointment.End.Subtract(appointment.Start);

if (!string.IsNullOrEmpty(recurrLine)) // Make sure we're positive
{
string[] rules = recurrLine.Split(';');
bool recurrUntilForever = true;
... no more changes after this point.
I'm trying to figure out now is how to get back to a 'clean' calendar without blowing away my contacts etc. That or how add a force option to the sync to tell it to undelete an event on the pda with an event it finds in Google Calendar.

John