Join MultiplyOpen a Free ShopSign InHelp
MultiplyLogo
SEARCH
Blog EntryJul 10, '07 10:47 AM
for everyone
Kantorku lagi migrasi dari MS Exchange Server ke Zimbra, sebuah collaboration and messaging software dari Zimbra, Inc. Nah kebetulan email clientku menggunakan Mozilla Portable Thunderbird. Pas mau export address book thunderbird yang sudah aku export dalam bentuk CSV (Comma Separated Value), ternyata tidak compatible. Akhirnya aku coba buat sebuah address di ThunderBird dan Zimbra, masing-masing aku isi dengan keterangan nama fieldnya, barulah ketahuan mappingnya.

Dasar aku orangnya pemalas, aku nggak mau masukin satu-satu email dari ThunderBird ke Zimbra (cappppeeeeeeeee deeeech). Mau nggak mau ya click icon Borland Delphi 2006 dan membuat tool sederhana untuk convert.

Berikut ini source codenya. Barangkali ada yang mau menambahkan konversi dari Outlook CSV ke Zimbra atau dari mail client lainnya, silakan.

unit MainForm;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ComCtrls;
 
type
  TformName = class(TForm)
    lblThunderbird: TLabel;
    edThunderbird: TEdit;
    sbOpenCSV: TSpeedButton;
    progressBar: TProgressBar;
    bbConvert: TBitBtn;
    SaveDialog: TSaveDialog;
    OpenDialog: TOpenDialog;
    procedure bbConvertClick(Sender: TObject);
    procedure sbOpenCSVClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Convert(thunderBirdFileName, zimbraFileName: String);
  end;
 
const
  {Thunderbird's Constants}
  TB_FIRST_NAME = 0;
  TB_LAST_NAME = 1;
  TB_DISPLAY_NAME = 2;
  TB_NICK_NAME = 3;
  TB_EMAIL = 4;
  TB_ADDITIONAL_EMAIL = 5;
  TB_WORK_PHONE = 6;
  TB_HOME_PHONE = 7;
  TB_FAX_NUMBER = 8;
  TB_PAGER = 9;
  TB_MOBILE_PHONE = 10;
  TB_HOME_ADDRESS_LINE_1 = 11;
  TB_HOME_ADDRESS_LINE_2 = 12;
  TB_HOME_CITY = 13;
  TB_HOME_STATE = 14;
  TB_HOME_ZIP = 15;
  TB_HOME_COUNTRY = 16;
  TB_WORK_ADDRESS_LINE_1 = 17;
  TB_WORK_ADDRESS_LINE_2 = 18;
  TB_WORK_CITY = 19;
  TB_WORK_STATE = 20;
  TB_WORK_ZIP = 21;
  TB_WORK_COUNTRY = 22;
  TB_WORK_TITLE = 23;
  TB_WORK_DEPARTMENT = 24;
  TB_WORK_ORGANIZATION = 25;
  TB_WORK_WEBSITE = 26;
  TB_HOME_WEBSITE = 27;
  TB_UNKNOWN_1 = 28;
  TB_UNKNOWN_2 = 29;
  TB_UNKNOWN_3 = 30;
  TB_CUSTOM_1 = 31;
  TB_CUSTOM_2 = 32;
  TB_CUSTOM_3 = 33;
  TB_CUSTOM_4 = 34;
  TB_NOTES = 35;
 
 
  {Zimbra's Constants}
  ZB_ASSISTANT_PHONE = 0;
  ZB_BIRTHDAY = 1;
  ZB_CALLBACK_PHONE = 2;
  ZB_CAR_PHONE = 3;
  ZB_WORK_ORGANIZATION = 4;
  ZB_COMPANY_PHONE = 5;
  ZB_DESCRIPTION = 6;
  ZB_WORK_DEPARTMENT = 7;
  ZB_DLIST = 8;
  ZB_EMAIL = 9;
  ZB_EMAIL2 = 10;
  ZB_EMAIL3 = 11;
  ZB_FILE_AS = 12;
  ZB_FIRST_NAME = 13;
  ZB_FULL_NAME = 14;
  ZB_HOME_CITY = 15;
  ZB_HOME_COUNTRY = 16;
  ZB_HOME_FAX = 17;
  ZB_HOME_PHONE = 18;
  ZB_HOME_PHONE2 = 19;
  ZB_HOME_ZIP = 20;
  ZB_HOME_STATE = 21;
  ZB_HOME_STREET = 22;
  ZB_HOME_WEBSITE = 23;
  ZB_INITIALS = 24;
  ZB_WORK_TITLE = 25;
  ZB_LAST_NAME = 26;
  ZB_MIDDLE_NAME = 27;
  ZB_MOBILE_PHONE = 28;
  ZB_NAME_PREFIX = 29;
  ZB_NAME_SUFFIX = 30;
  ZB_NICK_NAME = 31;
  ZB_NOTES = 32;
  ZB_OFFICE = 33;
  ZB_OTHER_CITY = 34;
  ZB_OTHER_COUNTRY = 35;
  ZB_OTHER_FAX = 36;
  ZB_OTHER_PHONE = 37;
  ZB_OTHER_ZIP_CODE = 38;
  ZB_OTHER_STATE = 39;
  ZB_OTHER_STREET = 40;
  ZB_OTHER_WEBSITE = 41;
  ZB_PAGER = 42;
  ZB_WORK_CITY = 43;
  ZB_WORK_COUNTRY = 44;
  ZB_WORK_FAX = 45;
  ZB_WORK_PHONE = 46;
  ZB_WORK_PHONE2 = 47;
  ZB_WORK_ZIP = 48;
  ZB_WORK_STATE = 49;
  ZB_WORK_STREET = 50;
  ZB_WORK_WEBSITE = 51;
  ZB_TYPE = 52;
 
var
  formName: TformName;
 
implementation
 
uses classStringSplitter, StrUtils;
 
{$R *.dfm}
 
procedure TformName.bbConvertClick(Sender: TObject);
begin
  if FileExists(edThunderbird.Text) then
  begin
    if SaveDialog.Execute then
    begin
      Convert(edThunderbird.Text, SaveDialog.FileName);
    end;
  end
  else
    MessageDlg('The file you requested is not found or cannot be read. ' +
    'Please try another file.', mtError, [mbOK], 0);
end;
 
procedure TformName.Convert(thunderBirdFileName, zimbraFileName: String);
var
  list, fields, outputList: TStringList;
  i, j: integer;
  destination: array[ZB_ASSISTANT_PHONE..ZB_TYPE] of String;
  row: String;
begin
  list := TStringList.Create;
 
  list.LoadFromFile(thunderBirdFileName);
  progressBar.Position := 0;
  progressBar.Max := list.Count;
 
  fields := TStringList.Create;
  outputList := TStringList.Create;
 
  outputList.Add('"assistantPhone","birthday","callbackPhone","carPhone",' +
  '"company","companyPhone","description","department","dlist","email",'+
  '"email2","email3","fileAs","firstName","fullName","homeCity",'+
  '"homeCountry","homeFax","homePhone","homePhone2","homePostalCode",'+
  '"homeState","homeStreet","homeURL","initials","jobTitle","lastName",'+
  '"middleName","mobilePhone","namePrefix","nameSuffix","nickname","notes",'+
  '"office","otherCity","otherCountry","otherFax","otherPhone",'+
  '"otherPostalCode","otherState","otherStreet","otherURL","pager",'+
  '"workCity","workCountry","workFax","workPhone","workPhone2",'+
  '"workPostalCode","workState","workStreet","workURL","type"');
 
  i := 0;
  while i < list.Count do
  begin
    row := '';
    TStringSplitter.split(list[i], ',', fields);
 
    destination[ZB_ASSISTANT_PHONE] := '';
    destination[ZB_BIRTHDAY] := '';
    destination[ZB_CALLBACK_PHONE] := '';
    destination[ZB_CAR_PHONE] := '';
    destination[ZB_WORK_ORGANIZATION] := fields[TB_WORK_ORGANIZATION];
    destination[ZB_COMPANY_PHONE] := '';
    destination[ZB_DESCRIPTION] := '';
    destination[ZB_WORK_DEPARTMENT] := fields[TB_WORK_DEPARTMENT];
    destination[ZB_DLIST] := '';
    destination[ZB_EMAIL] := fields[TB_EMAIL];
    destination[ZB_EMAIL2] := fields[TB_ADDITIONAL_EMAIL];
    destination[ZB_EMAIL3] := '';
    destination[ZB_FILE_AS] :=  '';
    destination[ZB_FIRST_NAME] := fields[TB_FIRST_NAME];
    destination[ZB_FULL_NAME] := fields[TB_FIRST_NAME] + ' ' + fields[TB_LAST_NAME];
    destination[ZB_HOME_CITY] := fields[TB_HOME_CITY];
    destination[ZB_HOME_COUNTRY] := fields[TB_HOME_COUNTRY];
    destination[ZB_HOME_FAX] := '';
    destination[ZB_HOME_PHONE] := fields[TB_HOME_PHONE];
    destination[ZB_HOME_PHONE2] := '';
    destination[ZB_HOME_ZIP] := fields[TB_HOME_ZIP];
    destination[ZB_HOME_STATE] := fields[TB_HOME_STATE];
    destination[ZB_HOME_STREET] := fields[TB_HOME_ADDRESS_LINE_1] + ' ' +
    fields[TB_HOME_ADDRESS_LINE_2];
    destination[ZB_HOME_WEBSITE] := fields[TB_HOME_WEBSITE];
    destination[ZB_INITIALS] := '';
    destination[ZB_WORK_TITLE] := fields[TB_WORK_TITLE];
    destination[ZB_LAST_NAME] := fields[TB_LAST_NAME];
    destination[ZB_MIDDLE_NAME] := '';
    destination[ZB_MOBILE_PHONE] := fields[TB_MOBILE_PHONE];
    destination[ZB_NAME_PREFIX] := '';
    destination[ZB_NAME_SUFFIX] := '';
    destination[ZB_NICK_NAME] := fields[TB_NICK_NAME];
    destination[ZB_NOTES] := fields[TB_NOTES];
    destination[ZB_OFFICE] := fields[TB_WORK_ORGANIZATION];
    destination[ZB_OTHER_CITY] := '';
    destination[ZB_OTHER_COUNTRY] := '';
    destination[ZB_OTHER_FAX] := '';
    destination[ZB_OTHER_PHONE] := '';
    destination[ZB_OTHER_ZIP_CODE] := '';
    destination[ZB_OTHER_STATE] := '';
    destination[ZB_OTHER_STREET] := '';
    destination[ZB_OTHER_WEBSITE] := '';
    destination[ZB_PAGER] := fields[TB_PAGER];
    destination[ZB_WORK_CITY] := fields[TB_WORK_CITY];
    destination[ZB_WORK_COUNTRY] := fields[TB_WORK_COUNTRY];
    destination[ZB_WORK_FAX] := fields[TB_FAX_NUMBER];
    destination[ZB_WORK_PHONE] := fields[TB_WORK_PHONE];
    destination[ZB_WORK_PHONE2] := '';
    destination[ZB_WORK_ZIP] := fields[TB_WORK_ZIP];
    destination[ZB_WORK_STATE] := fields[TB_WORK_STATE];
    destination[ZB_WORK_STREET] := fields[TB_WORK_ADDRESS_LINE_1] + ' ' +
    fields[TB_WORK_ADDRESS_LINE_1];
    destination[ZB_WORK_WEBSITE] := fields[TB_WORK_WEBSITE];
    destination[ZB_TYPE] := '';
 
    for j := ZB_ASSISTANT_PHONE to ZB_TYPE do
    begin
      row := row + '"' + destination[j] + '"';
      if j <> ZB_TYPE then
        row := row + ',';
    end;
      
    outputList.Add(row);
 
    progressBar.StepBy(1);
    Inc(i);
  end;
 
  outputList.SaveToFile(zimbraFileName);
 
  outputList.Free;
  fields.Free;
  list.Free;
end;
 
procedure TformName.sbOpenCSVClick(Sender: TObject);
begin
  if OpenDialog.Execute then
  begin
    edThunderbird.Text := OpenDialog.FileName;
  end;
end;
 
end.
 
Kalau mau download aplikasi dan source codenya silakan klik di attachment.
Kalau mau mengoreksi, mau menambahkan, please comment yaa..
Attachment: Thunderbird to Zimbra Converter.rar

16 CommentsChronological   Reverse   Threaded
farahinwonderland wrote on Jul 10, '07
Dasar aku orangnya pemalas
ini sih bukan pemalas, tapi pengrajin, pengrajin emas kali :)
setyo88 wrote on Jul 11, '07
Terima Kasih pak atas ilmunya
wishknew wrote on Jul 11, '07
tapi pengrajin,
pengrajin <> penguasa kerajaan jin kan? hehehe.. udah nonton harry potter belum?
wishknew wrote on Jul 11, '07
setyo88 said
Terima Kasih pak atas ilmunya
Sama-sama Setyo.
farahinwonderland wrote on Jul 12, '07
udah nonton harry potter belum
udah, semalem, bareng rombongan di jakarta theatre. tapi pas di tengah film, mati. huh! sebentar sih :)
wishknew wrote on Jul 12, '07
tapi pas di tengah film, mati. huh!
Masih menunggu janji Joni kali..
beeography wrote on Jul 12, '07
Bagusan lagi kalo field-nya gak hard coded gitu, bro. Jadiin aja semacam INI file. Trus migrasi bisa milih source INI file dan target INI file, mapping field bisa dilakukan oleh user sendiri. ;)
wishknew wrote on Jul 12, '07
For all, untuk FILE AS, isinya ternyata "First Last", "First, Last", "Company", dst. Baru ketahuan setelah lihat di Zimbranya.
umarfaisol wrote on Jul 12, '07
udah nonton harry potter belum?
Nunggu Cdnya aja... lagi males ke bioskop.
wishknew wrote on Jul 13, '07
Nunggu Cdnya aja... lagi males ke bioskop.
Oceh.
wishknew wrote on Jul 13, '07
Bagusan lagi kalo field-nya gak hard coded gitu, bro. Jadiin aja semacam INI file. Trus migrasi bisa milih source INI file dan target INI file, mapping field bisa dilakukan oleh user sendiri. ;)
Emang bener bro. Udah kepikiran waktu buat. Tapi budgetnya nggak nutup. Mesti ada CR (Change Request) kalau mau dibuat fitur itu :p. Wong ini dibuat hanya untuk konversi addressbook thunderbird yang defaultnya aja ke zimbra.

Makanya source code aku pasang di sini, barangkali ada yang mau serius membuat mappingnya (mirip di Outlook atau Thunderbird mapping), silakan.

Itu aja mbuatnya cuma setengah jam doang. Gak pake desain sama sekali. Hehehe..
umarfaisol wrote on Jul 22, '07
Btw mau nanya mas... Apa program yang dibuat dari delphi bisa ditampilkan di internet? Maksudnya seperti Applet atau Flash, atau barangkali ada cara untuk menampilkannya di internet. Rencananya program skripsi teman2 mau ditampilkan di internet. Tapi semuanya dibuat dengan delphi. Bisanya didownload baru dijalankan.

^_^
wishknew wrote on Jul 23, '07
Oh dikonversi saja ke ActiveX. Mudah kok caranya. Tinggal bikin ActiveX Form, lalu dicompile jadi OCX. Aku pernah melakukannya dan gak susah. Artikel yang paling mudah bisa dibaca di bukunya Teixeira, Delphi Developer Guide untuk D6.
umarfaisol wrote on Jul 24, '07
Artikel yang paling mudah bisa dibaca di bukunya Teixeira, Delphi Developer Guide untuk D6.
Makasih mas... tak coba dulu.
Comment deleted at the request of the author.
wishknew wrote on Jul 24, '07
Sama-sama!
Add a Comment