34
33
public class ThunderbirdContactItemSource : ItemSource
36
class EmailContactDetail: Item, IContactDetailItem
38
readonly string detail, description;
39
readonly ContactItem owner;
41
public EmailContactDetail (ContactItem owner, string detail)
45
description = string.IsNullOrEmpty (owner ["name"])
50
public override string Name {
51
get { return owner [detail]; }
54
public override string Description {
55
get { return description; }
58
public override string Icon {
59
get { return "thunderbird"; }
63
get { return detail; }
67
get { return owner [detail]; }
73
private Dictionary<string, uint> set;
77
set = new Dictionary<string, uint> ();
80
public void Add (string email, uint popularity)
82
if (!set.ContainsKey (email)) {
83
set.Add (email, popularity);
85
set [email] += popularity;
89
public bool Contains (string email)
91
return set.ContainsKey (email);
94
public uint this [string email] {
95
get { return set [email]; }
99
get { return set.Count; }
102
public ICollection<string> Keys {
103
get { return set.Keys; }
107
class ThunderbirdEmail
109
public readonly string email;
110
public readonly uint popularity;
112
public ThunderbirdEmail (string email, uint popularity)
115
this.popularity = popularity;
37
120
const string BeginProfileName = "Path=";
38
121
const string BeginDefaultProfile = "Name=default";
122
const string THUNDERBIRD_EMAIL = "email.thunderbird";
123
static readonly char[] nameDelimiters = { ' ', '\'', '"' };
125
Dictionary<string, Item> contacts; // name => ContactItem
42
127
public ThunderbirdContactItemSource ()
44
contacts = new List<Item> ();
129
contacts = new Dictionary<string, Item> ();
48
132
public override IEnumerable<Type> SupportedItemTypes {
50
134
return new Type[] {
56
140
public override string Name { get { return "Thunderbird Contacts"; } }
57
141
public override string Description { get { return "Thunderbird Contacts"; } }
58
142
public override string Icon { get { return "thunderbird"; } }
60
144
public override void UpdateItems ()
64
148
} catch (Exception e) {
65
Console.Error.WriteLine ("Cannot index Thunderbird contacts because a {0} was thrown: {1}", e.GetType (), e.Message);
149
Log<ThunderbirdContactItemSource>.Error ("Cannot index Thunderbird contacts because a {0} was thrown: {1}", e.GetType (), e.Message);
70
154
public override IEnumerable<Item> Items {
71
get { return contacts; }
155
get { return contacts.Values; }
74
158
public override IEnumerable<Item> ChildrenOfItem (Item item)
160
ContactItem contact = item as ContactItem;
162
foreach (string detail in contact.Details) {
163
if (detail.StartsWith (THUNDERBIRD_EMAIL)) {
164
yield return new EmailContactDetail (contact, detail);
79
170
void _UpdateItems ()
81
MorkDatabase database;
172
MorkDatabase abook, history;
173
Dictionary<string, EmailList> emails = new Dictionary<string, EmailList> ();
175
abook = new MorkDatabase (GetThunderbirdAddressBookFilePath ());
177
abook.EnumNamespace = "ns:addrbk:db:row:scope:card:all";
179
history = new MorkDatabase (GetThunderbirdHistoryFilePath ());
181
history.EnumNamespace = "ns:addrbk:db:row:scope:card:all";
183
addEmails (emails, history);
184
addEmails (emails, abook);
83
186
contacts.Clear ();
84
database = new MorkDatabase (GetThunderbirdAddressBookFilePath ());
86
database.EnumNamespace = "ns:addrbk:db:row:scope:card:all";
187
foreach (string name in emails.Keys) {
188
CreateThunderbirdContactItem (name, emails [name]);
192
void addEmails (Dictionary<string, EmailList> emails, MorkDatabase database)
88
194
foreach (string id in database) {
89
Hashtable contact_row;
92
contact_row = database.Compile (id, database.EnumNamespace);
93
contact = CreateThunderbirdContactItem (contact_row);
95
contacts.Add (contact);
195
Hashtable contact_row = database.Compile (id, database.EnumNamespace);
196
AddThunderbirdEmail (emails, contact_row);
99
ContactItem CreateThunderbirdContactItem (Hashtable row) {
200
void AddThunderbirdEmail (Dictionary<string, EmailList> emails, Hashtable row)
101
202
string name, email;
103
// foreach (object o in row.Keys)
104
// Console.WriteLine ("\t{0} --> {1}", o, row[o]);
106
205
// I think this will detect deleted contacts... Hmm...
107
if (row["table"] == null || row["table"] as string == "C6")
206
if (row ["table"] == null || row ["table"] as string == "C6")
111
name = row["DisplayName"] as string;
210
name = row ["DisplayName"] as string;
212
name = name.Trim (nameDelimiters);
112
214
if (name == null || name == string.Empty)
113
name = string.Format ("{0} {1}", row["FirstName"], row["LastName"]);
114
contact = ContactItem.Create (name);
215
name = string.Format ("{0} {1}", row ["FirstName"], row ["LastName"]);
117
email = row["PrimaryEmail"] as string;
118
if (email != null && email != string.Empty)
119
contact["email"] = email;
218
email = row ["PrimaryEmail"] as string;
219
string p = row ["PopularityIndex"] as string;
221
popularity = UInt32.Parse (p, System.Globalization.NumberStyles.HexNumber);
222
} catch (Exception) {
124
string GetThunderbirdAddressBookFilePath ()
226
if (name == null || name.Trim () == string.Empty)
229
if (string.IsNullOrEmpty (email))
232
if (!emails.ContainsKey (name)) {
233
emails [name] = new EmailList ();
235
emails [name].Add (email, popularity);
238
void CreateThunderbirdContactItem (string name, EmailList emails)
240
int emailCount = emails.Count;
241
ThunderbirdEmail[] sortedEmails = new ThunderbirdEmail[emailCount];
244
foreach (string key in emails.Keys) {
245
sortedEmails [i] = new ThunderbirdEmail (key, emails [key]);
248
Array.Sort (sortedEmails, (x, y) => (int)(y.popularity - x.popularity));
250
ContactItem contact = ContactItem.Create (name);
251
for (i = 0; i < emailCount; i++) {
252
string detail = THUNDERBIRD_EMAIL + "." + i;
253
contact [detail] = sortedEmails [i].email;
256
if (!contacts.ContainsKey (name.ToLower ())) {
257
contacts.Add (name.ToLower (), contact);
261
string GetThunderbirdDefaultProfilePath ()
126
263
string home, path, profile;
127
264
StreamReader reader;
130
267
home = System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal);
131
path = System.IO.Path.Combine (home, ".mozilla-thunderbird/profiles.ini");
268
path = System.IO.Path.Combine (home, ".thunderbird/profiles.ini");
133
270
reader = System.IO.File.OpenText (path);
142
279
line = line.Substring (BeginProfileName.Length);
146
else if (line.StartsWith (BeginDefaultProfile)) {
282
} else if (line.StartsWith (BeginDefaultProfile)) {
147
283
got_default = true;
290
string GetThunderbirdFilePath (string filename)
292
string path, home, profile;
293
home = System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal);
294
profile = GetThunderbirdDefaultProfilePath ();
152
295
if (profile == null) {
155
path = System.IO.Path.Combine (home, ".mozilla-thunderbird");
298
path = System.IO.Path.Combine (home, ".thunderbird");
156
299
path = System.IO.Path.Combine (path, profile);
157
path = System.IO.Path.Combine (path, "abook.mab");
300
path = System.IO.Path.Combine (path, filename);
304
string GetThunderbirdHistoryFilePath ()
306
return GetThunderbirdFilePath ("history.mab");
309
string GetThunderbirdAddressBookFilePath ()
311
return GetThunderbirdFilePath ("abook.mab");