New e-d-s backend which indexes all local addressbooks and calendars.
[beagle.git] / Util / Mozilla.cs
blob2d6f956f71810deb72131b2ccc62ddae59634df7
1 //
2 // Mozilla.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
6 // Authors:
7 // Fredrik Hedberg (fredrik.hedberg@avafan.com)
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in all
19 // copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 // SOFTWARE.
30 using System;
31 using System.IO;
32 using System.Text;
33 using System.Collections;
34 using System.Globalization;
36 namespace Beagle.Util.Mozilla
38 /// <summary>
39 /// Class representing a Mozilla profile, used to get a user's profiles and accounts
40 /// </summary>
41 public class Profile
43 // FIXME: Move Beagle.Daemon.PathFinder to Beagle.Platform namespace dammit
44 #if true
45 static string datadir = Environment.GetEnvironmentVariable("HOME"); // Unix
46 #else
47 static string datadir = Environment.GetEnvironmentVariable("APPDATA"); // Win32
48 #endif
50 // FIXME: Add more default locations
51 static string[] dirs =
53 "Thunderbird",
54 ".thunderbird",
55 "Mozilla" + System.IO.Path.DirectorySeparatorChar + "Firefox",
56 ".mozilla" + System.IO.Path.DirectorySeparatorChar + "firefox"
59 Hashtable accounts = new Hashtable ();
61 public ICollection Accounts {
62 get { return accounts.Values; }
65 string name;
66 public string Name {
67 get { return name; }
70 string path;
71 public string Path {
72 get { return path; }
75 /// <summary>
76 /// Creates and parses a profile from a prefs.js file
77 /// <summary>
78 public Profile (string name, string path)
80 this.name = name;
81 this.path = path;
83 Preferences prefs = new Preferences ( System.IO.Path.Combine (path, "prefs.js"));
85 string accountlist = prefs ["mail.accountmanager.accounts"];
87 if (accountlist != null) {
89 string[] accounts = accountlist.Split (',');
91 foreach (string accountname in accounts) {
93 Account account = new Account ();
94 string servername = prefs [String.Format ("mail.account.{0}.server", accountname)];
96 account.Path = prefs [String.Format ("mail.server.{0}.directory", servername)];
97 account.Name = prefs [String.Format ("mail.server.{0}.name", servername)];
98 account.Type = prefs [String.Format ("mail.server.{0}.type", servername)];
100 this.accounts.Add (accountname, account);
105 /// <summary>
106 /// Fetch a users profiles from default locations
107 /// <summary>
108 public static ICollection ReadProfiles ()
110 ArrayList profiles = new ArrayList ();
112 foreach (string subdir in dirs)
114 string dir = System.IO.Path.Combine (datadir, subdir);
116 if (!Directory.Exists (dir))
117 continue;
119 profiles.AddRange (ReadProfiles (dir));
122 return profiles;
125 /// <summary>
126 /// Fetch a users profiles from a specific profiles.ini file
127 /// <summary>
128 public static ICollection ReadProfiles (string path)
130 ArrayList profiles = new ArrayList ();
132 StreamReader reader = new StreamReader (new FileStream (System.IO.Path.Combine (path, "profiles.ini"), FileMode.Open, FileAccess.Read, FileShare.Read));
134 string lname = null;
135 string lpath = null;
137 string data = null;
139 while ((data = reader.ReadLine ()) != null) {
141 if (data.StartsWith ("[") && lname != null && lpath != null)
142 profiles.Add (new Profile (lname, System.IO.Path.Combine(path, lpath)));
144 if (data.IndexOf ("=") == -1)
145 continue;
147 string[] fields = data.Split ('=');
149 switch (fields[0].ToLower ())
151 case "name":
152 lname = fields[1];
153 break;
154 case "path":
155 lpath = fields[1];
156 break;
161 if (lname != null && lpath != null)
162 profiles.Add (new Profile (lname, System.IO.Path.Combine (path, lpath)));
164 return profiles;
168 /// <summary>
169 /// Class representing a Mozilla account
170 /// </summary>
171 public class Account
173 public string Path;
174 public string Name;
175 public string Type;
178 /// <summary>
179 /// Class for parsing Mozilla preferences files - prefs.js
180 /// </summary>
181 public class Preferences
183 Hashtable properties = new Hashtable ();
185 public Preferences (string path)
187 StreamReader reader = new StreamReader (new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.Read));
189 string data;
191 while ((data = reader.ReadLine ()) != null) {
193 if (!data.StartsWith ("user_pref"))
194 continue;
196 // FIXME: Use regexps
198 int index = data.IndexOf ('"',11);
200 string key = data.Substring (11, index-11);
201 string value = data.Substring (index, data.IndexOf (')')-index).Substring (3).Trim ('"');
203 properties[key] = value;
206 reader.Close ();
209 public IDictionary Properties {
210 get { return properties; }
213 public ICollection Keys {
214 get { return properties.Keys; }
217 virtual public string this [string key] {
218 get { return (string) properties [key]; }
219 set {
220 if (value == null || value == "") {
221 if (properties.Contains (key))
222 properties.Remove (key);
223 return;
225 properties [key] = value as string;
231 /// <summary>
232 /// Message (mail, rss whatever) in Mozilla
233 /// </summary>
234 public class Message
236 public string Id;
237 public string Date;
238 public string Subject;
239 public string From;
240 public string To;
241 public string Path;
242 public int Offset;
244 StringBuilder body = new StringBuilder ();
246 public string Body {
247 get { return body.ToString (); }
250 public void AppendBody (string str)
252 body.Append (str);
255 public Hashtable Headers = new Hashtable ();
258 public class Address
260 public string Name;
261 public string Email;
263 public override string ToString ()
265 if (Name != null && Name != "")
266 return String.Format ("{0} <{1}>", Name, Email);
267 else
268 return Email;
271 public static ICollection Parse (string str)
273 return null;
277 /// <summary>
278 /// FIXME: This is a hack and does not comply with any RFC, nor does it support attachments, encodings and other fancy shit
279 /// FIXME: Use a lib like gmime to parse messages, must be available on Linux, Win32 & MacOSX.
280 /// </summary>
281 public class MessageReader
283 StreamReader reader;
284 bool hasMore = true;
285 Message message;
286 string path;
288 public MessageReader (string path) : this (path, -1)
290 Console.WriteLine ("Doing: " + path);
293 public MessageReader (string path, int offset)
295 this.path = path;
297 FileStream stream;
299 try {
300 stream = new FileStream (path,
301 FileMode.Open,
302 FileAccess.Read,
303 FileShare.Read);
305 if (offset > 0)
306 stream.Seek (offset, SeekOrigin.Begin);
308 reader = new StreamReader (stream);
310 } catch (Exception e) {
311 Console.WriteLine ("Could not open '{0}' (offset={1})", path, offset);
312 Console.WriteLine (e);
315 reader.ReadLine ();
320 public bool HasMoreMessages
322 get { return hasMore; }
325 public Message NextMessage
327 get {
328 Read ();
329 return message;
333 private void Read ()
335 message = new Message ();
336 message.Path = path;
337 string data;
338 bool isBody = false;
340 try {
342 while ((data = reader.ReadLine ()) != null) {
344 // Break for new message
346 if (data.StartsWith ("From - ")) {
347 return;
350 // Add body to message
352 if (isBody) {
353 message.AppendBody (data);
354 continue;
357 // Break for message content
359 if (data.Length == 0) {
360 isBody = true;
361 continue;
364 // It's a header
366 int index = data.IndexOf (":");
368 if (index != -1 && !data.StartsWith (" ")) {
370 if (data.Length < index +2)
371 continue;
372 string key = data.Substring (0, index);
373 string value = data.Substring (index + 2);
375 message.Headers [key] = value;
377 switch (key.ToLower ()) {
378 case "subject":
379 message.Subject = value;
380 break;
381 case "from":
382 message.From = value;
383 break;
384 case "to":
385 message.To = value;
386 break;
387 case "date":
388 message.Date = value;
389 break;
390 case "message-id":
391 char[] shit = {'<', '>'};
392 message.Id = value.Trim (shit);
393 break;
398 hasMore = false;
399 } catch (Exception e) {
400 Console.WriteLine (e);
401 return;
406 #if false
407 public class Test
409 public static void Main (string[] args)
411 foreach (Profile profile in Profile.ReadProfiles ()) {
412 Console.WriteLine("Profile: {0} - {1}", profile.Name, profile.Path);
413 foreach (Account account in profile.Accounts) {
414 Console.WriteLine ("\t{0} ({1}) - {2}", account.Name, account.Type, account.Path);
419 #endif