//===================================================================== /// <summary> /// Collection indexer /// </summary> /// <param name="uniqueId">The unique ID of the item to get or set. When retrieving an item, null is /// returned if it does not exist in the collection.</param> /// <exception cref="ArgumentException">This is thrown if an attempt is made to set an item using a /// unique ID that does not exist in the collection.</exception> public VNote this[string uniqueId] { get { for (int idx = 0; idx < base.Count; idx++) { if (base[idx].UniqueId.Value == uniqueId) { return(base[idx]); } } return(null); } set { for (int idx = 0; idx < base.Count; idx++) { if (base[idx].UniqueId.Value == uniqueId) { base[idx] = value; return; } } throw new ArgumentException(LR.GetString("ExUIDNotFound")); } }
//===================================================================== /// <summary> /// Collection indexer /// </summary> /// <param name="propertyName">The name of the item to get or set. When retrieving an item, null is /// returned if it does not exist in the collection.</param> /// <exception cref="ArgumentException">This is thrown if an attempt is made to set an item using a name /// that does not exist in the collection.</exception> /// <remarks>The property name is case-insensitive</remarks> public CustomProperty this[string propertyName] { get { for (int idx = 0; idx < base.Count; idx++) { if (String.Compare(base[idx].Tag, propertyName, StringComparison.OrdinalIgnoreCase) == 0) { return(base[idx]); } } return(null); } set { for (int idx = 0; idx < base.Count; idx++) { if (String.Compare(base[idx].Tag, propertyName, StringComparison.OrdinalIgnoreCase) == 0) { base[idx] = value; return; } } throw new ArgumentException(LR.GetString("ExCPropIDNotFound")); } }
/// <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 version of the constructor is used when parsing vNote data that is to be stored in an existing /// vNote instance. /// </summary> /// <remarks>The properties in the passed vNote will be cleared</remarks> /// <param name="vNote">The existing vNote instance</param> /// <exception cref="ArgumentNullException">This is thrown if the specified vNote object is null</exception> protected VNoteParser(VNote vNote) : this() { currentNote = vNote ?? throw new ArgumentNullException(nameof(vNote), LR.GetString("ExParseNullObject", "vNote")); currentNote.ClearProperties(); vNotes.Add(vNote); }
/// <summary> /// This version of the constructor is used when parsing vCard data that is to be stored in an existing /// vCard instance. /// </summary> /// <remarks>The properties in the passed vCard will be cleared</remarks> /// <param name="vCard">The existing vCard instance</param> /// <exception cref="ArgumentNullException">This is thrown if the specified vCard object is null</exception> protected VCardParser(VCard vCard) : this() { currentCard = vCard ?? throw new ArgumentNullException(nameof(vCard), LR.GetString("ExParseNullObject", "vCard")); currentCard.ClearProperties(); vCards.Add(vCard); }
/// <summary> /// This is used by the recurrence pattern control to update the current frequency when the radio buttons /// selection changes. /// </summary> /// <param name="frequency">The new frequency</param> public void SetFrequency(RecurFrequency frequency) { rf = frequency; // Set the interval label and enable or disable the ByDay instance control based on the frequency switch (rf) { case RecurFrequency.Yearly: // Day instance is disabled if ByMonth and ByMonthDay are use together or if ByWeekNo is used if (lbByMonth.CheckedItems.Count > 0) { udcDayInstance.Enabled = (txtByMonthDay.Text.Length == 0); } else { udcDayInstance.Enabled = (txtByWeekNo.Text.Length == 0); } lblInterval.Text = LR.GetString("APYearly"); break; case RecurFrequency.Monthly: // Day instance is disabled if ByMonthDay is specified udcDayInstance.Enabled = (txtByMonthDay.Text.Length == 0); lblInterval.Text = LR.GetString("APMonthly"); break; case RecurFrequency.Weekly: udcDayInstance.Enabled = false; lblInterval.Text = LR.GetString("APWeekly"); break; case RecurFrequency.Daily: udcDayInstance.Enabled = false; lblInterval.Text = LR.GetString("APDaily"); break; case RecurFrequency.Hourly: udcDayInstance.Enabled = false; lblInterval.Text = LR.GetString("APHourly"); break; case RecurFrequency.Minutely: udcDayInstance.Enabled = false; lblInterval.Text = LR.GetString("APMinutely"); break; case RecurFrequency.Secondly: udcDayInstance.Enabled = false; lblInterval.Text = LR.GetString("APSecondly"); break; } LoadByDayValues(); // By Week # is only used by the Yearly frequency txtByWeekNo.Enabled = (rf == RecurFrequency.Yearly); }
//===================================================================== /// <summary> /// This is used to retrieve the recurrence information into the passed recurrence object /// </summary> /// <param name="recurrence">The recurrence in which to store the settings.</param> /// <exception cref="ArgumentNullException">This is thrown if the passed recurrence object is null</exception> public void GetRecurrence(Recurrence recurrence) { if (recurrence == null) { throw new ArgumentNullException("recurrence", LR.GetString("ExRPRecurrenceIsNull")); } rpRecurrence.GetRecurrence(recurrence); }
/// <summary> /// Delete a holiday from the list box /// </summary> private void btnRemove_Click(object sender, System.EventArgs e) { if(lbHolidays.SelectedIndex == -1) MessageBox.Show(LR.GetString("EditHMSelectHoliday")); else { holidays.RemoveAt(lbHolidays.SelectedIndex); this.LoadHolidayList(); } }
/// <summary> /// This can be used to set one address as the preferred address /// </summary> /// <param name="address">The address to make preferred</param> /// <remarks>The Preferred flag is turned off in all addresses except for the one specified</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the collection does not contain the /// specified address object.</exception> /// <overloads>There are two overloads for this method</overloads> public void SetPreferred(AddressProperty address) { int idx = base.IndexOf(address); if (idx == -1) { throw new ArgumentOutOfRangeException("address", address, LR.GetString("ExAddrNotInCollection")); } this.SetPreferred(idx); }
/// <summary> /// This can be used to set one phone number as the preferred phone number /// </summary> /// <param name="phone">The phone property to make preferred</param> /// <remarks>The Preferred flag is turned off in all phone numbers except for the one specified</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the collection does not contain the /// specified phone number object.</exception> /// <overloads>There are two overloads for this method</overloads> public void SetPreferred(TelephoneProperty phone) { int idx = base.IndexOf(phone); if (idx == -1) { throw new ArgumentOutOfRangeException("phone", phone, LR.GetString("ExPhoneNotInCollection")); } this.SetPreferred(idx); }
/// <summary> /// This can be used to set one e-mail address as the preferred e-mail address /// </summary> /// <param name="email">The e-mail address to make preferred</param> /// <remarks>The Preferred flag is turned off in all e-mail addresses except for the one specified</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the collection does not contain the /// specified e-mail address object.</exception> /// <overloads>There are two overloads for this method</overloads> public void SetPreferred(EMailProperty email) { int idx = base.IndexOf(email); if (idx == -1) { throw new ArgumentOutOfRangeException("email", email, LR.GetString("ExEAddrNotInCollection")); } this.SetPreferred(idx); }
/// <summary> /// This can be used to set one label as the preferred label /// </summary> /// <param name="label">The label to make preferred</param> /// <remarks>The Preferred flag is turned off in all labels except for the one specified</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the collection does not contain the /// specified label object.</exception> /// <overloads>There are two overloads for this method</overloads> public void SetPreferred(LabelProperty label) { int idx = base.IndexOf(label); if (idx == -1) { throw new ArgumentOutOfRangeException(nameof(label), label, LR.GetString("ExLabelNotInCollection")); } this.SetPreferred(idx); }
/// <summary> /// This version of the constructor is used when parsing vNote data that is to be stored in an existing /// vNote instance. /// </summary> /// <remarks>The properties in the passed vNote will be cleared</remarks> /// <param name="vNote">The existing vNote instance</param> /// <exception cref="ArgumentNullException">This is thrown if the specified vNote object is null</exception> protected VNoteParser(VNote vNote) : this() { if (vNote == null) { throw new ArgumentNullException("vNote", LR.GetString("ExParseNullObject", "vNote")); } currentNote = vNote; currentNote.ClearProperties(); vNotes.Add(vNote); }
/// <summary> /// This version of the constructor is used when parsing vCard data that is to be stored in an existing /// vCard instance. /// </summary> /// <remarks>The properties in the passed vCard will be cleared</remarks> /// <param name="vCard">The existing vCard instance</param> /// <exception cref="ArgumentNullException">This is thrown if the specified vCard object is null</exception> protected VCardParser(VCard vCard) : this() { if (vCard == null) { throw new ArgumentNullException("vCard", LR.GetString("ExParseNullObject", "vCard")); } currentCard = vCard; currentCard.ClearProperties(); vCards.Add(vCard); }
/// <summary> /// This method is used to parse one or more PDI objects from the specified file or URL /// </summary> /// <param name="filename">The name of the file from which to read the PDI objects. This can be a /// standard filename or a URL that starts with "file://", "http://", or "https://".</param> /// <remarks>The derived class will build a list of objects based on the data stream. See the derived /// classes for more information. The named file will be opened, its entire content parsed, and then /// it will be closed.</remarks> /// <seealso cref="VCardParser"/> /// <seealso cref="VCalendarParser"/> /// <exception cref="ArgumentNullException">This is thrown if the specified filename string is null or /// empty.</exception> /// <exception cref="PDIParserException">This is thrown if there is an error parsing the data stream. /// Inner exceptions may contain additional information about the cause of the error.</exception> /// <example> /// <code language="cs"> /// VCardParser vcp = new VCardParser(); /// vcp.ParseFile(@"C:\AddressBook.vcf"); /// //Or vcp.ParseFile("http://www.mydomain.com/vCards/AddressBook.vcf"); /// /// VCardCollection vCards = vcp.VCards; /// </code> /// <code language="vbnet"> /// Dim vcp As New VCardParser /// vcp.ParseFile("C:\AddressBook.vcf"); /// 'Or vcp.ParseFile("http://www.mydomain.com/vCards/AddressBook.vcf"); /// /// Dim vCards As VCardCollection = vcp.VCards /// </code> /// </example> public void ParseFile(string filename) { StreamReader sr = null; if (filename == null || filename.Length == 0) { throw new ArgumentNullException("filename", LR.GetString("ExParseNoFilename")); } // Exceptions will bubble up to the caller try { if (filename.StartsWith("http:", StringComparison.OrdinalIgnoreCase) || filename.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) { HttpWebRequest wrq = (HttpWebRequest)WebRequest.Create(new Uri(filename)); WebResponse wrsp = wrq.GetResponse(); sr = new StreamReader(wrsp.GetResponseStream(), defaultEncoding); } else if (filename.StartsWith("file:", StringComparison.OrdinalIgnoreCase)) { FileWebRequest frq = (FileWebRequest)WebRequest.Create(new Uri(filename)); WebResponse frsp = frq.GetResponse(); sr = new StreamReader(frsp.GetResponseStream(), defaultEncoding); } else { sr = new StreamReader(filename, defaultEncoding); } this.ParseReader(sr); } catch (PDIParserException) { // Just pass these on unchanged throw; } catch (Exception e) { // Wrap all other exceptions in a PDIParser exception throw new PDIParserException(lineNbr, LR.GetString("ExParseUnexpectedError"), e); } finally { if (sr != null) { sr.Close(); } } }
/// <summary> /// Perform validation and store the changes /// </summary> private void HolidayPropertiesDlg_Closing(object sender, System.ComponentModel.CancelEventArgs e) { // Ignore on cancel if (this.DialogResult == DialogResult.Cancel) { return; } txtDescription.Text = txtDescription.Text.Trim(); epErrors.Clear(); // We must have a description if (txtDescription.Text.Length == 0) { epErrors.SetError(txtDescription, LR.GetString("EditHAEBlankDesc")); e.Cancel = true; } // Leap years aren't accepted so always use a non-leap year to check the date if (rbFixed.Checked && udcDayOfMonth.Value > DateTime.DaysInMonth(2003, (int)cboMonth.SelectedValue)) { epErrors.SetError(udcDayOfMonth, LR.GetString("EditHAEBadDayOfMonth")); e.Cancel = true; } // If all is good, update the holiday object with the new settings if (!e.Cancel) { if (!rbFixed.Checked) { FloatingHoliday fl = new FloatingHoliday(); holiday = fl; fl.Occurrence = (DayOccurrence)cboOccurrence.SelectedValue; fl.Weekday = (System.DayOfWeek)cboDayOfWeek.SelectedValue; fl.Offset = (int)udcOffset.Value; } else { FixedHoliday fx = new FixedHoliday(); holiday = fx; fx.AdjustFixedDate = chkAdjustDate.Checked; fx.Day = (int)udcDayOfMonth.Value; } holiday.Month = (int)cboMonth.SelectedValue; holiday.Description = txtDescription.Text; } }
/// <summary> /// Load the holiday info from a file in the format selected by the user /// </summary> private void btnLoad_Click(object sender, System.EventArgs e) { using(OpenFileDialog dlg = new OpenFileDialog()) { dlg.Title = LR.GetString("HMLoadTitle"); dlg.DefaultExt = "xml"; dlg.Filter = LR.GetString("HMFileDlgFilter"); dlg.InitialDirectory = Environment.CurrentDirectory; if(dlg.ShowDialog() == DialogResult.OK) { // Deserialize the holidays from a file of the selected format try { this.Cursor = Cursors.WaitCursor; using(FileStream fs = new FileStream(dlg.FileName, FileMode.Open)) { XmlSerializer xs = new XmlSerializer(typeof(HolidayCollection)); holidays = (HolidayCollection)xs.Deserialize(fs); } this.LoadHolidayList(); } catch(Exception ex) { System.Diagnostics.Debug.Write(ex.ToString()); string errorMsg = LR.GetString("HMLoadError", ex.Message); if(ex.InnerException != null) { errorMsg += ex.InnerException.Message + "\n"; if(ex.InnerException.InnerException != null) errorMsg += ex.InnerException.InnerException.Message; } System.Diagnostics.Debug.WriteLine(errorMsg); MessageBox.Show(errorMsg, LR.GetString("HMErrorLoading"), MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { this.Cursor = Cursors.Default; } } } }
/// <summary> /// Collection indexer /// </summary> /// <param name="timeZoneId">The time zone ID of the item to get or set. When retrieving an item, null /// is returned if it does not exist in the collection.</param> /// <exception cref="ArgumentException">This is thrown if an attempt is made to set an item using a time /// zone ID that does not exist in the collection.</exception> public VTimeZone this[string timeZoneId] { get { this.Lock.AcquireReaderLock(250); try { for (int idx = 0; idx < items.Count; idx++) { if (items[idx].TimeZoneId.Value == timeZoneId) { return(items[idx]); } } return(null); } finally { this.Lock.ReleaseReaderLock(); } } set { this.Lock.AcquireWriterLock(250); try { for (int idx = 0; idx < items.Count; idx++) { if (items[idx].TimeZoneId.Value == timeZoneId) { this[idx] = value; return; } } throw new ArgumentException(LR.GetString("ExVTZIDNotFound")); } finally { this.Lock.ReleaseWriterLock(); } } }
/// <summary> /// This can be used to set one phone number as the preferred phone number /// </summary> /// <param name="idx">The index of the phone property to make preferred</param> /// <remarks>The Preferred flag is turned off in all phone numbers except for the one at the specified /// index.</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the index is out of bounds</exception> public void SetPreferred(int idx) { if (idx < 0 || idx > base.Count) { throw new ArgumentOutOfRangeException("idx", idx, LR.GetString("ExPhoneInvalidIndex")); } for (int phoneIdx = 0; phoneIdx < base.Count; phoneIdx++) { if (phoneIdx == idx) { this[phoneIdx].PhoneTypes |= PhoneTypes.Preferred; } else { this[phoneIdx].PhoneTypes &= ~PhoneTypes.Preferred; } } base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); }
/// <summary> /// This can be used to set one e-mail address as the preferred e-mail address /// </summary> /// <param name="idx">The index of the address to make preferred</param> /// <remarks>The Preferred flag is turned off in all e-mail addresses except for the one at the specified /// index.</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the index is out of bounds</exception> public void SetPreferred(int idx) { if (idx < 0 || idx > base.Count) { throw new ArgumentOutOfRangeException(nameof(idx), idx, LR.GetString("ExEAddrInvalidIndex")); } for (int nAddrIdx = 0; nAddrIdx < base.Count; nAddrIdx++) { if (nAddrIdx == idx) { this[nAddrIdx].EMailTypes |= EMailTypes.Preferred; } else { this[nAddrIdx].EMailTypes &= ~EMailTypes.Preferred; } } base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); }
/// <summary> /// This can be used to set one address as the preferred address /// </summary> /// <param name="idx">The index of the address to make preferred</param> /// <remarks>The Preferred flag is turned off in all addresses except for the one at the specified index</remarks> /// <exception cref="ArgumentOutOfRangeException">This is thrown if the index is out of bounds</exception> public void SetPreferred(int idx) { if (idx < 0 || idx > base.Count) { throw new ArgumentOutOfRangeException("idx", idx, LR.GetString("ExAddrInvalidIndex")); } for (int addrIdx = 0; addrIdx < base.Count; addrIdx++) { if (addrIdx == idx) { this[addrIdx].AddressTypes |= AddressTypes.Preferred; } else { this[addrIdx].AddressTypes &= ~AddressTypes.Preferred; } } base.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); }
/// <summary> /// Edit a holiday entry in the list box /// </summary> private void btnEdit_Click(object sender, System.EventArgs e) { if(lbHolidays.SelectedIndex == -1) { MessageBox.Show(LR.GetString("EditHMSelectHoliday")); return; } using(HolidayPropertiesDlg dlg = new HolidayPropertiesDlg()) { // The dialog takes care loading data from the object dlg.HolidayInfo = holidays[lbHolidays.SelectedIndex]; if(dlg.ShowDialog() == DialogResult.OK) { // Replace the holiday with the edited information. Because the type may change, the // add/edit dialog returns a new instance. holidays[lbHolidays.SelectedIndex] = dlg.HolidayInfo; this.LoadHolidayList(); } } }
//===================================================================== /// <summary> /// This is used to retrieve the recurrence information into the passed recurrence object /// </summary> /// <param name="recurrence">The recurrence in which to store the settings</param> /// <exception cref="ArgumentNullException">This is thrown if the passed recurrence object is null</exception> public void GetRecurrence(Recurrence recurrence) { Recurrence r = new Recurrence(); if (recurrence == null) { throw new ArgumentNullException("recurrence", LR.GetString("ExRPRecurrenceIsNull")); } // Get the basic stuff r.Reset(); r.WeekStart = (DayOfWeek)cboWeekStartDay.SelectedValue; r.CanOccurOnHoliday = chkHolidays.Checked; r.Frequency = rbYearly.Checked ? RecurFrequency.Yearly : rbMonthly.Checked ? RecurFrequency.Monthly : rbWeekly.Checked ? RecurFrequency.Weekly : rbDaily.Checked ? RecurFrequency.Daily : rbHourly.Checked ? RecurFrequency.Hourly : rbMinutely.Checked ? RecurFrequency.Minutely : RecurFrequency.Secondly; if (rbEndAfter.Checked) { r.MaximumOccurrences = (int)udcOccurrences.Value; } else if (rbEndByDate.Checked) { if (this.ShowEndTime) { r.RecurUntil = dtpEndDate.Value; } else { r.RecurUntil = dtpEndDate.Value.Date; } } // Get the frequency-specific stuff if (chkAdvanced.Checked) { ucAdvanced.GetValues(r); } else if (rbYearly.Checked) { ucYearly.GetValues(r); } else if (rbMonthly.Checked) { ucMonthly.GetValues(r); } else if (rbWeekly.Checked) { ucWeekly.GetValues(r); } else if (rbDaily.Checked) { ucDaily.GetValues(r); } else if (rbHourly.Checked) { ucHourly.GetValues(r); } else if (rbMinutely.Checked) { ucMinutely.GetValues(r); } else { ucSecondly.GetValues(r); } recurrence.Parse(r.ToString()); }
/// <summary> /// This is implemented to handle properties as they are parsed from the data stream /// </summary> /// <param name="propertyName">The name of the property.</param> /// <param name="parameters">A string collection containing the parameters and their values. If empty, /// there are no parameters.</param> /// <param name="propertyValue">The value of the property.</param> /// <remarks><para>There may be a mixture of name/value pairs or values alone in the parameters string /// collection. It is up to the derived class to process the parameter list based on the specification /// to which it conforms. For entries that are parameter names, the entry immediately following it in /// the collection is its associated parameter value. The property name, parameter names, and their /// values may be in upper, lower, or mixed case.</para> /// /// <para>The value may be an encoded string. The properties are responsible for any decoding that may /// need to occur (i.e. base 64 encoded image data).</para></remarks> /// <exception cref="PDIParserException">This is thrown if an error is encountered while parsing the data /// stream. Refer to the and inner exceptions for information on the cause of the problem.</exception> protected override void PropertyParser(string propertyName, StringCollection parameters, string propertyValue) { string temp; int idx; // The last entry is always CustomProperty so scan for length minus one for (idx = 0; idx < ntv.Length - 1; idx++) { if (ntv[idx].IsMatch(propertyName)) { break; } } // An opening BEGIN:VNOTE property must have been seen if (currentNote == null && ntv[idx].EnumValue != PropertyType.Begin) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VNOTE", propertyName)); } // Handle or create the property switch (ntv[idx].EnumValue) { case PropertyType.Begin: // The value must be VNOTE if (String.Compare(propertyValue.Trim(), "VNOTE", StringComparison.OrdinalIgnoreCase) != 0) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); } // NOTE: If serializing into an existing instance, this may not be null. If so, it is // ignored. if (currentNote == null) { currentNote = new VNote(); vNotes.Add(currentNote); } break; case PropertyType.End: // The value must be VNOTE if (String.Compare(propertyValue.Trim(), "VNOTE", StringComparison.OrdinalIgnoreCase) != 0) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); } // When done, we'll propagate the version number to all objects to make it consistent currentNote.PropagateVersion(); // The vNote is added to the collection when created so we don't have to rely on an END:VNOTE // to add it. currentNote = null; break; case PropertyType.Version: // Version must be 1.1 temp = propertyValue.Trim(); if (temp != "1.1") { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedVersion", "vNote", temp)); } currentNote.Version = SpecificationVersions.IrMC11; break; case PropertyType.UniqueId: currentNote.UniqueId.EncodedValue = propertyValue; break; case PropertyType.Summary: currentNote.Summary.DeserializeParameters(parameters); currentNote.Summary.EncodedValue = propertyValue; break; case PropertyType.Body: currentNote.Body.DeserializeParameters(parameters); currentNote.Body.EncodedValue = propertyValue; break; case PropertyType.Class: currentNote.Classification.EncodedValue = propertyValue; break; case PropertyType.Categories: currentNote.Categories.DeserializeParameters(parameters); currentNote.Categories.EncodedValue = propertyValue; break; case PropertyType.DateCreated: currentNote.DateCreated.DeserializeParameters(parameters); currentNote.DateCreated.EncodedValue = propertyValue; break; case PropertyType.LastModified: currentNote.LastModified.DeserializeParameters(parameters); currentNote.LastModified.EncodedValue = propertyValue; break; default: // Anything else is a custom property CustomProperty c = new CustomProperty(propertyName); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; currentNote.CustomProperties.Add(c); break; } }
/// <summary> /// This is implemented to handle properties as they are parsed from the data stream /// </summary> /// <param name="propertyName">The name of the property.</param> /// <param name="parameters">A string collection containing the parameters and their values. If empty, /// there are no parameters.</param> /// <param name="propertyValue">The value of the property.</param> /// <remarks><para>There may be a mixture of name/value pairs or values alone in the parameters string /// collection. It is up to the derived class to process the parameter list based on the specification /// to which it conforms. For entries that are parameter names, the entry immediately following it in /// the collection is its associated parameter value. The property name, parameter names, and their /// values may be in upper, lower, or mixed case.</para> /// /// <para>The value may be an encoded string. The properties are responsible for any decoding that may /// need to occur (i.e. base 64 encoded image data).</para></remarks> /// <exception cref="PDIParserException">This is thrown if an error is encountered while parsing the data /// stream. Refer to the and inner exceptions for information on the cause of the problem.</exception> protected override void PropertyParser(string propertyName, StringCollection parameters, string propertyValue) { SpecificationVersions version = SpecificationVersions.None; string temp, group = null; int idx; // Parse out the group name if there is one idx = propertyName.IndexOf('.'); if (idx != -1) { group = propertyName.Substring(0, idx).Trim(); propertyName = propertyName.Substring(idx + 1).Trim(); } // The last entry is always CustomProperty so scan for length minus one for (idx = 0; idx < ntv.Length - 1; idx++) { if (ntv[idx].IsMatch(propertyName)) { break; } } // An opening BEGIN:VCARD property must have been seen if (currentCard == null && ntv[idx].EnumValue != PropertyType.Begin) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseNoBeginProp", "BEGIN:VCARD", propertyName)); } // Handle or create the property switch (ntv[idx].EnumValue) { case PropertyType.Begin: // The value must be VCARD if (String.Compare(propertyValue.Trim(), "VCARD", StringComparison.OrdinalIgnoreCase) != 0) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); } // NOTE: If serializing into an existing instance, this may not be null. If so, it is // ignored. if (currentCard == null) { currentCard = new VCard(); vCards.Add(currentCard); } currentCard.Group = group; break; case PropertyType.End: // The value must be VCARD if (String.Compare(propertyValue.Trim(), "VCARD", StringComparison.OrdinalIgnoreCase) != 0) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); } // The group must match too if (currentCard.Group != group) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnexpectedGroupTag", currentCard.Group, group)); } // When done, we'll propagate the version number to all objects to make it consistent currentCard.PropagateVersion(); // The vCard is added to the collection when created so we don't have to rely on an END:VCARD // to add it. currentCard = null; break; case PropertyType.Profile: // The value must be VCARD if (String.Compare(propertyValue.Trim(), "VCARD", StringComparison.OrdinalIgnoreCase) != 0) { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedTagValue", ntv[idx].Name, propertyValue)); } currentCard.AddProfile = true; break; case PropertyType.Version: // Version must be 2.1 or 3.0 temp = propertyValue.Trim(); if (temp == "2.1") { version = SpecificationVersions.vCard21; } else if (temp == "3.0") { version = SpecificationVersions.vCard30; } else { throw new PDIParserException(this.LineNumber, LR.GetString("ExParseUnrecognizedVersion", "vCard", temp)); } currentCard.Version = version; break; case PropertyType.MimeName: currentCard.MimeName.EncodedValue = propertyValue; break; case PropertyType.MimeSource: currentCard.MimeSource.DeserializeParameters(parameters); currentCard.MimeSource.EncodedValue = propertyValue; break; case PropertyType.ProductId: currentCard.ProductId.EncodedValue = propertyValue; break; case PropertyType.Nickname: currentCard.Nickname.DeserializeParameters(parameters); currentCard.Nickname.EncodedValue = propertyValue; currentCard.Nickname.Group = group; break; case PropertyType.SortString: currentCard.SortString.DeserializeParameters(parameters); currentCard.SortString.EncodedValue = propertyValue; currentCard.SortString.Group = group; break; case PropertyType.Class: currentCard.Classification.EncodedValue = propertyValue; currentCard.Classification.Group = group; break; case PropertyType.Categories: currentCard.Categories.DeserializeParameters(parameters); currentCard.Categories.EncodedValue = propertyValue; currentCard.Categories.Group = group; break; case PropertyType.FormattedName: currentCard.FormattedName.DeserializeParameters(parameters); currentCard.FormattedName.EncodedValue = propertyValue; currentCard.FormattedName.Group = group; break; case PropertyType.Name: currentCard.Name.DeserializeParameters(parameters); currentCard.Name.EncodedValue = propertyValue; currentCard.Name.Group = group; break; case PropertyType.Title: currentCard.Title.DeserializeParameters(parameters); currentCard.Title.EncodedValue = propertyValue; currentCard.Title.Group = group; break; case PropertyType.Role: currentCard.Role.DeserializeParameters(parameters); currentCard.Role.EncodedValue = propertyValue; currentCard.Role.Group = group; break; case PropertyType.Mailer: currentCard.Mailer.DeserializeParameters(parameters); currentCard.Mailer.EncodedValue = propertyValue; currentCard.Mailer.Group = group; break; case PropertyType.Url: currentCard.Url.DeserializeParameters(parameters); currentCard.Url.EncodedValue = propertyValue; currentCard.Url.Group = group; break; case PropertyType.Organization: currentCard.Organization.DeserializeParameters(parameters); currentCard.Organization.EncodedValue = propertyValue; currentCard.Organization.Group = group; break; case PropertyType.UniqueId: currentCard.UniqueId.EncodedValue = propertyValue; currentCard.UniqueId.Group = group; break; case PropertyType.BirthDate: currentCard.BirthDate.DeserializeParameters(parameters); currentCard.BirthDate.EncodedValue = propertyValue; currentCard.BirthDate.Group = group; break; case PropertyType.Revision: currentCard.LastRevision.DeserializeParameters(parameters); currentCard.LastRevision.EncodedValue = propertyValue; currentCard.LastRevision.Group = group; break; case PropertyType.TimeZone: currentCard.TimeZone.DeserializeParameters(parameters); currentCard.TimeZone.EncodedValue = propertyValue; currentCard.TimeZone.Group = group; break; case PropertyType.GeographicPosition: currentCard.GeographicPosition.EncodedValue = propertyValue; currentCard.GeographicPosition.Group = group; break; case PropertyType.PublicKey: currentCard.PublicKey.DeserializeParameters(parameters); currentCard.PublicKey.EncodedValue = propertyValue; currentCard.PublicKey.Group = group; break; case PropertyType.Photo: currentCard.Photo.DeserializeParameters(parameters); currentCard.Photo.EncodedValue = propertyValue; currentCard.Photo.Group = group; break; case PropertyType.Logo: currentCard.Logo.DeserializeParameters(parameters); currentCard.Logo.EncodedValue = propertyValue; currentCard.Logo.Group = group; break; case PropertyType.Sound: currentCard.Sound.DeserializeParameters(parameters); currentCard.Sound.EncodedValue = propertyValue; currentCard.Sound.Group = group; break; case PropertyType.Note: NoteProperty n = new NoteProperty(); n.DeserializeParameters(parameters); n.EncodedValue = propertyValue; n.Group = group; currentCard.Notes.Add(n); break; case PropertyType.Address: AddressProperty a = new AddressProperty(); a.DeserializeParameters(parameters); a.EncodedValue = propertyValue; a.Group = group; currentCard.Addresses.Add(a); break; case PropertyType.Label: LabelProperty l = new LabelProperty(); l.DeserializeParameters(parameters); l.EncodedValue = propertyValue; l.Group = group; currentCard.Labels.Add(l); break; case PropertyType.Telephone: TelephoneProperty t = new TelephoneProperty(); t.DeserializeParameters(parameters); t.EncodedValue = propertyValue; t.Group = group; currentCard.Telephones.Add(t); break; case PropertyType.EMail: EMailProperty e = new EMailProperty(); e.DeserializeParameters(parameters); e.EncodedValue = propertyValue; e.Group = group; currentCard.EMailAddresses.Add(e); break; case PropertyType.Agent: AgentProperty ag = new AgentProperty(); ag.DeserializeParameters(parameters); ag.EncodedValue = propertyValue; ag.Group = group; currentCard.Agents.Add(ag); break; default: // Anything else is a custom property CustomProperty c = new CustomProperty(propertyName); c.DeserializeParameters(parameters); c.EncodedValue = propertyValue; c.Group = group; currentCard.CustomProperties.Add(c); break; } }
/// <summary> /// This method is used to return all recurring instances between the two specified date/times based on /// the current settings. /// </summary> /// <param name="fromDate">The minimum date/time on or after which instances should occur. This will /// include an instance if it starts before the date/time but overlaps it when its duration is added to /// its start time.</param> /// <param name="toDate">The maximum date/time on or before which instances should occur. This will /// include an instance if it starts on or before the specified date/time regardless of its duration.</param> /// <param name="inLocalTime">If true, the date/time parameters are assumed to be in local time and the /// returned date/times are expressed in local time. If false, the date/time parameters are assumed to /// be in the time zone of the object and the returned date/times are expressed in the time zone of the /// object as specified by the <see cref="TimeZoneId"/> property. If no time zone ID has been specified /// or it cannot be found, local time is used.</param> /// <returns>Returns a <see cref="DateTimeInstanceCollection"/> containing <see cref="DateTimeInstance" /> /// objects that represent all instances found between the two specified date/times. Instances may have /// a different duration if created from an <c>RDATE</c> property.</returns> /// <exception cref="ArgumentException">This is thrown if a start date has not been specified (it equals /// <c>DateTime.MinValue</c>) or the duration is negative.</exception> /// <seealso cref="AllInstances"/> /// <seealso cref="OccursOn"/> public DateTimeInstanceCollection InstancesBetween(DateTime fromDate, DateTime toDate, bool inLocalTime) { DateTimeCollection recurDates; Period p; DateTime endDate, tempDate1 = DateTime.MaxValue, tempDate2; int idx, count; string timeZoneID = this.TimeZoneId; PeriodCollection periods = new PeriodCollection(); DateTime startDate = this.StartDateTime.TimeZoneDateTime; Duration dur = this.InstanceDuration; if (startDate == DateTime.MinValue) { throw new ArgumentException(LR.GetString("ExNoComponentStartDate")); } if (dur.Ticks < 0) { throw new ArgumentException(LR.GetString("ExRONegativeDuration")); } // Convert fromDate and toDate to time zone time if inLocalTime is true. Recurrences are always // resolved in the time of the object. if (inLocalTime && timeZoneID != null) { fromDate = VCalendar.LocalTimeToTimeZoneTime(fromDate, timeZoneID).StartDateTime; toDate = VCalendar.LocalTimeToTimeZoneTime(toDate, timeZoneID).StartDateTime; } // There might be instances that overlap the requested range so we'll adjust the From date/time by // the duration to catch them. if (dur.Ticks > 1) { fromDate = fromDate.Add(new TimeSpan(0 - dur.Ticks + 1)); } // As per the spec, the start date/time is always included in the set but only if it (or it's // duration) is within the requested range. However, if it is recurring and the custom Exclude Start // property is set to true, it is not added. p = new Period(startDate, dur); if (((p.StartDateTime >= fromDate && p.StartDateTime <= toDate) || (p.EndDateTime >= fromDate && p.EndDateTime <= toDate)) && (!this.IsRecurring || !this.ExcludeStartDateTime)) { periods.Add(p); } // If it isn't recurring or starts after the requested end date, just return the collection as it is if (this.IsRecurring && startDate <= toDate) { // Expand each recurrence rule foreach (RRuleProperty rr in this.RecurrenceRules) { // If used, RecurUntil is stored in Universal Time which is converted to local time. If a // time zone ID is specified, convert it to that time zone temporarily to make sure things // are calculated correctly. if (rr.Recurrence.MaximumOccurrences == 0 && timeZoneID != null) { tempDate1 = rr.Recurrence.RecurUntil; rr.Recurrence.RecurUntil = VCalendar.LocalTimeToTimeZoneTime(tempDate1, timeZoneID).StartDateTime; } rr.Recurrence.StartDateTime = startDate; recurDates = rr.Recurrence.InstancesBetween(fromDate, toDate); if (rr.Recurrence.MaximumOccurrences == 0 && timeZoneID != null) { rr.Recurrence.RecurUntil = tempDate1; } foreach (DateTime dt in recurDates) { periods.Add(new Period(dt, dur)); } } // Add on recurrence dates within the range foreach (RDateProperty rd in this.RecurDates) { if (rd.ValueLocation != ValLocValue.Period) { // If it's not a period, use the component's duration. If it's only a date, assume it's // the whole day. The spec is not clear on this so I'm making a best guess. if (rd.ValueLocation == ValLocValue.DateTime) { endDate = rd.TimeZoneDateTime.Add(dur.TimeSpan); } else { endDate = rd.TimeZoneDateTime.Add(new TimeSpan(TimeSpan.TicksPerDay)); } if ((rd.TimeZoneDateTime >= fromDate && rd.TimeZoneDateTime <= toDate) || (endDate >= fromDate && endDate <= toDate)) { periods.Add(new Period(rd.TimeZoneDateTime, endDate)); } } else { // As with Recurrence.RecurUntil, the period values are in Universal Time so convert them // to the time zone time for proper comparison. tempDate1 = rd.PeriodValue.StartDateTime; tempDate2 = rd.PeriodValue.EndDateTime; if (timeZoneID != null) { tempDate1 = VCalendar.LocalTimeToTimeZoneTime(tempDate1, timeZoneID).StartDateTime; } if (timeZoneID != null) { tempDate2 = VCalendar.LocalTimeToTimeZoneTime(tempDate2, timeZoneID).StartDateTime; } if ((tempDate1 >= fromDate && tempDate1 <= toDate) || (tempDate2 >= fromDate && tempDate2 <= toDate)) { periods.Add(new Period(tempDate1, tempDate2)); } } } // Expand exception rules and filter out those instances count = periods.Count; foreach (RRuleProperty er in this.ExceptionRules) { // Same as above if (er.Recurrence.MaximumOccurrences == 0 && timeZoneID != null) { tempDate1 = er.Recurrence.RecurUntil; er.Recurrence.RecurUntil = VCalendar.LocalTimeToTimeZoneTime(tempDate1, timeZoneID).StartDateTime; } er.Recurrence.StartDateTime = startDate; recurDates = er.Recurrence.InstancesBetween(fromDate, toDate); if (er.Recurrence.MaximumOccurrences == 0 && timeZoneID != null) { er.Recurrence.RecurUntil = tempDate1; } foreach (DateTime dt in recurDates) { for (idx = 0; idx < count; idx++) { if (periods[idx].StartDateTime == dt) { periods.RemoveAt(idx); idx--; count--; } } } } // Filter out any exception dates foreach (ExDateProperty ed in this.ExceptionDates) { DateTime dt = ed.TimeZoneDateTime; // If it's only a date, assume it's the whole day and remove all instances on that day // regardless of the time. The spec is not clear on this so I'm making a best guess. if (ed.ValueLocation == ValLocValue.DateTime) { if (dt >= fromDate && dt <= toDate) { for (idx = 0; idx < count; idx++) { if (periods[idx].StartDateTime == dt) { periods.RemoveAt(idx); idx--; count--; } } } } else if (dt >= fromDate.Date && dt <= toDate.Date) { for (idx = 0; idx < count; idx++) { if (periods[idx].StartDateTime.Date == dt) { periods.RemoveAt(idx); idx--; count--; } } } } // Sort the periods and remove duplicates periods.Sort(true); for (idx = 1; idx < count; idx++) { if (periods[idx] == periods[idx - 1]) { periods.RemoveAt(idx); idx--; count--; } } } // Now convert the periods to DateTimeInstances that include the necessary time zone information DateTimeInstanceCollection dtic = new DateTimeInstanceCollection(); DateTimeInstance dti, dtiEnd; // Always in local time if there is no time zone ID if (timeZoneID == null) { inLocalTime = true; } foreach (Period pd in periods) { if (inLocalTime) { dti = VCalendar.TimeZoneTimeToLocalTime(pd.StartDateTime, timeZoneID); dtiEnd = VCalendar.TimeZoneTimeToLocalTime(pd.EndDateTime, timeZoneID); } else { dti = VCalendar.TimeZoneTimeInfo(pd.StartDateTime, timeZoneID); dtiEnd = VCalendar.TimeZoneTimeInfo(pd.EndDateTime, timeZoneID); } dti.Duration = pd.Duration; dti.EndDateTime = dtiEnd.EndDateTime; dti.EndIsDaylightSavingTime = dtiEnd.EndIsDaylightSavingTime; dti.EndTimeZoneName = dtiEnd.EndTimeZoneName; // If it already contains the entry and it is in DST, bump it forward an hour to account for the // time adjustment. This will happen on hourly, minutely, and secondly recurrence patterns. By // moving duplicates forward an hour, we retain the expected number of occurrences. if (!dtic.Contains(dti)) { dtic.Add(dti); } else if (dti.StartIsDaylightSavingTime) { dti.StartDateTime = dti.StartDateTime.AddHours(1); dti.EndDateTime = dti.EndDateTime.AddHours(1); dtic.Add(dti); } } return(dtic); // And finally, we are done }
/// <summary> /// This method is used to parse one or more PDI objects from a <see cref="TextReader"/> derived object /// such as a <see cref="StreamReader"/> or a <see cref="StringReader"/>. /// </summary> /// <param name="tr">The text reader object containing the PDI data stream. It is up to you to open the /// stream with the appropriate text encoding method if necessary.</param> /// <remarks>The derived class will build a list of objects based on the data stream. See the derived /// classes for more information. The stream will be read from its current position to the end of the /// stream.</remarks> /// <seealso cref="VCardParser"/> /// <seealso cref="VCalendarParser"/> /// <exception cref="ArgumentNullException">This is thrown if the specified text reader object is null.</exception> /// <exception cref="PDIParserException">This is thrown if there is an error parsing the data stream. /// Inner exceptions may contain additional information about the cause of the error.</exception> /// <example> /// <code language="cs"> /// VCardParser vcp = new VCardParser(); /// StreamReader sr = new StreamReader(@"C:\AddressBook.vcf"); /// vcp.ParseReader(sr); /// /// VCardCollection vCards = vcp.VCards; /// </code> /// <code language="vbnet"> /// Dim vcp As New VCardParser /// Dim sr As New StreamReader("C:\AddressBook.vcf") /// vcp.ParseReader(sr); /// /// Dim vCards As VCardCollection = vcp.VCards /// </code> /// </example> public void ParseReader(TextReader tr) { char ch; int nch; bool seenLF = false; if (tr == null) { throw new ArgumentNullException("tr", LR.GetString("ExParseNullReader")); } try { this.ResetState(true); while ((nch = tr.Read()) != -1) { ch = (char)nch; // Ignore carriage returns and empty lines if (ch == '\r' || (isStartOfLine && ch == '\n')) { if (ch == '\n') { lineNbr++; } // Some files have a line fold but no data on the last line (a space immediately followed // by CR/LF). In that case, we need to process the line feed to store the value. if (ch == '\r' || !isUnfolding || (isQPValue && isStartOfLine && ch == '\n')) { // Some files contained quoted printable data with a soft line break followed by a // blank line. In those cases, treat it like the end of the line. if (isQPValue && isStartOfLine && ch == '\n') { if (!seenLF) { seenLF = true; continue; } } else { continue; } } } seenLF = false; if (isStartOfLine) { // Start unfolding lines? if (!isUnfolding && Char.IsWhiteSpace(ch)) { isUnfolding = true; continue; } isStartOfLine = false; // If unfolding lines, carry on. This line will be appended to the last one. If not, // process a line feed to terminate the last line and flush any pending information. if (!isUnfolding) { // We should be in the property value except if just starting if (lineNbr > 0 && state != ParserState.PropertyValue) { throw new PDIParserException(lineNbr, LR.GetString("ExParseSepNotFound")); } this.ProcessCharacter('\n'); } // Process the first character of the new line this.ProcessCharacter(ch); } else { // Check for Quoted Printable soft line breaks if (isQPValue && ch == '=' && (tr.Peek() == '\r' || tr.Peek() == '\n')) { isStartOfLine = true; // Unfold soft line break isUnfolding = true; } else if (ch == '\n') { isStartOfLine = true; // End of line isUnfolding = false; lineNbr++; } else // Continuing current line { this.ProcessCharacter(ch); } } } this.Flush(); } catch (PDIParserException) { // Just pass these on unchanged throw; } catch (Exception e) { // Wrap all other exceptions in a PDIParser exception throw new PDIParserException(lineNbr, LR.GetString("ExParseUnexpectedError"), e); } }