Changeset 31 for trunk/UContact.pas
- Timestamp:
- Nov 25, 2021, 1:18:44 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/UContact.pas
r30 r31 6 6 7 7 uses 8 Classes, SysUtils, fgl, Dialogs, UDataFile, LazUTF8, base64;8 Classes, SysUtils, fgl, Dialogs, UDataFile, LazUTF8, Base64; 9 9 10 10 type … … 16 16 17 17 TContactFieldIndex = (cfFirstName, cfMiddleName, cfLastName, cfTitleBefore, 18 cfTitleAfter, cfFullName, cfTelPrefCell, 19 cfTelCell, cfTelHome, cfTelHome2, cfTelWork, cfTelVoip, 20 cfTelPrefWorkVoice, cfTelPrefHomeVoice, cfTelHomeVoice, cfTelWorkVoice, 21 cfTelVoice, cfTelMain, 18 cfTitleAfter, cfFullName, cfTelCell, cfTelHome, cfTelHome2, cfTelWork, cfTelVoip, 19 cfTelMain, cfEmail, 22 20 cfEmailHome, cfEmailInternet, cfNickName, cfNote, cfRole, cfTitle, 23 21 cfCategories, cfOrganization, cfAdrHome, cfHomeAddressStreet, 24 22 cfHomeAddressCity, cfHomeAddressCountry, cfXTimesContacted, 25 cfXLastTimeContacted, cfPhoto, cfXJabber); 23 cfXLastTimeContacted, cfPhoto, cfXJabber, cfDayOfBirth, cfRevision, 24 cfVersion); 26 25 27 26 TContactField = class 27 SysName: string; 28 Groups: TStringArray; 29 Title: string; 30 Index: TContactFieldIndex; 31 ValueIndex: Integer; 32 DataType: TDataType; 33 end; 34 35 { TContactFields } 36 37 TContactFields = class(TFPGObjectList<TContactField>) 38 function AddNew(Name: string; Groups: TStringArray; Title: string; Index: TContactFieldIndex; DataType: 39 TDataType; ValueIndex: Integer = -1): TContactField; 40 function GetByIndex(Index: TContactFieldIndex): TContactField; 41 procedure LoadToStrings(AItems: TStrings); 42 end; 43 44 { TContactProperty } 45 46 TContactProperty = class 28 47 Name: string; 29 Index: TContactFieldIndex; 30 DataType: TDataType; 31 end; 32 33 { TContactFields } 34 35 TContactFields = class(TFPGObjectList<TContactField>) 36 function AddNew(Name: string; Index: TContactFieldIndex; DataType: 37 TDataType): TContactField; 38 procedure LoadToStrings(AItems: TStrings); 48 Attributes: TStringList; 49 Values: TStringList; 50 Encoding: string; 51 Charset: string; 52 procedure EvaluateAttributes; 53 function GetDecodedValue: string; 54 function MatchNameGroups(AName: string; Groups: TStringArray): Boolean; 55 procedure Assign(Source: TContactProperty); 56 constructor Create; 57 destructor Destroy; override; 58 end; 59 60 { TContactProperties } 61 62 TContactProperties = class(TFPGObjectList<TContactProperty>) 63 function GetByName(Name: string): TContactProperty; 64 function GetByNameGroups(Name: string; Groups: TStringArray): TContactProperty; 65 function GetByNameGroupsMultiple(Name: string; Groups: TStringArray): TContactProperties; 39 66 end; 40 67 … … 46 73 procedure SetField(Index: TContactFieldIndex; AValue: string); 47 74 public 75 Properties: TContactProperties; 48 76 Parent: TContactsFile; 49 Version: string; 50 FirstName: string; 51 MiddleName: string; 52 LastName: string; 53 TitleBefore: string; 54 TitleAfter: string; 55 FullName: string; 56 TelPrefCell: string; 57 TelCell: string; 58 TelHome: string; 59 TelHome2: string; 60 TelWork: string; 61 TelVoip: string; 62 TelPrefWorkVoice: string; 63 TelPrefHomeVoice: string; 64 TelHomeVoice: string; 65 TelWorkVoice: string; 66 TelVoice: string; 67 TelMain: string; 68 EmailHome: string; 69 EmailInternet: string; 70 NickName: string; 71 Note: string; 72 Role: string; 73 Title: string; 74 Categories: string; 75 Organization: string; 76 AdrHome: string; 77 HomeAddressStreet: string; 78 HomeAddressCity: string; 79 HomeAddressCountry: string; 80 XTimesContacted: string; 81 XLastTimeContacted: string; 82 Photo: string; 83 XJabber: string; 77 function GetProperty(Index: TContactFieldIndex): TContactProperty; 84 78 procedure Assign(Source: TContact); 85 79 function UpdateFrom(Source: TContact): Boolean; 80 constructor Create; 81 destructor Destroy; override; 86 82 property Fields[Index: TContactFieldIndex]: string read GetField write SetField; 87 83 end; … … 101 97 private 102 98 FOnError: TErrorEvent; 103 function GetNext(var Text: string; Separator: string): string;104 99 procedure InitFields; 105 100 procedure Error(Text: string; Line: Integer); 101 function NewItem(Key, Value: string): string; 106 102 public 107 103 Fields: TContactFields; … … 126 122 SFoundPropertiesBeforeBlockStart = 'Found properties before the start of block'; 127 123 SFoundBlockEndWithoutBlockStart = 'Found block end without block start'; 128 129 { TContacts } 130 131 function TContacts.AddNew: TContact; 132 begin 133 Result := TContact.Create; 134 Result.Parent := ContactsFile; 135 Add(Result); 136 end; 137 138 function TContacts.Search(FullName: string): TContact; 139 var 140 Contact: TContact; 141 begin 142 Result := nil; 143 for Contact in Self do 144 if Contact.FullName = FullName then begin 145 Result := Contact; 146 Break; 147 end; 148 end; 149 150 function TContacts.ToString: ansistring; 151 var 152 I: Integer; 153 begin 154 Result := ''; 155 for I := 0 to Count - 1 do begin 156 if I > 0 then Result := Result + ', '; 157 Result := Result + TContact(Items[I]).FullName; 158 end; 159 end; 160 161 { TContactFields } 162 163 function TContactFields.AddNew(Name: string; Index: TContactFieldIndex; 164 DataType: TDataType): TContactField; 165 begin 166 Result := TContactField.Create; 167 Result.Name := Name; 168 Result.Index := Index; 169 Result.DataType := DataType; 170 Add(Result); 171 end; 172 173 procedure TContactFields.LoadToStrings(AItems: TStrings); 174 var 175 I: Integer; 176 begin 177 while AItems.Count < Count do AItems.Add(''); 178 while AItems.Count > Count do AItems.Delete(AItems.Count - 1); 179 for I := 0 to Count - 1 do 180 AItems[I] := TContactField(Items[I]).Name; 181 end; 182 183 { TContact } 184 185 function TContact.GetField(Index: TContactFieldIndex): string; 186 begin 187 case Index of 188 cfFirstName: Result := FirstName; 189 cfMiddleName: Result := MiddleName; 190 cfLastName: Result := LastName; 191 cfTitleBefore: Result := TitleBefore; 192 cfTitleAfter: Result := TitleAfter; 193 cfFullName: Result := FullName; 194 cfTelPrefCell: Result := TelPrefCell; 195 cfTelCell: Result := TelCell; 196 cfTelHome: Result := TelHome; 197 cfTelHome2: Result := TelHome2; 198 cfTelWork: Result := TelWork; 199 cfTelVoip: Result := TelVoip; 200 cfTelPrefWorkVoice: Result := TelPrefWorkVoice; 201 cfTelPrefHomeVoice: Result := TelPrefHomeVoice; 202 cfTelHomeVoice: Result := TelHomeVoice; 203 cfTelWorkVoice: Result := TelWorkVoice; 204 cfTelVoice: Result := TelVoice; 205 cfTelMain: Result := TelMain; 206 cfEmailHome: Result := EmailHome; 207 cfEmailInternet: Result := EmailInternet; 208 cfNickName: Result := NickName; 209 cfNote: Result := Note; 210 cfRole: Result := Role; 211 cfTitle: Result := Title; 212 cfCategories: Result := Categories; 213 cfOrganization: Result := Organization; 214 cfAdrHome: Result := AdrHome; 215 cfHomeAddressStreet: Result := HomeAddressStreet; 216 cfHomeAddressCity: Result := HomeAddressCity; 217 cfHomeAddressCountry: Result := HomeAddressCountry; 218 cfXTimesContacted: Result := XTimesContacted; 219 cfXLastTimeContacted: Result := XLastTimeContacted; 220 cfPhoto: Result := Photo; 221 cfXJabber: Result := XJabber; 222 else raise Exception.Create(SUnsupportedContactFieldsIndex); 223 end; 224 end; 225 226 procedure TContact.SetField(Index: TContactFieldIndex; AValue: string); 227 begin 228 case Index of 229 cfFirstName: FirstName := AValue; 230 cfMiddleName: MiddleName := AValue; 231 cfLastName: LastName := AValue; 232 cfTitleBefore: TitleBefore := AValue; 233 cfTitleAfter: TitleAfter := AValue; 234 cfFullName: FullName := AValue; 235 cfTelPrefCell: TelPrefCell := AValue; 236 cfTelCell: TelCell := AValue; 237 cfTelHome: TelHome := AValue; 238 cfTelHome2: TelHome2 := AValue; 239 cfTelWork: TelWork := AValue; 240 cfTelVoip: TelVoip := AValue; 241 cfTelPrefWorkVoice: TelPrefWorkVoice := AValue; 242 cfTelPrefHomeVoice: TelPrefHomeVoice := AValue; 243 cfTelHomeVoice: TelHomeVoice := AValue; 244 cfTelWorkVoice: TelWorkVoice := AValue; 245 cfTelVoice: TelVoice := AValue; 246 cfTelMain: TelMain := AValue; 247 cfEmailHome: EmailHome := AValue; 248 cfEmailInternet: EmailInternet := AValue; 249 cfNickName: NickName := AValue; 250 cfNote: Note := AValue; 251 cfRole: Role := AValue; 252 cfTitle: Title := AValue; 253 cfCategories: Categories := AValue; 254 cfOrganization: Organization := AValue; 255 cfAdrHome: AdrHome := AValue; 256 cfHomeAddressStreet: HomeAddressStreet := AValue; 257 cfHomeAddressCity: HomeAddressCity := AValue; 258 cfHomeAddressCountry: HomeAddressCountry := AValue; 259 cfXTimesContacted: XTimesContacted := AValue; 260 cfXLastTimeContacted: XLastTimeContacted := AValue; 261 cfPhoto: Photo := AValue; 262 cfXJabber: XJabber := AValue; 263 else raise Exception.Create(SUnsupportedContactFieldsIndex); 264 end; 265 end; 266 267 procedure TContact.Assign(Source: TContact); 268 begin 269 Version := Source.Version; 270 FirstName := Source.FirstName; 271 MiddleName := Source.MiddleName; 272 LastName := Source.LastName; 273 TitleBefore := Source.TitleBefore; 274 TitleAfter := Source.TitleAfter; 275 FullName := Source.FullName; 276 TelPrefCell := Source.TelPrefCell; 277 TelCell := Source.TelCell; 278 TelHome := Source.TelHome; 279 TelHome2 := Source.TelHome2; 280 TelWork := Source.TelWork; 281 TelVoip := Source.TelVoip; 282 TelPrefWorkVoice := Source.TelPrefWorkVoice; 283 TelPrefHomeVoice := Source.TelPrefHomeVoice; 284 TelHomeVoice := Source.TelHomeVoice; 285 TelWorkVoice := Source.TelWorkVoice; 286 EmailHome := Source.EmailHome; 287 EmailInternet := Source.EmailInternet; 288 NickName := Source.NickName; 289 Note := Source.Note; 290 Role := Source.Role; 291 Title := Source.Title; 292 Categories := Source.Categories; 293 Organization := Source.Organization; 294 AdrHome := Source.AdrHome; 295 HomeAddressStreet := Source.HomeAddressStreet; 296 HomeAddressCity := Source.HomeAddressCity; 297 HomeAddressCountry := Source.HomeAddressCountry; 298 XTimesContacted := Source.XTimesContacted; 299 XLastTimeContacted := Source.XLastTimeContacted; 300 Photo := Source.Photo; 301 XJabber := Source.XJabber; 302 end; 303 304 function TContact.UpdateFrom(Source: TContact): Boolean; 305 var 306 I: Integer; 307 begin 308 Result := False; 309 for I := 0 to Parent.Fields.Count - 1 do begin 310 if (Source.Fields[TContactField(Parent.Fields[I]).Index] <> '') and 311 (Source.Fields[TContactField(Parent.Fields[I]).Index] <> 312 Fields[TContactField(Parent.Fields[I]).Index]) then begin 313 Result := True; 314 Fields[TContactField(Parent.Fields[I]).Index] := Source.Fields[TContactField(Parent.Fields[I]).Index]; 315 end; 316 end; 317 end; 318 319 { TContactsFile } 320 321 function TContactsFile.GetNext(var Text: string; Separator: string): string; 124 SFieldIndexNotDefined = 'Field index not defined'; 125 126 function GetNext(var Text: string; Separator: string): string; 322 127 begin 323 128 if Pos(Separator, Text) > 0 then begin … … 330 135 end; 331 136 332 procedure TContactsFile.InitFields;333 begin334 with Fields do begin335 AddNew('First Name', cfFirstName, dtString);336 AddNew('Middle Name', cfMiddleName, dtString);337 AddNew('Last Name', cfLastName, dtString);338 AddNew('Title Before', cfTitleBefore, dtString);339 AddNew('Title After', cfTitleAfter, dtString);340 AddNew('Full Name', cfFullName, dtString);341 AddNew('Preferred cell phone', cfTelPrefCell, dtString);342 AddNew('Cell phone', cfTelCell, dtString);343 AddNew('Home phone', cfTelHome, dtString);344 AddNew('Home phone 2', cfTelHome2, dtString);345 AddNew('Home work', cfTelWork, dtString);346 AddNew('Tel Voip', cfTelVoip, dtString);347 AddNew('Tel Pref Work Voice', cfTelPrefWorkVoice, dtString);348 AddNew('Tel Pref Home Voice', cfTelPrefHomeVoice, dtString);349 AddNew('Tel Home Voice', cfTelHomeVoice, dtString);350 AddNew('Tel Work Voice', cfTelWorkVoice, dtString);351 AddNew('Tel Voice', cfTelVoice, dtString);352 AddNew('Tel Main', cfTelMain, dtString);353 AddNew('Email Home', cfEmailHome, dtString);354 AddNew('Email Internet', cfEmailInternet, dtString);355 AddNew('Nick Name', cfNickName, dtString);356 AddNew('Note', cfNote, dtString);357 AddNew('Role', cfRole, dtString);358 AddNew('Title', cfTitle, dtString);359 AddNew('Categories', cfCategories, dtString);360 AddNew('Organization', cfOrganization, dtString);361 AddNew('Home Address', cfAdrHome, dtString);362 AddNew('Home Address Street', cfHomeAddressStreet, dtString);363 AddNew('Home Address City', cfHomeAddressCity, dtString);364 AddNew('Home Address Country', cfHomeAddressCountry, dtString);365 AddNew('Times Contacted', cfXTimesContacted, dtString);366 AddNew('Last Time Contacted', cfXLastTimeContacted, dtString);367 AddNew('Photo', cfPhoto, dtString);368 AddNew('Jabber', cfXJabber, dtString);369 end;370 end;371 372 procedure TContactsFile.Error(Text: string; Line: Integer);373 begin374 if Assigned(FOnError) then FOnError(Text, Line);375 end;376 377 function TContactsFile.GetFileName: string;378 begin379 Result := SVCardFile;380 end;381 382 function TContactsFile.GetFileExt: string;383 begin384 Result := '.vcf';385 end;386 387 function TContactsFile.GetFileFilter: string;388 begin389 Result := GetFileName + ' (' + GetFileExt + ')|*' + GetFileExt + '|' + inherited;390 end;391 392 procedure TContactsFile.SaveToFile(FileName: string);393 var394 Output: TStringList;395 I: Integer;396 PhotoBase64: string;397 Line: string;398 399 137 function IsAsciiString(Text: string): Boolean; 400 138 var … … 409 147 end; 410 148 411 function NewItem(Key, Value: string): string; 149 { TContactProperties } 150 151 function TContactProperties.GetByName(Name: string): TContactProperty; 152 var 153 I: Integer; 154 begin 155 I := 0; 156 while (I < Count) and (Items[I].Name <> Name) do Inc(I); 157 if I < Count then Result := Items[I] 158 else Result := nil; 159 end; 160 161 function TContactProperties.GetByNameGroups(Name: string; Groups: TStringArray 162 ): TContactProperty; 163 var 164 I: Integer; 165 begin 166 I := 0; 167 while (I < Count) and not Items[I].MatchNameGroups(Name, Groups) do Inc(I); 168 if I < Count then Result := Items[I] 169 else Result := nil; 170 end; 171 172 function TContactProperties.GetByNameGroupsMultiple(Name: string; 173 Groups: TStringArray): TContactProperties; 174 var 175 I: Integer; 176 begin 177 Result := TContactProperties.Create(False); 178 for I := 0 to Count - 1 do 179 if Items[I].MatchNameGroups(Name, Groups) then 180 Result.Add(Items[I]); 181 end; 182 183 { TContactProperty } 184 185 procedure TContactProperty.EvaluateAttributes; 186 begin 187 if Attributes.IndexOfName('ENCODING') <> -1 then 188 Encoding := Attributes.Values['ENCODING'] 189 else Encoding := ''; 190 if Attributes.IndexOfName('CHARSET') <> -1 then 191 Charset := Attributes.Values['CHARSET'] 192 else Charset := ''; 193 end; 194 195 function TContactProperty.GetDecodedValue: string; 196 begin 197 if Encoding = 'BASE64' then 198 Result := DecodeStringBase64(Values.DelimitedText) 199 else 200 if Encoding = 'QUOTED-PRINTABLE' then 201 Result := Values.DelimitedText 202 else Result := ''; 203 end; 204 205 function TContactProperty.MatchNameGroups(AName: string; Groups: TStringArray 206 ): Boolean; 207 var 208 I: Integer; 209 begin 210 Result := Name = AName; 211 if Result then begin 212 for I := 0 to Length(Groups) - 1 do 213 if Attributes.IndexOf(Groups[I]) = -1 then begin 214 Result := False; 215 Break; 216 end; 217 end; 218 end; 219 220 procedure TContactProperty.Assign(Source: TContactProperty); 221 begin 222 Name := Source.Name; 223 Attributes.Assign(Source.Attributes); 224 Values.Assign(Source.Values); 225 end; 226 227 constructor TContactProperty.Create; 228 begin 229 Attributes := TStringList.Create; 230 Attributes.Delimiter := ';'; 231 Attributes.NameValueSeparator := '='; 232 Attributes.StrictDelimiter := True; 233 Values := TStringList.Create; 234 Values.Delimiter := ';'; 235 Values.NameValueSeparator := '='; 236 Values.StrictDelimiter := True; 237 end; 238 239 destructor TContactProperty.Destroy; 240 begin 241 FreeAndNil(Values); 242 FreeAndNil(Attributes); 243 inherited; 244 end; 245 246 { TContacts } 247 248 function TContacts.AddNew: TContact; 249 begin 250 Result := TContact.Create; 251 Result.Parent := ContactsFile; 252 Add(Result); 253 end; 254 255 function TContacts.Search(FullName: string): TContact; 256 var 257 Contact: TContact; 258 begin 259 Result := nil; 260 for Contact in Self do 261 if Contact.Fields[cfFullName] = FullName then begin 262 Result := Contact; 263 Break; 264 end; 265 end; 266 267 function TContacts.ToString: ansistring; 268 var 269 I: Integer; 270 begin 271 Result := ''; 272 for I := 0 to Count - 1 do begin 273 if I > 0 then Result := Result + ', '; 274 Result := Result + Items[I].Fields[cfFullName]; 275 end; 276 end; 277 278 { TContactFields } 279 280 function TContactFields.AddNew(Name: string; Groups: TStringArray; Title: string; Index: TContactFieldIndex; 281 DataType: TDataType; ValueIndex: Integer = -1): TContactField; 282 begin 283 Result := TContactField.Create; 284 Result.SysName := Name; 285 Result.Groups := Groups; 286 Result.Title := Title; 287 Result.Index := Index; 288 Result.ValueIndex := ValueIndex; 289 Result.DataType := DataType; 290 Add(Result); 291 end; 292 293 function TContactFields.GetByIndex(Index: TContactFieldIndex): TContactField; 294 var 295 I: Integer; 296 begin 297 I := 0; 298 while (I < Count) and (Items[I].Index <> Index) do Inc(I); 299 if I < Count then Result := Items[I] 300 else Result := nil; 301 end; 302 303 procedure TContactFields.LoadToStrings(AItems: TStrings); 304 var 305 I: Integer; 306 begin 307 while AItems.Count < Count do AItems.Add(''); 308 while AItems.Count > Count do AItems.Delete(AItems.Count - 1); 309 for I := 0 to Count - 1 do 310 AItems[I] := Items[I].Title; 311 end; 312 313 { TContact } 314 315 function TContact.GetField(Index: TContactFieldIndex): string; 316 var 317 Prop: TContactProperty; 318 Field: TContactField; 319 begin 320 Prop := GetProperty(Index); 321 if Assigned(Prop) then begin 322 Field := Parent.Fields.GetByIndex(Index); 323 if Field.ValueIndex <> -1 then begin 324 if Field.ValueIndex < Prop.Values.Count then 325 Result := Prop.Values.Strings[Field.ValueIndex] 326 else Result := ''; 327 end else Result := Prop.Values.DelimitedText; 328 end else Result := ''; 329 end; 330 331 procedure TContact.SetField(Index: TContactFieldIndex; AValue: string); 332 var 333 Prop: TContactProperty; 334 Field: TContactField; 335 I: Integer; 336 begin 337 Field := Parent.Fields.GetByIndex(Index); 338 if Assigned(Field) then begin 339 Prop := Properties.GetByNameGroups(Field.SysName, Field.Groups); 340 if not Assigned(Prop) then begin 341 Prop := TContactProperty.Create; 342 Prop.Name := Field.SysName; 343 for I := 0 to Length(Field.Groups) - 1 do 344 Prop.Attributes.Add(Field.Groups[I]); 345 Properties.Add(Prop); 346 end; 347 if Field.ValueIndex <> -1 then begin 348 while Prop.Values.Count <= Field.ValueIndex do Prop.Values.Add(''); 349 Prop.Values.Strings[Field.ValueIndex] := AValue 350 end else Prop.Values.DelimitedText := AValue; 351 end else raise Exception.Create(SFieldIndexNotDefined); 352 end; 353 354 function TContact.GetProperty(Index: TContactFieldIndex): TContactProperty; 355 var 356 Prop: TContactProperty; 357 Field: TContactField; 358 begin 359 Field := Parent.Fields.GetByIndex(Index); 360 if Assigned(Field) then begin 361 Result := Properties.GetByNameGroups(Field.SysName, Field.Groups); 362 end else raise Exception.Create(SFieldIndexNotDefined); 363 end; 364 365 procedure TContact.Assign(Source: TContact); 366 begin 367 Properties.Assign(Source.Properties); 368 end; 369 370 function TContact.UpdateFrom(Source: TContact): Boolean; 371 var 372 I: Integer; 373 begin 374 Result := False; 375 for I := 0 to Parent.Fields.Count - 1 do begin 376 if (Source.Fields[Parent.Fields[I].Index] <> '') and 377 (Source.Fields[Parent.Fields[I].Index] <> 378 Fields[Parent.Fields[I].Index]) then begin 379 Result := True; 380 Fields[Parent.Fields[I].Index] := Source.Fields[Parent.Fields[I].Index]; 381 end; 382 end; 383 end; 384 385 constructor TContact.Create; 386 begin 387 Properties := TContactProperties.Create; 388 end; 389 390 destructor TContact.Destroy; 391 begin 392 FreeAndNil(Properties); 393 inherited; 394 end; 395 396 { TContactsFile } 397 398 procedure TContactsFile.InitFields; 399 begin 400 with Fields do begin 401 AddNew('N', [], 'Last Name', cfLastName, dtString, 0); 402 AddNew('N', [], 'First Name', cfFirstName, dtString, 1); 403 AddNew('N', [], 'Middle Name', cfMiddleName, dtString, 2); 404 AddNew('N', [], 'Title Before', cfTitleBefore, dtString, 3); 405 AddNew('N', [], 'Title After', cfTitleAfter, dtString, 4); 406 AddNew('FN', [], 'Full Name', cfFullName, dtString); 407 AddNew('TEL', ['CELL'], 'Cell phone', cfTelCell, dtString); 408 AddNew('TEL', ['HOME'], 'Home phone', cfTelHome, dtString); 409 AddNew('TEL', ['HOME2'], 'Home phone 2', cfTelHome2, dtString); 410 AddNew('TEL', ['WORK'], 'Home work', cfTelWork, dtString); 411 AddNew('TEL', ['VOIP'], 'Tel VoIP', cfTelVoip, dtString); 412 AddNew('TEL', ['MAIN'], 'Tel Main', cfTelMain, dtString); 413 AddNew('EMAIL', [], 'Email', cfEmail, dtString); 414 AddNew('EMAIL', ['HOME'], 'Email Home', cfEmailHome, dtString); 415 AddNew('EMAIL', ['INTERNET'], 'Email Internet', cfEmailInternet, dtString); 416 AddNew('X-NICKNAME', [], 'Nick Name', cfNickName, dtString); 417 AddNew('NOTE', [], 'Note', cfNote, dtString); 418 AddNew('ROLE', [], 'Role', cfRole, dtString); 419 AddNew('TITLE', [], 'Title', cfTitle, dtString); 420 AddNew('CATEGORIES', [], 'Categories', cfCategories, dtString); 421 AddNew('ORG', [], 'Organization', cfOrganization, dtString); 422 AddNew('ADR', ['HOME'], 'Home Address', cfAdrHome, dtString); 423 AddNew('ADR', ['HOME'], 'Home Address Street', cfHomeAddressStreet, dtString, 1); 424 AddNew('ADR', ['HOME'], 'Home Address City', cfHomeAddressCity, dtString, 2); 425 AddNew('ADR', ['HOME'], 'Home Address Country', cfHomeAddressCountry, dtString, 3); 426 AddNew('X-TIMES_CONTACTED', [], 'Times Contacted', cfXTimesContacted, dtString); 427 AddNew('X-LAST_TIME_CONTACTED', [], 'Last Time Contacted', cfXLastTimeContacted, dtString); 428 AddNew('PHOTO', [], 'Photo', cfPhoto, dtString); 429 AddNew('X-JABBER', [], 'Jabber', cfXJabber, dtString); 430 AddNew('BDAY', [], 'Day of birth', cfDayOfBirth, dtString); 431 AddNew('REV', [], 'Revision', cfRevision, dtString); 432 end; 433 end; 434 435 procedure TContactsFile.Error(Text: string; Line: Integer); 436 begin 437 if Assigned(FOnError) then FOnError(Text, Line); 438 end; 439 440 function TContactsFile.GetFileName: string; 441 begin 442 Result := SVCardFile; 443 end; 444 445 function TContactsFile.GetFileExt: string; 446 begin 447 Result := '.vcf'; 448 end; 449 450 function TContactsFile.GetFileFilter: string; 451 begin 452 Result := GetFileName + ' (' + GetFileExt + ')|*' + GetFileExt + '|' + inherited; 453 end; 454 455 function TContactsFile.NewItem(Key, Value: string): string; 412 456 var 413 457 Charset: string; … … 418 462 end; 419 463 464 procedure TContactsFile.SaveToFile(FileName: string); 465 var 466 Output: TStringList; 467 I: Integer; 468 J: Integer; 469 Value: string; 470 NameText: string; 420 471 begin 421 472 inherited; … … 423 474 Output := TStringList.Create; 424 475 for I := 0 to Contacts.Count - 1 do 425 with TContact(Contacts[I]), Output do begin476 with Contacts[I], Output do begin 426 477 Add('BEGIN:VCARD'); 427 if Version <> '' then Add('VERSION:' + Version); 428 if XTimesContacted <> '' then Add('X-TIMES_CONTACTED:' + XTimesContacted); 429 if XLastTimeContacted <> '' then Add('X-LAST_TIME_CONTACTED:' + XLastTimeContacted); 430 if (LastName <> '') or (FirstName <> '') or (MiddleName <> '') or (TitleBefore <> '') or (TitleAfter <> '') then 431 Add(NewItem('N', LastName + ';' + FirstName + ';' + MiddleName + ';' + TitleBefore + ';' + TitleAfter)); 432 if FullName <> '' then Add(NewItem('FN', FullName)); 433 if TelCell <> '' then Add('TEL;CELL:' + TelCell); 434 if TelPrefCell <> '' then Add('TEL;PREF;CELL:' + TelPrefCell); 435 if TelHome <> '' then Add('TEL;HOME:' + TelHome); 436 if TelHome2 <> '' then Add('TEL;HOME2:' + TelHome2); 437 if TelWork <> '' then Add('TEL;WORK:' + TelWork); 438 if TelVoip <> '' then Add('TEL;VOIP:' + TelVoip); 439 if TelPrefWorkVoice <> '' then Add('TEL;PREF;WORK;VOICE:' + TelPrefWorkVoice); 440 if TelPrefHomeVoice <> '' then Add('TEL;PREF;HOME;VOICE:' + TelPrefHomeVoice); 441 if TelHomeVoice <> '' then Add('TEL;HOME;VOICE:' + TelHomeVoice); 442 if TelWorkVoice <> '' then Add('TEL;WORK;VOICE:' + TelWorkVoice); 443 if TelVoice <> '' then Add('TEL;VOICE:' + TelVoice); 444 if TelMain <> '' then Add('TEL;MAIN:' + TelMain); 445 if Note <> '' then Add('NOTE:' + Note); 446 if AdrHome <> '' then Add('ADR;HOME:' + AdrHome); 447 if EmailHome <> '' then Add('EMAIL;HOME:' + EmailHome); 448 if NickName <> '' then Add('X-NICKNAME:' + NickName); 449 if EmailInternet <> '' then Add('EMAIL;INTERNET:' + EmailInternet); 450 if XJabber <> '' then Add('X-JABBER:' + XJabber); 451 if Role <> '' then Add('TITLE:' + Role); 452 if Categories <> '' then Add('CATEGORIES:' + Categories); 453 if Organization <> '' then Add('ORG:' + Organization); 454 if (HomeAddressCity <> '') or (HomeAddressStreet <> '') or 455 (HomeAddressCountry <> '') then Add('ADR;HOME:;;' + HomeAddressStreet + ';' + HomeAddressCity + ';;;' + HomeAddressCountry); 456 if Photo <> '' then begin 457 PhotoBase64 := EncodeStringBase64(Photo); 458 459 Line := Copy(PhotoBase64, 1, 73 - Length('PHOTO;ENCODING=BASE64;JPEG:')); 460 System.Delete(PhotoBase64, 1, Length(Line)); 461 Add('PHOTO;ENCODING=BASE64;JPEG:' + Line); 462 while PhotoBase64 <> '' do begin 463 Line := Copy(PhotoBase64, 1, 73); 464 System.Delete(PhotoBase64, 1, Length(Line)); 465 Add(' ' + Line); 478 for J := 0 to Properties.Count - 1 do 479 with Properties[J] do begin 480 Value := Values.DelimitedText; 481 if Pos(LineEnding, Value) > 0 then begin 482 NameText := Name; 483 if Attributes.Count > 0 then 484 NameText := NameText + ';' + Attributes.DelimitedText; 485 Add(NameText + ':' + GetNext(Value, LineEnding)); 486 while Pos(LineEnding, Value) > 0 do begin 487 Add(' ' + GetNext(Value, LineEnding)); 488 end; 489 Add(' ' + GetNext(Value, LineEnding)); 490 Add(''); 491 end else begin 492 NameText := Name; 493 if Attributes.Count > 0 then 494 NameText := NameText + ';' + Attributes.DelimitedText; 495 Add(NameText + ':' + Value); 466 496 end; 467 Add('');468 497 end; 469 498 Add('END:VCARD'); … … 479 508 Lines: TStringList; 480 509 Line: string; 510 Value: string; 481 511 I: Integer; 482 512 NewRecord: TContact; 483 Command: string;513 NewProperty: TContactProperty; 484 514 CommandPart: string; 485 Charset: string; 486 Encoding: string; 487 Language: string; 488 CommandItems: TStringList; 515 Names: string; 489 516 begin 490 517 inherited; … … 494 521 Lines.LoadFromFile(FileName); 495 522 try 496 CommandItems := TStringList.Create;497 CommandItems.Delimiter := ';';498 523 I := 0; 499 524 while I < Lines.Count do begin 500 525 Line := Lines[I]; 526 if Line = '' then 527 else 501 528 if Line = 'BEGIN:VCARD' then begin 502 529 NewRecord := TContact.Create; … … 511 538 if Pos(':', Line) > 0 then begin 512 539 CommandPart := GetNext(Line, ':'); 513 CommandItems.DelimitedText := CommandPart;514 if CommandItems.IndexOfName('CHARSET') >= 0 then begin515 Charset := CommandItems.Values['CHARSET'];516 CommandItems.Delete(CommandItems.IndexOfName('CHARSET'));517 end518 else if CommandItems.IndexOfName('ENCODING') >= 0 then begin519 Encoding := CommandItems.Values['ENCODING'];520 CommandItems.Delete(CommandItems.IndexOfName('ENCODING'));521 end522 else if CommandItems.IndexOfName('LANGUAGE') >= 0 then begin523 Language := CommandItems.Values['LANGUAGE'];524 CommandItems.Delete(CommandItems.IndexOfName('LANGUAGE'));525 end;526 Command := CommandItems.DelimitedText;527 528 540 if Assigned(NewRecord) then begin 529 if Command = 'FN' then NewRecord.FullName := Line 530 else if Command = 'N' then begin 531 NewRecord.LastName := GetNext(Line, ';'); 532 NewRecord.FirstName := GetNext(Line, ';'); 533 NewRecord.MiddleName := GetNext(Line, ';'); 534 NewRecord.TitleBefore := GetNext(Line, ';'); 535 NewRecord.TitleAfter := GetNext(Line, ';'); 536 end 537 else if Command = 'VERSION' then NewRecord.Version := Line 538 else if Command = 'TEL;PREF;CELL' then NewRecord.TelPrefCell := Line 539 else if Command = 'TEL;CELL' then NewRecord.TelCell := Line 540 else if Command = 'TEL;HOME' then NewRecord.TelHome := Line 541 else if Command = 'TEL;HOME2' then NewRecord.TelHome2 := Line 542 else if Command = 'TEL;WORK' then NewRecord.TelWork := Line 543 else if Command = 'TEL;VOIP' then NewRecord.TelVoip := Line 544 else if Command = 'TEL;PREF;WORK;VOICE' then NewRecord.TelPrefWorkVoice := Line 545 else if Command = 'TEL;PREF;HOME;VOICE' then NewRecord.TelPrefHOMEVoice := Line 546 else if Command = 'TEL;HOME;VOICE' then NewRecord.TelHomeVoice := Line 547 else if Command = 'TEL;WORK;VOICE' then NewRecord.TelWorkVoice := Line 548 else if Command = 'TEL;VOICE' then NewRecord.TelVoice := Line 549 else if Command = 'TEL;MAIN' then NewRecord.TelMain := Line 550 else if Command = 'ADR;HOME' then NewRecord.AdrHome := Line 551 else if Command = 'X-NICKNAME' then NewRecord.NickName := Line 552 else if Command = 'EMAIL;HOME' then NewRecord.EmailHome := Line 553 else if Command = 'EMAIL;INTERNET' then NewRecord.EmailInternet := Line 554 else if Command = 'NOTE' then NewRecord.Note := Line 555 else if Command = 'ORG' then NewRecord.Organization := Line 556 else if Command = 'X-JABBER' then NewRecord.XJabber := Line 557 else if Command = 'TITLE' then NewRecord.Role := Line 558 else if Command = 'X-TIMES_CONTACTED' then NewRecord.XTimesContacted := Line 559 else if Command = 'X-LAST_TIME_CONTACTED' then NewRecord.XLastTimeContacted := Line 560 else if Command = 'PHOTO;JPEG' then begin 561 NewRecord.Photo := Trim(Line); 562 repeat 563 Inc(I); 564 Line := Trim(Lines[I]); 565 if Line <> '' then NewRecord.Photo := NewRecord.Photo + Line; 566 until Line = ''; 567 NewRecord.Photo := DecodeStringBase64(NewRecord.Photo); 568 end 569 else Error(Format(SUnknownCommand, [Command]), I + 1); 541 Names := CommandPart; 542 Value := Line; 543 while True do begin 544 Inc(I); 545 if (Length(Lines[I]) > 0) and (Lines[I][1] = ' ') then begin 546 Value := Value + Trim(Lines[I]); 547 end else begin 548 Dec(I); 549 Break; 550 end; 551 end; 552 NewProperty := NewRecord.Properties.GetByName(Names); 553 if not Assigned(NewProperty) then begin 554 NewProperty := TContactProperty.Create; 555 NewRecord.Properties.Add(NewProperty); 556 end; 557 NewProperty.Attributes.DelimitedText := Names; 558 if NewProperty.Attributes.Count > 0 then begin 559 NewProperty.Name := NewProperty.Attributes[0]; 560 NewProperty.Attributes.Delete(0); 561 end; 562 NewProperty.Values.DelimitedText := Value; 563 NewProperty.EvaluateAttributes; 570 564 end else Error(SFoundPropertiesBeforeBlockStart, I + 1); 571 565 end; 572 566 Inc(I); 573 567 end; 574 CommandItems.Free;575 568 finally 576 569 Lines.Free;
Note:
See TracChangeset
for help on using the changeset viewer.