/// <summary> /// This can be used to write a time zone to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the time zone is /// written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> /// <exception cref="ArgumentException">This is thrown if the TimeZoneId's Value property is null</exception> public override void WriteToStream(TextWriter tw, StringBuilder sb) { PropagateVersion(); tw.Write("BEGIN:VTIMEZONE\r\n"); // The TZID property is required. if (this.TimeZoneId.Value == null) { throw new ArgumentException(LR.GetString("ExTZIDCannotBeNull")); } BaseProperty.WriteToStream(timeZoneId, sb, tw); BaseProperty.WriteToStream(timeZoneUrl, sb, tw); BaseProperty.WriteToStream(lastMod, sb, tw); if (rules != null && rules.Count != 0) { foreach (ObservanceRule r in rules) { r.WriteToStream(tw, sb); } } if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } tw.Write("END:VTIMEZONE\r\n"); }
/// <summary> /// This can be used to write a free/busy object to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the free/busy object is /// written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> public override void WriteToStream(TextWriter tw, StringBuilder sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream this.TimeStamp.DateTimeValue = DateTime.Now; PropagateVersion(); tw.Write("BEGIN:VFREEBUSY\r\n"); // This is a required property for iCalendar 2.0. BaseProperty.WriteToStream(this.UniqueId, sb, tw); BaseProperty.WriteToStream(organizer, sb, tw); if (attendees != null && attendees.Count != 0) { foreach (AttendeeProperty a in attendees) { BaseProperty.WriteToStream(a, sb, tw); } } BaseProperty.WriteToStream(contact, sb, tw); BaseProperty.WriteToStream(startDate, sb, tw); BaseProperty.WriteToStream(endDate, sb, tw); BaseProperty.WriteToStream(duration, sb, tw); BaseProperty.WriteToStream(comment, sb, tw); BaseProperty.WriteToStream(url, sb, tw); BaseProperty.WriteToStream(timeStamp, sb, tw); if (reqstats != null && reqstats.Count != 0) { foreach (RequestStatusProperty r in reqstats) { BaseProperty.WriteToStream(r, sb, tw); } } if (freebusy != null && freebusy.Count != 0) { // If there are any, they are sorted in ascending order first freebusy.Sort(true); foreach (FreeBusyProperty fb in freebusy) { BaseProperty.WriteToStream(fb, sb, tw); } } if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } tw.Write("END:VFREEBUSY\r\n"); }
/// <summary> /// This is used to write recurrence properties to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the event is written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> public override void WriteToStream(TextWriter tw, StringBuilder sb) { if (rRules != null && rRules.Count != 0) { foreach (RRuleProperty r in rRules) { BaseProperty.WriteToStream(r, sb, tw); } } if (rDates != null && rDates.Count != 0) { foreach (RDateProperty r in rDates) { BaseProperty.WriteToStream(r, sb, tw); } } if (exRules != null && exRules.Count != 0) { foreach (ExRuleProperty e in exRules) { BaseProperty.WriteToStream(e, sb, tw); } } if (exDates != null && exDates.Count != 0) { foreach (ExDateProperty e in exDates) { BaseProperty.WriteToStream(e, sb, tw); } } if (this.ExcludeStartDateTime) { tw.Write("X-EWSOFTWARE-EXCLUDESTART:1\r\n"); } }
/// <summary> /// This can be used to write a vNote to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the vNote is written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="ToString"/> as well as owning objects when they convert /// themselves to a string or write themselves to a PDI data stream.</remarks> public void WriteToStream(TextWriter tw, StringBuilder sb) { PropagateVersion(); tw.Write("BEGIN:VNOTE\r\n"); tw.Write("VERSION:1.1\r\n"); BaseProperty.WriteToStream(uid, sb, tw); BaseProperty.WriteToStream(summary, sb, tw); // The BODY property is required, all others are optional. However, it can be blank so we must force // it if it is blank. if (body == null || String.IsNullOrEmpty(body.Value)) { tw.Write("BODY:\r\n"); } else { BaseProperty.WriteToStream(body, sb, tw); } BaseProperty.WriteToStream(categories, sb, tw); BaseProperty.WriteToStream(classification, sb, tw); BaseProperty.WriteToStream(dateCreated, sb, tw); BaseProperty.WriteToStream(lastModified, sb, tw); if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } tw.Write("END:VNOTE\r\n"); }
/// <summary> /// This can be used to write a vCard to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the vCard is written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="ToString"/> as well as owning objects when they convert /// themselves to a string or write themselves to a PDI data stream.</remarks> public void WriteToStream(TextWriter tw, StringBuilder sb) { // If Formatted Name is undefined, try to set it based on Name if (fn == null || fn.Value == "Unknown") { this.FormattedName.Value = this.Name.FormattedName; } PropagateVersion(); if (groupName != null) { tw.Write(groupName); tw.Write('.'); } tw.Write("BEGIN:VCARD\r\n"); if (this.Version == SpecificationVersions.vCard21) { tw.Write("VERSION:2.1\r\n"); } else { tw.Write("VERSION:3.0\r\n"); } // Save 3.0 specification properties when needed. We'll group the properties to keep similar ones // together. It's not necessary, but it makes things easier to find. if (this.Version == SpecificationVersions.vCard30) { if (addProfile) { tw.Write("PROFILE:VCARD\r\n"); } BaseProperty.WriteToStream(prodId, sb, tw); BaseProperty.WriteToStream(mimeName, sb, tw); BaseProperty.WriteToStream(mimeSource, sb, tw); } // These two are required properties BaseProperty.WriteToStream(this.FormattedName, sb, tw); BaseProperty.WriteToStream(this.Name, sb, tw); if (this.Version == SpecificationVersions.vCard30) { BaseProperty.WriteToStream(nickname, sb, tw); BaseProperty.WriteToStream(sortString, sb, tw); } BaseProperty.WriteToStream(bday, sb, tw); BaseProperty.WriteToStream(org, sb, tw); BaseProperty.WriteToStream(title, sb, tw); BaseProperty.WriteToStream(role, sb, tw); if (this.Version == SpecificationVersions.vCard30) { BaseProperty.WriteToStream(classification, sb, tw); BaseProperty.WriteToStream(categories, sb, tw); } if (addrs != null && addrs.Count != 0) { foreach (AddressProperty a in addrs) { BaseProperty.WriteToStream(a, sb, tw); } } if (labels != null && labels.Count != 0) { foreach (LabelProperty l in labels) { BaseProperty.WriteToStream(l, sb, tw); } } if (phones != null && phones.Count != 0) { foreach (TelephoneProperty t in phones) { BaseProperty.WriteToStream(t, sb, tw); } } if (email != null && email.Count != 0) { foreach (EMailProperty e in email) { BaseProperty.WriteToStream(e, sb, tw); } } if (agents != null && agents.Count != 0) { foreach (AgentProperty a in agents) { BaseProperty.WriteToStream(a, sb, tw); } } if (notes != null && notes.Count != 0) { foreach (NoteProperty n in notes) { BaseProperty.WriteToStream(n, sb, tw); } } BaseProperty.WriteToStream(url, sb, tw); BaseProperty.WriteToStream(tz, sb, tw); BaseProperty.WriteToStream(geo, sb, tw); BaseProperty.WriteToStream(mailer, sb, tw); BaseProperty.WriteToStream(rev, sb, tw); BaseProperty.WriteToStream(uid, sb, tw); BaseProperty.WriteToStream(key, sb, tw); BaseProperty.WriteToStream(photo, sb, tw); BaseProperty.WriteToStream(logo, sb, tw); BaseProperty.WriteToStream(sound, sb, tw); if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } if (groupName != null) { tw.Write(groupName); tw.Write('.'); } tw.Write("END:VCARD\r\n"); }
/// <summary> /// This can be used to write an event to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the event is written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> public override void WriteToStream(TextWriter tw, StringBuilder sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream // (iCalendar 2.0 only). this.TimeStamp.DateTimeValue = DateTime.Now; PropagateVersion(); tw.Write("BEGIN:VEVENT\r\n"); // This is a required property for iCalendar 2.0 but is optional for vCalendar 1.0 if (this.Version != SpecificationVersions.vCalendar10 || uid != null) { BaseProperty.WriteToStream(this.UniqueId, sb, tw); } BaseProperty.WriteToStream(startDate, sb, tw); if (this.Version == SpecificationVersions.iCalendar20) { // Duration and end date are mutually exclusive. If there is a duration, end date is ignored. if (duration != null && duration.DurationValue != PDI.Duration.Zero) { BaseProperty.WriteToStream(duration, sb, tw); } if (endDate != null && (duration == null || duration.DurationValue == PDI.Duration.Zero)) { BaseProperty.WriteToStream(endDate, sb, tw); } BaseProperty.WriteToStream(organizer, sb, tw); } else { // vCalendar uses DTEND and doesn't have a DURATION BaseProperty.WriteToStream(endDate, sb, tw); BaseProperty.WriteToStream(rNum, sb, tw); } BaseProperty.WriteToStream(summary, sb, tw); BaseProperty.WriteToStream(desc, sb, tw); BaseProperty.WriteToStream(classification, sb, tw); BaseProperty.WriteToStream(categories, sb, tw); BaseProperty.WriteToStream(resources, sb, tw); BaseProperty.WriteToStream(location, sb, tw); BaseProperty.WriteToStream(priority, sb, tw); BaseProperty.WriteToStream(sequence, sb, tw); BaseProperty.WriteToStream(transp, sb, tw); BaseProperty.WriteToStream(status, sb, tw); BaseProperty.WriteToStream(url, sb, tw); BaseProperty.WriteToStream(dateCreated, sb, tw); BaseProperty.WriteToStream(lastMod, sb, tw); if (this.Version == SpecificationVersions.iCalendar20) { BaseProperty.WriteToStream(dateStamp, sb, tw); BaseProperty.WriteToStream(comment, sb, tw); BaseProperty.WriteToStream(geo, sb, tw); BaseProperty.WriteToStream(recurId, sb, tw); if (contacts != null && contacts.Count != 0) { foreach (ContactProperty c in contacts) { BaseProperty.WriteToStream(c, sb, tw); } } if (reqStats != null && reqStats.Count != 0) { foreach (RequestStatusProperty r in reqStats) { BaseProperty.WriteToStream(r, sb, tw); } } } if (attendees != null && attendees.Count != 0) { foreach (AttendeeProperty a in attendees) { BaseProperty.WriteToStream(a, sb, tw); } } if (relatedTo != null && relatedTo.Count != 0) { foreach (RelatedToProperty r in relatedTo) { BaseProperty.WriteToStream(r, sb, tw); } } base.WriteToStream(tw, sb); if (alarms != null && alarms.Count != 0) { foreach (VAlarm a in alarms) { a.WriteToStream(tw, sb); } } if (attachments != null && attachments.Count != 0) { foreach (AttachProperty a in attachments) { BaseProperty.WriteToStream(a, sb, tw); } } if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } tw.Write("END:VEVENT\r\n"); }
/// <summary> /// This can be used to write a journal to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the journal is written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> public override void WriteToStream(TextWriter tw, StringBuilder sb) { // DTSTAMP is always updated and written to reflect when the object was saved to the stream this.TimeStamp.DateTimeValue = DateTime.Now; PropagateVersion(); tw.Write("BEGIN:VJOURNAL\r\n"); // This is a required property for iCalendar 2.0 BaseProperty.WriteToStream(this.UniqueId, sb, tw); BaseProperty.WriteToStream(timeStamp, sb, tw); BaseProperty.WriteToStream(sequence, sb, tw); BaseProperty.WriteToStream(startDate, sb, tw); BaseProperty.WriteToStream(summary, sb, tw); BaseProperty.WriteToStream(desc, sb, tw); BaseProperty.WriteToStream(comment, sb, tw); BaseProperty.WriteToStream(organizer, sb, tw); BaseProperty.WriteToStream(classification, sb, tw); BaseProperty.WriteToStream(categories, sb, tw); BaseProperty.WriteToStream(status, sb, tw); BaseProperty.WriteToStream(recurId, sb, tw); BaseProperty.WriteToStream(url, sb, tw); BaseProperty.WriteToStream(dateCreated, sb, tw); BaseProperty.WriteToStream(lastMod, sb, tw); if (contacts != null && contacts.Count != 0) { foreach (ContactProperty c in contacts) { BaseProperty.WriteToStream(c, sb, tw); } } if (attendees != null && attendees.Count != 0) { foreach (AttendeeProperty a in attendees) { BaseProperty.WriteToStream(a, sb, tw); } } if (relatedTo != null && relatedTo.Count != 0) { foreach (RelatedToProperty r in relatedTo) { BaseProperty.WriteToStream(r, sb, tw); } } if (reqStats != null && reqStats.Count != 0) { foreach (RequestStatusProperty r in reqStats) { BaseProperty.WriteToStream(r, sb, tw); } } base.WriteToStream(tw, sb); if (attachments != null && attachments.Count != 0) { foreach (AttachProperty a in attachments) { BaseProperty.WriteToStream(a, sb, tw); } } if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } tw.Write("END:VJOURNAL\r\n"); }
/// <summary> /// This can be used to write an alarm to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the alarm is written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> public override void WriteToStream(TextWriter tw, StringBuilder sb) { StringBuilder sbVCal = null; PropagateVersion(); // If vCalendar 1.0, write in alternate format if (this.Version == SpecificationVersions.vCalendar10) { // If using a StringWriter, append directly to it if (sb == null) { sbVCal = ((StringWriter)tw).GetStringBuilder(); } else { sbVCal = sb; sbVCal.Length = 0; } int priorLen = sbVCal.Length; switch (this.Action.Action) { case AlarmAction.Audio: sbVCal.Append("AALARM"); if (this.Attachments.Count != 0) { this.Attachments[0].SerializeParameters(sbVCal); } sbVCal.Append(':'); sbVCal.Append(this.Trigger.EncodedValue); sbVCal.Append(';'); if (duration != null) { sbVCal.Append(duration.EncodedValue); } sbVCal.Append(';'); if (repeat != null) { sbVCal.Append(repeat.EncodedValue); } sbVCal.Append(';'); if (this.Attachments.Count != 0) { sbVCal.Append(this.Attachments[0].EncodedValue); } break; case AlarmAction.Display: sbVCal.Append("DALARM"); this.Description.SerializeParameters(sbVCal); sbVCal.Append(':'); sbVCal.Append(this.Trigger.EncodedValue); sbVCal.Append(';'); if (duration != null) { sbVCal.Append(duration.EncodedValue); } sbVCal.Append(';'); if (repeat != null) { sbVCal.Append(repeat.EncodedValue); } sbVCal.Append(';'); sbVCal.Append(this.Description.EncodedValue); break; case AlarmAction.EMail: sbVCal.Append("MALARM"); this.Description.SerializeParameters(sbVCal); sbVCal.Append(':'); sbVCal.Append(this.Trigger.EncodedValue); sbVCal.Append(';'); if (duration != null) { sbVCal.Append(duration.EncodedValue); } sbVCal.Append(';'); if (repeat != null) { sbVCal.Append(repeat.EncodedValue); } sbVCal.Append(';'); if (this.Attendees.Count != 0) { sbVCal.Append(this.Attendees[0].EncodedValue); } sbVCal.Append(';'); sbVCal.Append(this.Description.EncodedValue); break; case AlarmAction.Procedure: sbVCal.Append("PALARM"); if (this.Attachments.Count != 0) { this.Attachments[0].SerializeParameters(sbVCal); } sbVCal.Append(':'); sbVCal.Append(this.Trigger.EncodedValue); sbVCal.Append(';'); if (duration != null) { sbVCal.Append(duration.EncodedValue); } sbVCal.Append(';'); if (repeat != null) { sbVCal.Append(repeat.EncodedValue); } sbVCal.Append(';'); if (this.Attachments.Count != 0) { sbVCal.Append(this.Attachments[0].EncodedValue); } break; default: break; // Anything else is unknown } sbVCal.Append("\r\n"); // Insert line folds? if (sbVCal.Length - priorLen > 75) { int len = 1; while (priorLen < sbVCal.Length) { if (sbVCal[priorLen] == '\r' || sbVCal[priorLen] == '\n') { len = 1; } else { len++; } priorLen++; if (len == 76 && priorLen < sbVCal.Length && sbVCal[priorLen] != '\r' && sbVCal[priorLen] != '\n') { // Find the first non-whitespace character that isn't '=' (possible quoted-printable) // and insert the break there. do { len--; priorLen--; } while(len > 0 && (Char.IsWhiteSpace(sbVCal[priorLen]) || sbVCal[priorLen] == '=')); if (len > 0) { len = 1; sbVCal.Insert(priorLen + 1, "\r\n "); priorLen += 3; } else // Couldn't find a non-whitespace char, give up { priorLen += 75; } } } } if (sb != null) { tw.Write(sb.ToString()); } return; } tw.Write("BEGIN:VALARM\r\n"); // Action and Trigger are required properties BaseProperty.WriteToStream(this.Action, sb, tw); BaseProperty.WriteToStream(this.Trigger, sb, tw); // These are optional but if one is specified, the other must be as well if ((repeat != null && repeat.RepeatCount != 0) || (duration != null && duration.DurationValue != PDI.Duration.Zero)) { // Force a repeat if not specified if (this.Repeat.RepeatCount < 1) { this.Repeat.RepeatCount = 1; } // Specify a minimum duration if one hasn't been specified if (this.Duration.DurationValue == PDI.Duration.Zero) { this.Duration.DurationValue = new Duration("PT15M"); } BaseProperty.WriteToStream(this.Repeat, sb, tw); BaseProperty.WriteToStream(this.Duration, sb, tw); } // The remaining properties are saved based on the action type switch (this.Action.Action) { case AlarmAction.Audio: // Only one attachment is allowed if specified if (attachments != null && attachments.Count != 0) { BaseProperty.WriteToStream(attachments[0], sb, tw); } break; case AlarmAction.Display: BaseProperty.WriteToStream(desc, sb, tw); break; case AlarmAction.Procedure: BaseProperty.WriteToStream(desc, sb, tw); // Only one attachment is allowed if specified if (attachments != null && attachments.Count != 0) { BaseProperty.WriteToStream(attachments[0], sb, tw); } break; default: // Email or Other BaseProperty.WriteToStream(summary, sb, tw); BaseProperty.WriteToStream(desc, sb, tw); if (attendees != null && attendees.Count != 0) { foreach (AttendeeProperty a in attendees) { BaseProperty.WriteToStream(a, sb, tw); } } if (attachments != null && attachments.Count != 0) { foreach (AttachProperty a in attachments) { BaseProperty.WriteToStream(a, sb, tw); } } break; } // Add any custom properties if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } tw.Write("END:VALARM\r\n"); }
/// <summary> /// This can be used to write an observance rule to a PDI data stream /// </summary> /// <param name="tw">A <see cref="System.IO.TextWriter"/> derived class to which the observance rule is /// written.</param> /// <param name="sb">A <see cref="System.Text.StringBuilder"/> used by the properties as a temporary /// buffer. This can be null if the TextWriter is a <see cref="System.IO.StringWriter"/>.</param> /// <remarks>This is called by <see cref="CalendarObject.ToString"/> as well as owning objects when they /// convert themselves to a string or write themselves to a PDI data stream.</remarks> public override void WriteToStream(TextWriter tw, StringBuilder sb) { PropagateVersion(); if (ruleType == ObservanceRuleType.Standard) { tw.Write("BEGIN:STANDARD\r\n"); } else { tw.Write("BEGIN:DAYLIGHT\r\n"); } if (startDate != null) { startDate.TimeZoneId = null; // Never use a time zone ID startDate.IsFloating = true; // Always floating BaseProperty.WriteToStream(startDate, sb, tw); } BaseProperty.WriteToStream(offsetFrom, sb, tw); BaseProperty.WriteToStream(offsetTo, sb, tw); BaseProperty.WriteToStream(comment, sb, tw); if (rRules != null && rRules.Count != 0) { foreach (RRuleProperty r in rRules) { BaseProperty.WriteToStream(r, sb, tw); } } if (rDates != null && rDates.Count != 0) { foreach (RDateProperty rdt in rDates) { rdt.TimeZoneId = null; // Never use a time zone ID rdt.IsFloating = true; // Always floating // Periods aren't supported so force them to a date/time if (rdt.ValueLocation == ValLocValue.Period) { rdt.ValueLocation = ValLocValue.DateTime; } BaseProperty.WriteToStream(rdt, sb, tw); } } if (tzNames != null && tzNames.Count != 0) { foreach (TimeZoneNameProperty tzn in tzNames) { BaseProperty.WriteToStream(tzn, sb, tw); } } if (customProps != null && customProps.Count != 0) { foreach (CustomProperty c in customProps) { BaseProperty.WriteToStream(c, sb, tw); } } if (ruleType == ObservanceRuleType.Standard) { tw.Write("END:STANDARD\r\n"); } else { tw.Write("END:DAYLIGHT\r\n"); } }