2018-06-14 15:15:18 +00:00
|
|
|
{ Imports vCard contact files }
|
2018-06-08 20:03:23 +00:00
|
|
|
|
|
|
|
unit VpVCard;
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
uses
|
2018-06-14 15:15:18 +00:00
|
|
|
Classes, SysUtils, VpBaseDataFiles;
|
|
|
|
|
|
|
|
const
|
|
|
|
ITEM_SEPARATOR = ';';
|
2018-06-08 20:03:23 +00:00
|
|
|
|
|
|
|
type
|
2018-06-14 15:15:18 +00:00
|
|
|
TVpVCardItem = class(TVpFileItem)
|
2018-06-08 20:03:23 +00:00
|
|
|
end;
|
|
|
|
|
2018-06-14 15:15:18 +00:00
|
|
|
TVpVCard = class(TVpFileBlock)
|
2018-06-08 20:03:23 +00:00
|
|
|
private
|
|
|
|
FVersion: String;
|
|
|
|
|
|
|
|
FFirstName: String;
|
|
|
|
FLastName: String;
|
|
|
|
FTitle: String;
|
|
|
|
|
|
|
|
FCompany: String;
|
|
|
|
FWorkAddress: String;
|
|
|
|
FWorkCity: String;
|
|
|
|
FWorkZip: String;
|
|
|
|
FWorkState: String;
|
|
|
|
FWorkCountry: String;
|
|
|
|
FWorkEMail: String;
|
|
|
|
FWorkPhone: String;
|
|
|
|
FWorkFax: String;
|
|
|
|
|
|
|
|
FHomeAddress: String;
|
|
|
|
FHomeCity: String;
|
|
|
|
FHomeZip: String;
|
|
|
|
FHomeState: String;
|
|
|
|
FHomeCountry: String;
|
|
|
|
FHomeEMail: String;
|
|
|
|
FHomePhone: String;
|
|
|
|
FHomeFax: String;
|
|
|
|
|
|
|
|
FMobile: String;
|
|
|
|
FCarPhone: String;
|
|
|
|
FISDN: String;
|
|
|
|
FPager: String;
|
2022-08-18 17:44:47 +00:00
|
|
|
|
|
|
|
FBirthDay: TDateTime;
|
|
|
|
FAnniversary: TDateTime;
|
2022-08-19 10:53:49 +00:00
|
|
|
FCategories: TStrings;
|
|
|
|
FPickedCategory: Integer;
|
2022-08-11 20:32:13 +00:00
|
|
|
|
2022-08-19 14:06:54 +00:00
|
|
|
FChecked: Boolean;
|
2022-08-19 10:53:49 +00:00
|
|
|
|
|
|
|
function GetCategory(AIndex: Integer): String;
|
|
|
|
function GetCategoryCount: Integer;
|
2018-06-08 20:03:23 +00:00
|
|
|
public
|
|
|
|
constructor Create;
|
2022-08-19 10:53:49 +00:00
|
|
|
destructor Destroy; override;
|
2018-06-14 15:15:18 +00:00
|
|
|
procedure Analyze; override;
|
2018-06-08 20:03:23 +00:00
|
|
|
function FindItem(AKey, ATags: String): TVpVCardItem;
|
2022-08-11 20:32:13 +00:00
|
|
|
|
|
|
|
function GetEMail: String;
|
|
|
|
function GetFullName: String;
|
|
|
|
function GetHomeAddress: String;
|
|
|
|
function GetPhone: String;
|
|
|
|
function GetWorkAddress: String;
|
2018-06-08 20:03:23 +00:00
|
|
|
|
2022-08-18 17:44:47 +00:00
|
|
|
procedure SaveToStrings(AList: TStrings);
|
|
|
|
|
|
|
|
property FirstName: String read FFirstName write FFirstName;
|
|
|
|
property LastName: String read FLastName write FLastName;
|
|
|
|
property Title: String read FTitle write FTitle;
|
|
|
|
|
|
|
|
property Company: String read FCompany write FCompany;
|
|
|
|
property WorkAddress: String read FWorkAddress write FWorkAddress;
|
|
|
|
property WorkCity: String read FWorkCity write FWorkCity;
|
|
|
|
property WorkZip: String read FWorkZip write FWorkZip;
|
|
|
|
property WorkState: String read FWorkState write FWorkState;
|
|
|
|
property WorkCountry: String read FWorkCountry write FWorkCountry;
|
|
|
|
property WorkEMail: String read FWorkEMail write FWorkEMail;
|
|
|
|
property WorkPhone: String read FWorkPhone write FWorkPhone;
|
|
|
|
property WorkFax: String read FWorkFax write FWorkFax;
|
|
|
|
|
|
|
|
property HomeAddress: String read FHomeAddress write FHomeAddress;
|
|
|
|
property HomeCity: String read FHomeCity write FHomeCity;
|
|
|
|
property HomeZip: String read FHomeZip write FHomeZip;
|
|
|
|
property HomeState: String read FHomeState write FHomeState;
|
|
|
|
property HomeCountry: String read FHomeCountry write FHomeCountry;
|
|
|
|
property HomeEMail: String read FHomeEMail write FHomeEMail;
|
|
|
|
property HomePhone: String read FHomePhone write FHomePhone;
|
|
|
|
property HomeFax: String read FHomeFax write FHomeFax;
|
|
|
|
|
|
|
|
property CarPhone: String read FCarPhone write FCarPhone;
|
|
|
|
property Mobile: String read FMobile write FMobile;
|
|
|
|
property ISDN: String read FISDN write FISDN;
|
|
|
|
property Pager: String read FPager write FPager;
|
|
|
|
|
|
|
|
property Anniversary: TDateTime read FAnniversary write FAnniversary;
|
2022-08-19 10:53:49 +00:00
|
|
|
property BirthDay: TDateTime read FBirthday write FBirthDay;
|
|
|
|
property Category[AIndex: Integer]: string read GetCategory;
|
|
|
|
property CategoryCount: Integer read GetCategoryCount;
|
|
|
|
property Categories: TStrings read FCategories write FCategories;
|
|
|
|
property PickedCategory: Integer read FPickedCategory write FPickedCategory;
|
2018-06-08 20:03:23 +00:00
|
|
|
|
|
|
|
property Version: String read FVersion;
|
2022-08-19 14:06:54 +00:00
|
|
|
property Checked: Boolean read FChecked write FChecked default true; // Flag to skip import
|
2018-06-08 20:03:23 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
TVpVCards = class
|
|
|
|
private
|
|
|
|
FCards: array of TVpVCard;
|
|
|
|
function GetCard(AIndex: Integer): TVpVCard;
|
|
|
|
function GetCount: Integer;
|
|
|
|
protected
|
|
|
|
procedure LoadFromStrings(const AStrings: TStrings);
|
2022-08-18 17:44:47 +00:00
|
|
|
procedure SaveToStrings(AList: TStrings);
|
|
|
|
|
2018-06-08 20:03:23 +00:00
|
|
|
public
|
|
|
|
constructor Create;
|
|
|
|
destructor Destroy; override;
|
2022-08-18 17:44:47 +00:00
|
|
|
procedure Add(ACard: TVpVCard);
|
2018-06-08 20:03:23 +00:00
|
|
|
procedure ClearCards;
|
|
|
|
procedure LoadFromFile(const AFileName: String);
|
|
|
|
procedure LoadFromStream(const AStream: TStream);
|
2022-08-18 17:44:47 +00:00
|
|
|
procedure SaveToFile(const AFileName: String);
|
|
|
|
procedure SaveToStream(const AStream: TStream);
|
2018-06-08 20:03:23 +00:00
|
|
|
property Count: Integer read GetCount;
|
|
|
|
property Card[AIndex: Integer]: TVpVCard read GetCard; default;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure VCardAddress(AText: String;
|
|
|
|
out Address, ACity, AZip, AState, ACountry: String);
|
|
|
|
|
|
|
|
function VCardDate(AText: String): TDate;
|
|
|
|
|
|
|
|
procedure VCardName(AText: String; out ALastName, AFirstName, ATitle: String);
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
uses
|
|
|
|
StrUtils, DateUtils,
|
2019-01-15 22:14:01 +00:00
|
|
|
VpMisc;
|
2018-06-08 20:03:23 +00:00
|
|
|
|
|
|
|
const
|
|
|
|
ITEMS_DELIMITER = ';';
|
|
|
|
|
|
|
|
{ Example:
|
|
|
|
ADR;TYPE=home:;;Heidestrasse 17;Koeln;;51147;Germany }
|
|
|
|
procedure VCardAddress(AText: String;
|
|
|
|
out Address, ACity, AZip, AState, ACountry: String);
|
|
|
|
var
|
|
|
|
strArr: TStringArray;
|
|
|
|
begin
|
|
|
|
Address := '';
|
|
|
|
ACity := '';
|
|
|
|
AState := '';
|
|
|
|
ACountry := '';
|
|
|
|
strArr := Split(AText, ITEMS_DELIMITER);
|
|
|
|
{ strArr[0] - post office box ---> not used
|
|
|
|
strArr[1] - extended address (e.g., apartment or suite number) ---> not used
|
|
|
|
strArr[2] - street address
|
|
|
|
strArr[3] - locality (e.g., city)
|
|
|
|
strArr[4] - region (e.g., state or province)
|
|
|
|
strArr[5] - postal code
|
|
|
|
strArr[6] - country name }
|
|
|
|
if Length(strArr) > 2 then Address := strArr[2];
|
|
|
|
if Length(strArr) > 3 then ACity := strArr[3];
|
|
|
|
if Length(strArr) > 4 then AState := strArr[4];
|
|
|
|
if Length(strArr) > 5 then AZip := strArr[5];
|
|
|
|
if Length(strArr) > 6 then ACountry := strArr[6];
|
|
|
|
end;
|
|
|
|
|
|
|
|
function VCardDate(AText: String): TDate;
|
|
|
|
var
|
|
|
|
fs: TFormatSettings;
|
|
|
|
y, m, d: Integer;
|
|
|
|
begin
|
|
|
|
if AText <> '' then begin
|
|
|
|
if TryStrToInt(copy(AText, 1, 4), y) and
|
|
|
|
TryStrToInt(copy(AText, 5, 2), m) and
|
|
|
|
TryStrToInt(copy(AText, 7, 2), d) then
|
|
|
|
begin
|
|
|
|
if TryEncodeDate(y, m, d, Result) then
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
fs.ShortDateFormat := 'yyyy-mm-dd';
|
|
|
|
fs.LongDateFormat := fs.ShortDateFormat;
|
|
|
|
if TryStrToDate(AText, Result, fs) then
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
Result := -1;
|
|
|
|
end;
|
|
|
|
|
|
|
|
{ Example:
|
|
|
|
N:Mustermann;Erika;;Dr.; }
|
|
|
|
procedure VCardName(AText: String; out ALastName, AFirstName, ATitle: String);
|
|
|
|
var
|
|
|
|
strArr: TStringArray;
|
|
|
|
begin
|
|
|
|
ALastName := '';
|
|
|
|
AFirstName := '';
|
|
|
|
ATitle := '';
|
|
|
|
strArr := Split(AText, ITEMS_DELIMITER);
|
|
|
|
if Length(strArr) > 0 then ALastName := strArr[0];
|
|
|
|
if Length(strArr) > 1 then AFirstName := strArr[1];
|
|
|
|
if Length(strArr) > 3 then ATitle := strArr[3];
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
{==============================================================================}
|
|
|
|
{ TVpVCard }
|
|
|
|
{==============================================================================}
|
|
|
|
|
|
|
|
constructor TVpVCard.Create;
|
|
|
|
begin
|
2018-06-14 15:15:18 +00:00
|
|
|
inherited Create(TVpVCardItem);
|
2022-08-19 14:06:54 +00:00
|
|
|
FChecked := true;
|
2022-08-19 10:53:49 +00:00
|
|
|
FCategories := TStringList.Create;
|
|
|
|
FCategories.Delimiter := ','; // VCard categories are separated by comma in vcf file.
|
|
|
|
FCategories.StrictDelimiter := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TVpVCard.Destroy;
|
|
|
|
begin
|
|
|
|
FCategories.Free;
|
|
|
|
inherited;
|
2018-06-08 20:03:23 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TVpVCard.Analyze;
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
item: TVpVCardItem;
|
2019-01-10 10:10:16 +00:00
|
|
|
fn, ln, t: String;
|
2022-08-11 20:32:13 +00:00
|
|
|
fullName: String;
|
2022-08-18 17:44:47 +00:00
|
|
|
fs: TFormatSettings;
|
|
|
|
dt: TDateTime;
|
2018-06-08 20:03:23 +00:00
|
|
|
begin
|
2018-06-14 15:15:18 +00:00
|
|
|
inherited;
|
|
|
|
|
2018-06-08 20:03:23 +00:00
|
|
|
for i := 0 to FItems.Count-1 do begin
|
|
|
|
item := TVpVCardItem(FItems[i]);
|
|
|
|
case item.Key of
|
2018-06-14 15:15:18 +00:00
|
|
|
'VERSION':
|
|
|
|
FVersion := item.Value;
|
2022-08-11 20:32:13 +00:00
|
|
|
'FN':
|
|
|
|
fullName := item.Value;
|
|
|
|
'N':
|
2019-01-10 10:10:16 +00:00
|
|
|
begin
|
|
|
|
VCardName(item.Value, ln, fn, t);
|
|
|
|
if FLastName = '' then FLastName := ln;
|
|
|
|
if FFirstName = '' then FFirstName := fn;
|
|
|
|
if FTitle = '' then FTitle := t;
|
|
|
|
end;
|
2018-06-08 20:03:23 +00:00
|
|
|
'ORG':
|
2022-08-18 17:44:47 +00:00
|
|
|
begin
|
|
|
|
FCompany := item.Value;
|
|
|
|
if (FCompany <> '') and (FCompany[Length(FCompany)] = ';') then
|
|
|
|
Delete(FCompany, Length(FCompany), 1);
|
|
|
|
end;
|
2018-06-08 20:03:23 +00:00
|
|
|
'ADR':
|
2018-06-15 23:40:18 +00:00
|
|
|
if item.Attributes.IndexOf('WORK') <> -1 then
|
2018-06-08 20:03:23 +00:00
|
|
|
VCardAddress(item.Value, FWorkAddress, FWorkCity, FWorkZip, FWorkState, FWorkCountry)
|
2018-06-15 23:40:18 +00:00
|
|
|
else if item.Attributes.IndexOf('HOME') <> -1 then
|
2018-06-08 20:03:23 +00:00
|
|
|
VCardAddress(item.value, FHomeAddress, FHomeCity, FHomeZip, FHomeState, FHomeCountry)
|
|
|
|
else
|
|
|
|
if FCompany = '' then
|
|
|
|
VCardAddress(item.Value, FHomeAddress, FHomeCity, FHomeZip, FHomeState, FHomeCountry)
|
|
|
|
else
|
|
|
|
VCardAddress(item.Value, FWorkAddress, FWorkCity, FWorkZip, FWorkState, FWorkCountry);
|
|
|
|
'EMAIL':
|
2022-08-18 17:44:47 +00:00
|
|
|
if (item.Attributes.IndexOf('WORK') <> -1) then
|
|
|
|
FWorkEMail := IfThen(FWorkEMail = '', item.Value, FWorkEMail + ITEM_SEPARATOR + ' ' + item.Value)
|
|
|
|
else
|
2018-06-15 23:40:18 +00:00
|
|
|
if (FCompany = '') or (item.Attributes.IndexOf('HOME') <> -1) then
|
2022-08-18 17:44:47 +00:00
|
|
|
FHomeEMail := IfThen(FHomeEMail = '', item.Value, FHomeEMail + ITEM_SEPARATOR + ' ' + item.Value)
|
2018-06-08 20:03:23 +00:00
|
|
|
else
|
2022-08-18 17:44:47 +00:00
|
|
|
FWorkEMail := IfThen(FWorkEMail = '', item.Value, FWorkEMail + ITEM_SEPARATOR + ' ' + item.Value);
|
2018-06-08 20:03:23 +00:00
|
|
|
'TEL':
|
2018-06-15 23:40:18 +00:00
|
|
|
if item.Attributes.IndexOf('CELL') <> -1 then
|
2018-06-08 20:03:23 +00:00
|
|
|
FMobile := item.Value
|
|
|
|
else
|
2018-06-15 23:40:18 +00:00
|
|
|
if item.Attributes.IndexOf('PAGER') <> -1 then
|
2018-06-08 20:03:23 +00:00
|
|
|
FPager := item.Value
|
|
|
|
else
|
2018-06-15 23:40:18 +00:00
|
|
|
if item.Attributes.IndexOf('FAX') <> -1 then begin
|
|
|
|
if (FCompany = '') or (item.Attributes.IndexOf('HOME') <> -1) then
|
2018-06-08 20:03:23 +00:00
|
|
|
FHomeFax := item.Value
|
|
|
|
else
|
|
|
|
FWorkFax := item.Value;
|
|
|
|
end else
|
2018-06-15 23:40:18 +00:00
|
|
|
if item.Attributes.IndexOf('CAR') <> -1 then
|
2018-06-08 20:03:23 +00:00
|
|
|
FCarPhone := item.Value
|
|
|
|
else
|
2018-06-15 23:40:18 +00:00
|
|
|
if item.Attributes.IndexOf('ISDN') <> -1 then
|
2018-06-08 20:03:23 +00:00
|
|
|
FISDN := item.Value
|
|
|
|
else
|
2022-08-18 17:44:47 +00:00
|
|
|
if item.Attributes.IndexOf('WORK') <> -1 then
|
|
|
|
FWorkPhone := IfThen(FWorkPhone = '', item.Value, FWorkPhone + ITEM_SEPARATOR + ' ' + item.Value)
|
|
|
|
else
|
|
|
|
if (item.Attributes.IndexOf('HOME') <> -1) then
|
|
|
|
FHomePhone := IfThen(FHomePhone = '', item.Value, FHomePhone + ITEM_SEPARATOR + ' ' +item.Value)
|
2018-06-08 20:03:23 +00:00
|
|
|
else
|
2022-08-18 17:44:47 +00:00
|
|
|
FWorkPhone := IfThen(FWorkPhone = '', item.Value, FWorkPhone + ITEM_SEPARATOR + ' ' + item.Value);
|
|
|
|
'BDAY', 'ANNIVERSARY':
|
|
|
|
begin
|
|
|
|
fs := FormatSettings;
|
|
|
|
fs.DateSeparator := '-';
|
|
|
|
fs.ShortDateFormat := 'yyyy/mm/dd';
|
2022-08-22 20:56:10 +00:00
|
|
|
if TryStrToDate(item.Value, dt, fs) then
|
2022-08-18 17:44:47 +00:00
|
|
|
begin
|
|
|
|
if (item.Key = 'BDAY') then
|
|
|
|
FBirthday := dt
|
|
|
|
else if (item.Key = 'ANNIVERSARY') then
|
|
|
|
FAnniversary := dt;
|
|
|
|
end;
|
|
|
|
end;
|
2022-08-19 10:53:49 +00:00
|
|
|
'CATEGORIES':
|
|
|
|
FCategories.CommaText := item.Value;
|
2018-06-08 20:03:23 +00:00
|
|
|
end;
|
|
|
|
end;
|
2022-08-11 20:32:13 +00:00
|
|
|
|
|
|
|
if (FFirstName = '') and (FLastName = '') then
|
|
|
|
begin
|
|
|
|
FLastName := fullName;
|
|
|
|
FFirstName := '';
|
|
|
|
FTitle := '';
|
|
|
|
end;
|
2018-06-08 20:03:23 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCard.FindItem(AKey, ATags: String): TVpVCardItem;
|
|
|
|
begin
|
2018-06-14 15:15:18 +00:00
|
|
|
Result := TVpVCardItem(inherited FindItem(AKey, ATags));
|
2018-06-08 20:03:23 +00:00
|
|
|
end;
|
|
|
|
|
2022-08-19 10:53:49 +00:00
|
|
|
function TVpVCard.GetCategory(AIndex: Integer): String;
|
|
|
|
begin
|
|
|
|
Result := FCategories[AIndex];
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCard.GetCategoryCount: Integer;
|
|
|
|
begin
|
|
|
|
Result := FCategories.Count;
|
|
|
|
end;
|
|
|
|
|
2022-08-11 20:32:13 +00:00
|
|
|
function TVpVCard.GetEMail: String;
|
|
|
|
begin
|
2022-08-18 17:44:47 +00:00
|
|
|
Result := '';
|
|
|
|
if WorkEMail <> '' then Result := Format('%s; %s (work)', [Result, WorkEMail]);
|
|
|
|
if HomeEMail <> '' then Result := Format('%s; %s (home)', [Result, HomeEMail]);
|
|
|
|
if Result <> '' then
|
|
|
|
Delete(Result, 1, 2);
|
2022-08-11 20:32:13 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCard.GetFullName: String;
|
|
|
|
begin
|
|
|
|
Result := LastName;
|
|
|
|
if FirstName <> '' then Result := FirstName + ' ' + Result;
|
|
|
|
if Title <> '' then Result := Result + ', ' + Title;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCard.GetHomeAddress: String;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
if (HomeAddress = '') and (HomeZip = '') and (HomeCity = '') then
|
|
|
|
exit;
|
|
|
|
Result := HomeAddress + ', ' + HomeZip + ' ' + HomeCity;
|
|
|
|
if HomeState <> '' then
|
|
|
|
Result := Result + ', ' + HomeState;
|
|
|
|
if HomeCountry <> '' then
|
|
|
|
Result := Result + ', ' + HomeCountry;
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCard.GetPhone: String;
|
|
|
|
begin
|
2022-08-18 17:44:47 +00:00
|
|
|
Result := '';
|
|
|
|
if WorkPhone <> '' then Result := Format('%s; %s (work)', [Result, WorkPhone]);
|
|
|
|
if HomePhone <> '' then Result := Format('%s; %s (home)', [Result, HomePhone]);
|
|
|
|
if Mobile <> '' then Result := Format('%s; %s (mobile)', [Result, Mobile]);
|
|
|
|
if Result <> '' then Delete(Result, 1, 2);
|
2022-08-11 20:32:13 +00:00
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCard.GetWorkAddress: String;
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
if (Company = '') and (WorkAddress = '') and (WorkZip = '') and (WorkCity = '') then
|
|
|
|
exit;
|
|
|
|
|
|
|
|
Result := Company + ', ' + WorkAddress + ', ' + WorkZip + ' ' + WorkCity;
|
|
|
|
if WorkState <> '' then
|
|
|
|
Result := Result + ', ' + WorkState;
|
|
|
|
if WorkCountry <> '' then
|
|
|
|
Result := Result + ', ' + WorkCountry;
|
|
|
|
end;
|
2022-08-18 17:44:47 +00:00
|
|
|
|
|
|
|
procedure TVpVCard.SaveToStrings(AList: TStrings);
|
|
|
|
begin
|
|
|
|
AList.Add('BEGIN:VCARD');
|
|
|
|
AList.Add('VERSION:3.0');
|
|
|
|
|
|
|
|
// Name
|
|
|
|
AList.Add('FN:' + GetFullName);
|
|
|
|
AList.Add('N:' + LastName + ';' + FirstName + ';;;');
|
|
|
|
|
|
|
|
// Addresses
|
|
|
|
if (WorkAddress <> '') or (WorkCity <> '') or (WorkZip <> '') or
|
|
|
|
(WorkState <> '') or (WorkCountry <> '')
|
|
|
|
then
|
|
|
|
AList.Add('ADR;TYPE=WORK:' + WorkAddress + ';' + WorkCity + ';' +
|
|
|
|
WorkState +';' + WorkZip + ';' + WorkCountry);
|
|
|
|
if (HomeAddress <> '') or (HomeCity <> '') or (HomeZip <> '') or
|
|
|
|
(HomeState <> '') or (HomeCountry <> '')
|
|
|
|
then
|
|
|
|
AList.Add('ADR;TYPE=HOME:' + HomeAddress + ';' + HomeCity + ';' +
|
|
|
|
HomeState +';' + HomeZip + ';' + HomeCountry);
|
|
|
|
|
|
|
|
// Company
|
|
|
|
if Company <> '' then
|
|
|
|
AList.Add('ORG:' + Company);
|
|
|
|
|
|
|
|
// Phone numbers
|
|
|
|
if WorkPhone <> '' then
|
|
|
|
AList.Add('TEL;TYPE=WORK:' + WorkPhone);
|
|
|
|
if HomePhone <> '' then
|
|
|
|
AList.Add('TEL;TYPE=HOME:' + HomePhone);
|
|
|
|
if Mobile <> '' then
|
|
|
|
AList.Add('TEL;TYPE=CELL:' + Mobile);
|
|
|
|
if CarPhone <> '' then
|
|
|
|
AList.Add('TEL;TYPE=CAR:' + CarPhone);
|
|
|
|
if ISDN <> '' then
|
|
|
|
AList.Add('TEL;TYPE=ISDN:' + ISDN);
|
|
|
|
if Pager <> '' then
|
|
|
|
AList.Add('TEL;TYPE=PAGER:' + Pager);
|
|
|
|
|
|
|
|
// Fax
|
|
|
|
if WorkFax <> '' then
|
|
|
|
AList.Add('TEL;TYPE="fax,work":' + WorkFax);
|
|
|
|
if HomeFax <> '' then
|
|
|
|
AList.Add('TEL;TYPE="fax,home":' + HomeFax);
|
|
|
|
|
|
|
|
// E-Mail
|
|
|
|
if WorkEMail <> '' then
|
|
|
|
AList.Add('EMAIL;TYPE=WORK:' + WorkEMail);
|
|
|
|
if HomeEMail <> '' then
|
|
|
|
AList.Add('EMAIL;TYPE=HOME:' + HomeEMail);
|
|
|
|
|
2022-08-19 10:53:49 +00:00
|
|
|
// Categories
|
|
|
|
if Categories.Count > 0 then
|
|
|
|
AList.Add('CATEGORIES:' + Categories.CommaText);
|
|
|
|
|
2022-08-18 17:44:47 +00:00
|
|
|
AList.Add('END:VCARD');
|
|
|
|
end;
|
|
|
|
|
2018-06-08 20:03:23 +00:00
|
|
|
|
|
|
|
{==============================================================================}
|
|
|
|
{ TVpCards }
|
|
|
|
{==============================================================================}
|
|
|
|
|
|
|
|
constructor TVpVCards.Create;
|
|
|
|
begin
|
|
|
|
inherited;
|
|
|
|
SetLength(FCards, 0);
|
|
|
|
end;
|
|
|
|
|
|
|
|
destructor TVpVCards.Destroy;
|
|
|
|
begin
|
|
|
|
ClearCards;
|
|
|
|
inherited;
|
|
|
|
end;
|
|
|
|
|
2022-08-18 17:44:47 +00:00
|
|
|
procedure TVpVCards.Add(ACard: TVpVCard);
|
|
|
|
var
|
|
|
|
n: Integer;
|
|
|
|
begin
|
|
|
|
n := Length(FCards);
|
|
|
|
SetLength(FCards, n+1);
|
|
|
|
FCards[n] := ACard;
|
|
|
|
end;
|
|
|
|
|
2018-06-08 20:03:23 +00:00
|
|
|
procedure TVpVCards.ClearCards;
|
|
|
|
var
|
|
|
|
j: Integer;
|
|
|
|
begin
|
|
|
|
for j := Count-1 downto 0 do
|
|
|
|
FCards[j].Free;
|
|
|
|
SetLength(FCards, 0);
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCards.GetCard(AIndex: Integer): TVpVCard;
|
|
|
|
begin
|
|
|
|
Result := FCards[AIndex];
|
|
|
|
end;
|
|
|
|
|
|
|
|
function TVpVCards.GetCount: Integer;
|
|
|
|
begin
|
|
|
|
Result := Length(FCards);
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TVpVCards.LoadFromFile(const AFilename: String);
|
|
|
|
var
|
|
|
|
L: TStrings;
|
|
|
|
begin
|
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
L.LoadFromFile(AFileName);
|
|
|
|
LoadFromStrings(L);
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TVpVCards.LoadFromStream(const AStream: TStream);
|
|
|
|
var
|
|
|
|
L: TStrings;
|
|
|
|
begin
|
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
L.LoadFromStream(AStream);
|
|
|
|
LoadFromStrings(L);
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TVpVCards.LoadFromStrings(const AStrings: TStrings);
|
|
|
|
const
|
|
|
|
BLOCK_SIZE = 100;
|
|
|
|
var
|
|
|
|
p: Integer;
|
|
|
|
itemName: String;
|
|
|
|
itemValue: String;
|
|
|
|
i, n: Integer;
|
|
|
|
s: String;
|
|
|
|
begin
|
|
|
|
// Clear item list
|
|
|
|
ClearCards;
|
|
|
|
n := 0;
|
|
|
|
SetLength(FCards, BLOCK_SIZE);
|
|
|
|
|
|
|
|
for i:=0 to AStrings.Count-1 do begin
|
|
|
|
s := AStrings[i];
|
|
|
|
if s = '' then
|
|
|
|
continue;
|
|
|
|
p := pos(':', s);
|
|
|
|
if p = 0 then
|
|
|
|
continue;
|
|
|
|
itemName := Uppercase(copy(s, 1, p-1));
|
|
|
|
itemValue := Uppercase(copy(s, p+1, MaxInt));
|
|
|
|
if (itemName = 'BEGIN') and (itemValue = 'VCARD') then begin
|
|
|
|
FCards[n] := TVpVCard.Create;
|
|
|
|
inc(n);
|
|
|
|
if n mod BLOCK_SIZE = 0 then
|
|
|
|
SetLength(FCards, Length(FCards) + BLOCK_SIZE);
|
|
|
|
end else
|
|
|
|
if (itemName = 'END') and (itemValue = 'VCARD') then
|
|
|
|
FCards[n-1].Analyze
|
|
|
|
else
|
|
|
|
FCards[n-1].Add(s);
|
|
|
|
end;
|
|
|
|
SetLength(FCards, n);
|
|
|
|
end;
|
|
|
|
|
2022-08-18 17:44:47 +00:00
|
|
|
procedure TVpVCards.SaveToFile(const AFileName: String);
|
|
|
|
var
|
|
|
|
L: TStrings;
|
|
|
|
begin
|
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
SaveToStrings(L);
|
|
|
|
L.SaveToFile(AFileName);
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TVpVCards.SaveToStream(const AStream: TStream);
|
|
|
|
var
|
|
|
|
L: TStrings;
|
|
|
|
begin
|
|
|
|
L := TStringList.Create;
|
|
|
|
try
|
|
|
|
SaveToStrings(L);
|
|
|
|
L.SaveToStream(AStream);
|
|
|
|
finally
|
|
|
|
L.Free;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
procedure TVpVCards.SaveToStrings(AList: TStrings);
|
|
|
|
var
|
|
|
|
i: Integer;
|
|
|
|
begin
|
2022-08-20 17:06:03 +00:00
|
|
|
AList.Clear;
|
2022-08-18 17:44:47 +00:00
|
|
|
for i := 0 to Count-1 do
|
|
|
|
FCards[i].SaveToStrings(AList);
|
|
|
|
end;
|
|
|
|
|
2018-06-08 20:03:23 +00:00
|
|
|
end.
|
|
|
|
|