~ted/ubuntu/lucid/tomboy/with-patch

« back to all changes in this revision

Viewing changes to Tomboy/Addins/Evolution/EvolutionNoteAddin.cs

  • Committer: Bazaar Package Importer
  • Author(s): Pedro Fragoso
  • Date: 2008-01-15 11:32:52 UTC
  • mfrom: (1.1.31 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080115113252-p59wg7nqkl6vcg7a
Tags: 0.9.4-0ubuntu1
* New upstream release (LP: #181798)
  - Fix crash during note deletion 
  - Fix null reference exception 
  - Fix mnemonics in sync preferences dialog 
  - Fix fuse mount timeout for sync 
  - New port option for SSH sync 
  - New multi-select notes support in Search All Notes window
  - New config dialog for Insert Timestamp Add-in 
  - New gconf preference, middle-click paste on Tomboy icon
  - New gconf preference, disable ESC closing notes 
  - New paragraph within a bullet with SHIFT + ENTER
  - New bug numbers as links in Export to HTML 
  - New notebook notes can be created off notebook's context menu.
  - New sketching add-in (still incomplete, --enable-sketching)
  - New "Unfiled Notes" item to notebook list 
  - New drag note to "Unfiled Notes" to remove from notebook 
 * debian/tomboy.menu: updated

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
namespace Tomboy.Evolution
18
18
{
19
19
 
20
 
class EvoUtils
21
 
{
22
 
        // Cache of account URLs to account UIDs
23
 
        static Hashtable source_url_to_uid;
24
 
 
25
 
        static GConf.Client gc;
26
 
        static GConf.NotifyEventHandler changed_handler;
27
 
 
28
 
        static EvoUtils ()
 
20
        class EvoUtils
29
21
        {
30
 
                try {
31
 
                        gc = new GConf.Client ();
32
 
            
33
 
                        changed_handler = new GConf.NotifyEventHandler (OnAccountsSettingChanged);
34
 
                        gc.AddNotify ("/apps/evolution/mail/accounts", changed_handler);
35
 
                                
36
 
                        source_url_to_uid = new Hashtable ();
 
22
                // Cache of account URLs to account UIDs
 
23
                static Hashtable source_url_to_uid;
 
24
 
 
25
                static GConf.Client gc;
 
26
                static GConf.NotifyEventHandler changed_handler;
 
27
 
 
28
                static EvoUtils ()
 
29
                {
 
30
                        try {
 
31
                                gc = new GConf.Client ();
 
32
 
 
33
                                changed_handler = new GConf.NotifyEventHandler (OnAccountsSettingChanged);
 
34
                                gc.AddNotify ("/apps/evolution/mail/accounts", changed_handler);
 
35
 
 
36
                                source_url_to_uid = new Hashtable ();
 
37
                                SetupAccountUrlToUidMap ();
 
38
                        }
 
39
                        catch (Exception e) {
 
40
                                Logger.Log ("Evolution: Error reading accounts: {0}", e);
 
41
                        }
 
42
                }
 
43
 
 
44
                static void OnAccountsSettingChanged (object sender, GConf.NotifyEventArgs args)
 
45
                {
37
46
                        SetupAccountUrlToUidMap ();
38
 
                } 
39
 
                catch (Exception e) {
40
 
                        Logger.Log ("Evolution: Error reading accounts: {0}", e);
41
 
                }
42
 
        }
43
 
 
44
 
        static void OnAccountsSettingChanged (object sender, GConf.NotifyEventArgs args)
45
 
        {
46
 
                SetupAccountUrlToUidMap ();
47
 
        }
48
 
 
49
 
        static void SetupAccountUrlToUidMap ()
50
 
        {
51
 
                source_url_to_uid.Clear ();
52
 
 
53
 
                ICollection accounts = (ICollection) gc.Get ("/apps/evolution/mail/accounts");
54
 
 
55
 
                foreach (string xml in accounts) {
56
 
                        XmlDocument xmlDoc = new XmlDocument ();
57
 
 
58
 
                        xmlDoc.LoadXml (xml);
59
 
 
60
 
                        XmlNode account = xmlDoc.SelectSingleNode ("//account");
61
 
                        if (account == null)
62
 
                                continue;
63
 
 
64
 
                        string uid = null;
65
 
 
66
 
                        foreach (XmlAttribute attr in account.Attributes) {
67
 
                                if (attr.Name == "uid") {
68
 
                                        uid = attr.InnerText;
69
 
                                        break;
70
 
                                }
71
 
                        }
72
 
 
73
 
                        if (uid == null)
74
 
                                continue;
75
 
 
76
 
                        XmlNode source_url = xmlDoc.SelectSingleNode ("//source/url");
77
 
                        if (source_url == null || source_url.InnerText == null)
78
 
                                continue;
79
 
 
80
 
                        try {
81
 
                            Uri uri = new Uri (source_url.InnerText);
82
 
                            source_url_to_uid [uri] = uid;
83
 
                        } catch (System.UriFormatException) {
84
 
                            Logger.Log (
85
 
                                    "Evolution: Unable to parse account source URI \"{0}\"",
86
 
                                    source_url.InnerText);
87
 
                        }
88
 
                }
89
 
        }
90
 
 
91
 
        //
92
 
        // Duplicates evoluion/camel/camel-url.c:camel_url_encode and
93
 
        // escapes ";?" as well.
94
 
        //
95
 
        static string CamelUrlEncode (string uri_part)
96
 
        {
97
 
                // The characters Camel encodes
98
 
                const string camel_escape_chars = " \"%#<>{}|\\^[]`;?";
99
 
 
100
 
                StringBuilder builder = new StringBuilder (null);
101
 
                foreach (char c in uri_part) {
102
 
                        if (camel_escape_chars.IndexOf (c) > -1)
103
 
                                builder.Append (Uri.HexEscape (c));
104
 
                        else
105
 
                                builder.Append (c);
106
 
                }
107
 
 
108
 
                return builder.ToString ();
109
 
        }
110
 
        
111
 
        //
112
 
        // Duplicates
113
 
        // evolution/mail/mail-config.c:mail_config_get_account_by_source_url...
114
 
        //
115
 
        static string FindAccountUidForUri (Uri uri)
116
 
        {
117
 
                if (source_url_to_uid == null)
118
 
                        return null;
119
 
 
120
 
                string account_uid = null;
121
 
 
122
 
                foreach (Uri source_uri in source_url_to_uid.Keys) {
123
 
                        if (uri.Scheme != source_uri.Scheme)
124
 
                                continue;
125
 
                        
126
 
                        bool match = false;
127
 
 
128
 
                        // FIXME: check "authmech" matches too
 
47
                }
 
48
 
 
49
                static void SetupAccountUrlToUidMap ()
 
50
                {
 
51
                        source_url_to_uid.Clear ();
 
52
 
 
53
                        ICollection accounts = (ICollection) gc.Get ("/apps/evolution/mail/accounts");
 
54
 
 
55
                        foreach (string xml in accounts) {
 
56
                                XmlDocument xmlDoc = new XmlDocument ();
 
57
 
 
58
                                xmlDoc.LoadXml (xml);
 
59
 
 
60
                                XmlNode account = xmlDoc.SelectSingleNode ("//account");
 
61
                                if (account == null)
 
62
                                        continue;
 
63
 
 
64
                                string uid = null;
 
65
 
 
66
                                foreach (XmlAttribute attr in account.Attributes) {
 
67
                                        if (attr.Name == "uid") {
 
68
                                                uid = attr.InnerText;
 
69
                                                break;
 
70
                                        }
 
71
                                }
 
72
 
 
73
                                if (uid == null)
 
74
                                        continue;
 
75
 
 
76
                                XmlNode source_url = xmlDoc.SelectSingleNode ("//source/url");
 
77
                                if (source_url == null || source_url.InnerText == null)
 
78
                                        continue;
 
79
 
 
80
                                try {
 
81
                                        Uri uri = new Uri (source_url.InnerText);
 
82
                                        source_url_to_uid [uri] = uid;
 
83
                                } catch (System.UriFormatException) {
 
84
                                        Logger.Log (
 
85
                                                "Evolution: Unable to parse account source URI \"{0}\"",
 
86
                                                source_url.InnerText);
 
87
                                }
 
88
                        }
 
89
                }
 
90
 
 
91
                //
 
92
                // Duplicates evoluion/camel/camel-url.c:camel_url_encode and
 
93
                // escapes ";?" as well.
 
94
                //
 
95
                static string CamelUrlEncode (string uri_part)
 
96
                {
 
97
                        // The characters Camel encodes
 
98
                        const string camel_escape_chars = " \"%#<>{}|\\^[]`;?";
 
99
 
 
100
                        StringBuilder builder = new StringBuilder (null);
 
101
                        foreach (char c in uri_part) {
 
102
                                if (camel_escape_chars.IndexOf (c) > -1)
 
103
                                        builder.Append (Uri.HexEscape (c));
 
104
                                else
 
105
                                        builder.Append (c);
 
106
                        }
 
107
 
 
108
                        return builder.ToString ();
 
109
                }
 
110
 
 
111
                //
 
112
                // Duplicates
 
113
                // evolution/mail/mail-config.c:mail_config_get_account_by_source_url...
 
114
                //
 
115
                static string FindAccountUidForUri (Uri uri)
 
116
                {
 
117
                        if (source_url_to_uid == null)
 
118
                                return null;
 
119
 
 
120
                        string account_uid = null;
 
121
 
 
122
                        foreach (Uri source_uri in source_url_to_uid.Keys) {
 
123
                                if (uri.Scheme != source_uri.Scheme)
 
124
                                        continue;
 
125
 
 
126
                                bool match = false;
 
127
 
 
128
                                // FIXME: check "authmech" matches too
 
129
                                switch (uri.Scheme) {
 
130
                                case "pop":
 
131
                                case "sendmail":
 
132
                                case "smtp":
 
133
                                        match = (uri.PathAndQuery == source_uri.PathAndQuery) &&
 
134
                                                (uri.Authority == source_uri.Authority) &&
 
135
                                                (uri.UserInfo == source_uri.UserInfo);
 
136
                                        break;
 
137
 
 
138
                                case "mh":
 
139
                                case "mbox":
 
140
                                case "maildir":
 
141
                                case "spool":
 
142
                                        // FIXME: Do some path canonicalization here?
 
143
                                        match = (uri.PathAndQuery == source_uri.PathAndQuery) &&
 
144
                                                (uri.Authority == source_uri.Authority) &&
 
145
                                                (uri.UserInfo == source_uri.UserInfo);
 
146
                                        break;
 
147
 
 
148
                                case "imap":
 
149
                                case "imap4":
 
150
                                case "imapp":
 
151
                                case "groupwise":
 
152
                                case "nntp":
 
153
                                case "exchange":
 
154
                                        match = (uri.Authority == source_uri.Authority) &&
 
155
                                                (uri.UserInfo == source_uri.UserInfo);
 
156
                                        break;
 
157
                                }
 
158
 
 
159
                                if (match) {
 
160
                                        account_uid = (string) source_url_to_uid [source_uri];
 
161
                                        Logger.Log ("Evolution: Matching account '{0}'...",
 
162
                                                    account_uid);
 
163
                                        break;
 
164
                                }
 
165
                        }
 
166
 
 
167
                        return account_uid;
 
168
                }
 
169
 
 
170
                //
 
171
                // Duplicates evolution/mail/em-utils.c:em_uri_from_camel...
 
172
                //
 
173
                public static string EmailUriFromDropUri (string drop_uri)
 
174
                {
 
175
                        if (drop_uri.StartsWith ("email:"))
 
176
                                return drop_uri;
 
177
 
 
178
                        Uri uri = new Uri (drop_uri);
 
179
                        string account_uid = null;
 
180
                        string path;
 
181
 
 
182
                        if (drop_uri.StartsWith ("vfolder:"))
 
183
                                account_uid = "vfolder@local";
 
184
                        else {
 
185
                                account_uid = FindAccountUidForUri (uri);
 
186
 
 
187
                                if (account_uid == null)
 
188
                                        account_uid = "local@local";
 
189
                        }
 
190
 
129
191
                        switch (uri.Scheme) {
130
 
                        case "pop":
131
 
                        case "sendmail":
132
 
                        case "smtp":
133
 
                                match = (uri.PathAndQuery == source_uri.PathAndQuery) &&
134
 
                                        (uri.Authority == source_uri.Authority) &&
135
 
                                        (uri.UserInfo == source_uri.UserInfo);
136
 
                                break;
137
 
 
 
192
                        case "imap4":
138
193
                        case "mh":
139
194
                        case "mbox":
140
195
                        case "maildir":
141
196
                        case "spool":
142
 
                                // FIXME: Do some path canonicalization here?
143
 
                                match = (uri.PathAndQuery == source_uri.PathAndQuery) &&
144
 
                                        (uri.Authority == source_uri.Authority) &&
145
 
                                        (uri.UserInfo == source_uri.UserInfo);
146
 
                                break;
147
 
 
148
 
                        case "imap":
149
 
                        case "imap4":
150
 
                        case "imapp":
151
 
                        case "groupwise":
152
 
                        case "nntp":
153
 
                        case "exchange":
154
 
                                match = (uri.Authority == source_uri.Authority) &&
155
 
                                        (uri.UserInfo == source_uri.UserInfo);
156
 
                                break;
157
 
                        }
158
 
 
159
 
                        if (match) {
160
 
                                account_uid = (string) source_url_to_uid [source_uri];
161
 
                                Logger.Log ("Evolution: Matching account '{0}'...", 
162
 
                                                   account_uid);
163
 
                                break;
164
 
                        }
165
 
                }
166
 
 
167
 
                return account_uid;
168
 
        }
169
 
 
170
 
        //
171
 
        // Duplicates evolution/mail/em-utils.c:em_uri_from_camel...
172
 
        //
173
 
        public static string EmailUriFromDropUri (string drop_uri)
174
 
        {
175
 
                if (drop_uri.StartsWith ("email:"))
176
 
                        return drop_uri;
177
 
 
178
 
                Uri uri = new Uri (drop_uri);
179
 
                string account_uid = null;
180
 
                string path; 
181
 
 
182
 
                if (drop_uri.StartsWith ("vfolder:"))
183
 
                        account_uid = "vfolder@local";
184
 
                else {
185
 
                        account_uid = FindAccountUidForUri (uri);
186
 
 
187
 
                        if (account_uid == null)
188
 
                                account_uid = "local@local";
189
 
                }
190
 
 
191
 
                switch (uri.Scheme) {
192
 
                case "imap4":
193
 
                case "mh":
194
 
                case "mbox":
195
 
                case "maildir":
196
 
                case "spool":
197
 
                        // These schemes keep the folder as the URI fragment
198
 
                        path = uri.Fragment;
199
 
                        break;
200
 
                default:
201
 
                        path = uri.AbsolutePath;
202
 
                        break;
203
 
                }
204
 
 
205
 
                if (path != string.Empty) {
206
 
                        // Skip leading '/' or '#'...
207
 
                        path = path.Substring (1); 
208
 
                        path = CamelUrlEncode (path);
209
 
                }
210
 
 
211
 
                return string.Format ("email://{0}/{1}", account_uid, path);
212
 
        }
213
 
 
214
 
        public static string EmailUriFromDropUri (string drop_uri, string uid)
215
 
        {
216
 
                string email_uri = EmailUriFromDropUri (drop_uri);
217
 
 
218
 
                if (email_uri == null)
219
 
                        return null;
220
 
                else
221
 
                        return string.Format ("{0};uid={1}", email_uri, uid);
222
 
        }
223
 
}
224
 
 
225
 
public class EmailLink : DynamicNoteTag
226
 
{
227
 
        public EmailLink ()
228
 
                : base ()
229
 
        {
230
 
        }
231
 
 
232
 
        public override void Initialize (string element_name)
233
 
        {
234
 
                base.Initialize (element_name);
235
 
 
236
 
                Underline = Pango.Underline.Single;
237
 
                Foreground = "blue";
238
 
                CanActivate = true;
239
 
 
240
 
                Image = new Gdk.Pixbuf (null, "stock_mail.png");
241
 
        }
242
 
 
243
 
        public string EmailUri
244
 
        {
245
 
                get { return (string) Attributes ["uri"]; }
246
 
                set { Attributes ["uri"] = value; }
247
 
        }
248
 
        
249
 
        protected override bool OnActivate (NoteEditor editor,
250
 
                                            Gtk.TextIter start, 
251
 
                                            Gtk.TextIter end)
252
 
        {
253
 
                Process p = new Process ();
254
 
                p.StartInfo.FileName = "evolution";
255
 
                p.StartInfo.Arguments = EmailUri;
256
 
                p.StartInfo.UseShellExecute = false;
257
 
 
258
 
                try {
259
 
                        p.Start ();
260
 
                } catch (Exception e) {
261
 
                        string message = String.Format ("Error running Evolution: {0}", 
262
 
                                                        e.Message);
263
 
                        Logger.Log (message);
264
 
                        HIGMessageDialog dialog = 
265
 
                                new HIGMessageDialog (editor.Toplevel as Gtk.Window,
266
 
                                                      Gtk.DialogFlags.DestroyWithParent,
267
 
                                                      Gtk.MessageType.Info,
268
 
                                                      Gtk.ButtonsType.Ok,
269
 
                                                      Catalog.GetString ("Cannot open email"),
270
 
                                                      message);
271
 
                        dialog.Run ();
272
 
                        dialog.Destroy ();
273
 
                }
274
 
 
275
 
                return true;
276
 
        }
277
 
}
278
 
 
279
 
 
280
 
public class EvolutionNoteAddin : NoteAddin
281
 
{
282
 
        // Used in the two-phase evolution drop handling.
283
 
        ArrayList xuid_list;
284
 
        ArrayList subject_list;
285
 
 
286
 
        static EvolutionNoteAddin ()
287
 
        {
288
 
                GMime.Global.Init();
289
 
        }
290
 
 
291
 
        public override void Initialize ()
292
 
        {
293
 
                if (!Note.TagTable.IsDynamicTagRegistered ("link:evo-mail")) {
294
 
                        Note.TagTable.RegisterDynamicTag ("link:evo-mail", typeof (EmailLink));
295
 
                }
296
 
        }
297
 
 
298
 
        Gtk.TargetList TargetList 
299
 
        {
300
 
                get {
301
 
                        return Gtk.Drag.DestGetTargetList (Window.Editor);
302
 
                }
303
 
        }
304
 
 
305
 
        public override void Shutdown ()
306
 
        {
307
 
                if (HasWindow)
308
 
                        TargetList.Remove (Gdk.Atom.Intern ("x-uid-list", false));
309
 
        }
310
 
 
311
 
        public override void OnNoteOpened () 
312
 
        {
313
 
                TargetList.Add (Gdk.Atom.Intern ("x-uid-list", false), 0, 99);
314
 
                Window.Editor.DragDataReceived += OnDragDataReceived;
315
 
        }
316
 
 
317
 
        [DllImport("libgobject-2.0.so.0")]
318
 
        static extern void g_signal_stop_emission_by_name (IntPtr raw, string name);
319
 
 
320
 
        //
321
 
        // DND Drop Handling
322
 
        //
323
 
        [GLib.ConnectBefore]
324
 
        void OnDragDataReceived (object sender, Gtk.DragDataReceivedArgs args)
325
 
        {
326
 
                bool stop_emission = false;
327
 
                
328
 
                if (args.SelectionData.Length < 0)
329
 
                        return;
330
 
 
331
 
                if (args.Info == 1) {
332
 
                        foreach (Gdk.Atom atom in args.Context.Targets) {
333
 
                                if (atom.Name == "x-uid-list") {
334
 
                                        // Parse MIME mails in tmp files
335
 
                                        DropEmailUriList (args);
336
 
 
337
 
                                        Gtk.Drag.GetData (Window.Editor, 
338
 
                                                          args.Context, 
339
 
                                                          Gdk.Atom.Intern ("x-uid-list", false),
340
 
                                                          args.Time);
341
 
 
342
 
                                        Gdk.Drag.Status (args.Context, 
343
 
                                                         Gdk.DragAction.Link, 
344
 
                                                         args.Time);
345
 
                                        stop_emission = true;
346
 
                                }
347
 
                        }
348
 
                } else if (args.Info == 99) {
349
 
                        // Parse the evolution internal URLs and generate email:
350
 
                        // URLs we can pass on the commandline.
351
 
                        DropXUidList (args);
352
 
 
353
 
                        // Insert the email: links into the note, using the
354
 
                        // message subject as the display text.
355
 
                        InsertMailLinks (args.X, args.Y, xuid_list, subject_list);
356
 
 
357
 
                        Gtk.Drag.Finish (args.Context, true, false, args.Time);
358
 
                        stop_emission = true;
359
 
                }
360
 
 
361
 
                // No return value for drag_data_received so no way to stop the
362
 
                // default TextView handler from running without resorting to
363
 
                // violence...
364
 
                if (stop_emission) {
365
 
                        g_signal_stop_emission_by_name(Window.Editor.Handle,
366
 
                                                       "drag_data_received");
367
 
                }
368
 
        }
369
 
 
370
 
        void DropEmailUriList (Gtk.DragDataReceivedArgs args)
371
 
        {
372
 
                string uri_string = Encoding.UTF8.GetString (args.SelectionData.Data);
373
 
 
374
 
                subject_list = new ArrayList();
375
 
 
376
 
                UriList uri_list = new UriList (uri_string);
377
 
                foreach (Uri uri in uri_list) {
378
 
                        Logger.Log ("Evolution: Dropped URI: {0}", uri.LocalPath);
379
 
 
380
 
                        int mail_fd = Syscall.open (uri.LocalPath, OpenFlags.O_RDONLY);
381
 
                        if (mail_fd == -1)
382
 
                                continue;
383
 
 
384
 
                        GMime.Stream stream = new GMime.StreamFs (mail_fd);
385
 
                        GMime.Parser parser = new GMime.Parser (stream);
386
 
                        parser.ScanFrom = true;
387
 
 
388
 
                        // Use GMime to read the RFC822 message bodies (in temp
389
 
                        // files pointed to by a uri-list) in MBOX format, so we
390
 
                        // can get subject/sender/date info.
391
 
                        while (!parser.Eos()) {
392
 
                                GMime.Message message = parser.ConstructMessage ();
393
 
                                if (message == null)
394
 
                                        break;
395
 
 
396
 
                                string subject = GMime.Utils.HeaderDecodePhrase (message.Subject);
397
 
                                subject_list.Add (subject);
398
 
                                message.Dispose ();
399
 
 
400
 
                                Logger.Log ("Evolution: Message Subject: {0}", subject);
401
 
                        };
402
 
 
403
 
                        parser.Dispose ();
404
 
                        stream.Close ();
405
 
                        stream.Dispose ();
406
 
                }
407
 
        }
408
 
 
409
 
        void DropXUidList (Gtk.DragDataReceivedArgs args)
410
 
        {
411
 
                // FIXME: x-uid-list is an Evolution-internal drop type.
412
 
                //        We shouldn't be using it, but there is no other way
413
 
                //        to get the info we need to be able to generate email:
414
 
                //        URIs evo will open on the command-line.
415
 
                //
416
 
                // x-uid-list Format: "uri\0uid1\0uid2\0uid3\0...\0uidn" 
417
 
                //
418
 
                string source = Encoding.UTF8.GetString (args.SelectionData.Data);
419
 
                string [] list = source.Split ('\0');
420
 
 
421
 
                xuid_list = new ArrayList ();
422
 
 
423
 
                Logger.Log ("Evolution: Dropped XUid: uri = '{0}'", list [0]);
424
 
 
425
 
                for (int i = 1; i < list.Length; i++) {
426
 
                        if (list [i] == string.Empty)
427
 
                                continue;
428
 
 
429
 
                        string launch_uri = 
430
 
                                EvoUtils.EmailUriFromDropUri (list [0] /* evo account uri */,
431
 
                                                              list [i] /* message uid */);
432
 
 
433
 
                        Logger.Log ("Evolution: Translating XUid uid='{0}' to uri='{1}'", 
434
 
                                           list [i],
435
 
                                           launch_uri);
436
 
 
437
 
                        xuid_list.Add (launch_uri);
438
 
                }
439
 
        }
440
 
 
441
 
        void InsertMailLinks (int x, int y, ArrayList xuid_list, ArrayList subject_list)
442
 
        {
443
 
                int message_idx = 0;
444
 
                bool more_than_one = false;
445
 
                
446
 
                // Place the cursor in the position where the uri was
447
 
                // dropped, adjusting x,y by the TextView's VisibleRect.
448
 
                Gdk.Rectangle rect = Window.Editor.VisibleRect;
449
 
                x = x + rect.X;
450
 
                y = y + rect.Y;
451
 
                Gtk.TextIter cursor = Window.Editor.GetIterAtLocation (x, y);
452
 
                Buffer.PlaceCursor (cursor);
453
 
 
454
 
                foreach (string subject in subject_list) {
455
 
                        int start_offset;
456
 
 
457
 
                        if (more_than_one) {
 
197
                                // These schemes keep the folder as the URI fragment
 
198
                                path = uri.Fragment;
 
199
                                break;
 
200
                        default:
 
201
                                path = uri.AbsolutePath;
 
202
                                break;
 
203
                        }
 
204
 
 
205
                        if (path != string.Empty) {
 
206
                                // Skip leading '/' or '#'...
 
207
                                path = path.Substring (1);
 
208
                                path = CamelUrlEncode (path);
 
209
                        }
 
210
 
 
211
                        return string.Format ("email://{0}/{1}", account_uid, path);
 
212
                }
 
213
 
 
214
                public static string EmailUriFromDropUri (string drop_uri, string uid)
 
215
                {
 
216
                        string email_uri = EmailUriFromDropUri (drop_uri);
 
217
 
 
218
                        if (email_uri == null)
 
219
                                return null;
 
220
                        else
 
221
                                return string.Format ("{0};uid={1}", email_uri, uid);
 
222
                }
 
223
        }
 
224
 
 
225
        public class EmailLink : DynamicNoteTag
 
226
        {
 
227
                public EmailLink ()
 
228
: base ()
 
229
                {
 
230
                }
 
231
 
 
232
                public override void Initialize (string element_name)
 
233
                {
 
234
                        base.Initialize (element_name);
 
235
 
 
236
                        Underline = Pango.Underline.Single;
 
237
                        Foreground = "blue";
 
238
                        CanActivate = true;
 
239
 
 
240
                        Image = new Gdk.Pixbuf (null, "stock_mail.png");
 
241
                }
 
242
 
 
243
                public string EmailUri
 
244
                {
 
245
                        get {
 
246
                                return (string) Attributes ["uri"];
 
247
                        }
 
248
                        set {
 
249
                                Attributes ["uri"] = value;
 
250
                        }
 
251
                }
 
252
 
 
253
                protected override bool OnActivate (NoteEditor editor,
 
254
                                                    Gtk.TextIter start,
 
255
                                                    Gtk.TextIter end)
 
256
                {
 
257
                        Process p = new Process ();
 
258
                        p.StartInfo.FileName = "evolution";
 
259
                        p.StartInfo.Arguments = EmailUri;
 
260
                        p.StartInfo.UseShellExecute = false;
 
261
 
 
262
                        try {
 
263
                                p.Start ();
 
264
                        } catch (Exception e) {
 
265
                                string message = String.Format ("Error running Evolution: {0}",
 
266
                                                                e.Message);
 
267
                                Logger.Log (message);
 
268
                                HIGMessageDialog dialog =
 
269
                                        new HIGMessageDialog (editor.Toplevel as Gtk.Window,
 
270
                                                              Gtk.DialogFlags.DestroyWithParent,
 
271
                                                              Gtk.MessageType.Info,
 
272
                                                              Gtk.ButtonsType.Ok,
 
273
                                                              Catalog.GetString ("Cannot open email"),
 
274
                                                              message);
 
275
                                dialog.Run ();
 
276
                                dialog.Destroy ();
 
277
                        }
 
278
 
 
279
                        return true;
 
280
                }
 
281
        }
 
282
 
 
283
 
 
284
        public class EvolutionNoteAddin : NoteAddin
 
285
        {
 
286
                // Used in the two-phase evolution drop handling.
 
287
                ArrayList xuid_list;
 
288
                ArrayList subject_list;
 
289
 
 
290
                static EvolutionNoteAddin ()
 
291
                {
 
292
                        GMime.Global.Init();
 
293
                }
 
294
 
 
295
                public override void Initialize ()
 
296
                {
 
297
                        if (!Note.TagTable.IsDynamicTagRegistered ("link:evo-mail")) {
 
298
                                Note.TagTable.RegisterDynamicTag ("link:evo-mail", typeof (EmailLink));
 
299
                        }
 
300
                }
 
301
 
 
302
                Gtk.TargetList TargetList
 
303
                {
 
304
                        get {
 
305
                                return Gtk.Drag.DestGetTargetList (Window.Editor);
 
306
                        }
 
307
                }
 
308
 
 
309
                public override void Shutdown ()
 
310
                {
 
311
                        if (HasWindow)
 
312
                                TargetList.Remove (Gdk.Atom.Intern ("x-uid-list", false));
 
313
                }
 
314
 
 
315
                public override void OnNoteOpened ()
 
316
                {
 
317
                        TargetList.Add (Gdk.Atom.Intern ("x-uid-list", false), 0, 99);
 
318
                        Window.Editor.DragDataReceived += OnDragDataReceived;
 
319
                }
 
320
 
 
321
                [DllImport("libgobject-2.0.so.0")]
 
322
                static extern void g_signal_stop_emission_by_name (IntPtr raw, string name);
 
323
 
 
324
                //
 
325
                // DND Drop Handling
 
326
                //
 
327
                [GLib.ConnectBefore]
 
328
                void OnDragDataReceived (object sender, Gtk.DragDataReceivedArgs args)
 
329
                {
 
330
                        bool stop_emission = false;
 
331
 
 
332
                        if (args.SelectionData.Length < 0)
 
333
                                return;
 
334
 
 
335
                        if (args.Info == 1) {
 
336
                                foreach (Gdk.Atom atom in args.Context.Targets) {
 
337
                                        if (atom.Name == "x-uid-list") {
 
338
                                                // Parse MIME mails in tmp files
 
339
                                                DropEmailUriList (args);
 
340
 
 
341
                                                Gtk.Drag.GetData (Window.Editor,
 
342
                                                                  args.Context,
 
343
                                                                  Gdk.Atom.Intern ("x-uid-list", false),
 
344
                                                                  args.Time);
 
345
 
 
346
                                                Gdk.Drag.Status (args.Context,
 
347
                                                                 Gdk.DragAction.Link,
 
348
                                                                 args.Time);
 
349
                                                stop_emission = true;
 
350
                                        }
 
351
                                }
 
352
                        } else if (args.Info == 99) {
 
353
                                // Parse the evolution internal URLs and generate email:
 
354
                                // URLs we can pass on the commandline.
 
355
                                DropXUidList (args);
 
356
 
 
357
                                // Insert the email: links into the note, using the
 
358
                                // message subject as the display text.
 
359
                                InsertMailLinks (args.X, args.Y, xuid_list, subject_list);
 
360
 
 
361
                                Gtk.Drag.Finish (args.Context, true, false, args.Time);
 
362
                                stop_emission = true;
 
363
                        }
 
364
 
 
365
                        // No return value for drag_data_received so no way to stop the
 
366
                        // default TextView handler from running without resorting to
 
367
                        // violence...
 
368
                        if (stop_emission) {
 
369
                                g_signal_stop_emission_by_name(Window.Editor.Handle,
 
370
                                                               "drag_data_received");
 
371
                        }
 
372
                }
 
373
 
 
374
                void DropEmailUriList (Gtk.DragDataReceivedArgs args)
 
375
                {
 
376
                        string uri_string = Encoding.UTF8.GetString (args.SelectionData.Data);
 
377
 
 
378
                        subject_list = new ArrayList();
 
379
 
 
380
                        UriList uri_list = new UriList (uri_string);
 
381
                        foreach (Uri uri in uri_list) {
 
382
                                Logger.Log ("Evolution: Dropped URI: {0}", uri.LocalPath);
 
383
 
 
384
                                int mail_fd = Syscall.open (uri.LocalPath, OpenFlags.O_RDONLY);
 
385
                                if (mail_fd == -1)
 
386
                                        continue;
 
387
 
 
388
                                GMime.Stream stream = new GMime.StreamFs (mail_fd);
 
389
                                GMime.Parser parser = new GMime.Parser (stream);
 
390
                                parser.ScanFrom = true;
 
391
 
 
392
                                // Use GMime to read the RFC822 message bodies (in temp
 
393
                                // files pointed to by a uri-list) in MBOX format, so we
 
394
                                // can get subject/sender/date info.
 
395
                                while (!parser.Eos()) {
 
396
                                        GMime.Message message = parser.ConstructMessage ();
 
397
                                        if (message == null)
 
398
                                                break;
 
399
 
 
400
                                        string subject = GMime.Utils.HeaderDecodePhrase (message.Subject);
 
401
                                        subject_list.Add (subject);
 
402
                                        message.Dispose ();
 
403
 
 
404
                                        Logger.Log ("Evolution: Message Subject: {0}", subject);
 
405
                                };
 
406
 
 
407
                                parser.Dispose ();
 
408
                                stream.Close ();
 
409
                                stream.Dispose ();
 
410
                        }
 
411
                }
 
412
 
 
413
                void DropXUidList (Gtk.DragDataReceivedArgs args)
 
414
                {
 
415
                        // FIXME: x-uid-list is an Evolution-internal drop type.
 
416
                        //        We shouldn't be using it, but there is no other way
 
417
                        //        to get the info we need to be able to generate email:
 
418
                        //        URIs evo will open on the command-line.
 
419
                        //
 
420
                        // x-uid-list Format: "uri\0uid1\0uid2\0uid3\0...\0uidn"
 
421
                        //
 
422
                        string source = Encoding.UTF8.GetString (args.SelectionData.Data);
 
423
                        string [] list = source.Split ('\0');
 
424
 
 
425
                        xuid_list = new ArrayList ();
 
426
 
 
427
                        Logger.Log ("Evolution: Dropped XUid: uri = '{0}'", list [0]);
 
428
 
 
429
                        for (int i = 1; i < list.Length; i++) {
 
430
                                if (list [i] == string.Empty)
 
431
                                        continue;
 
432
 
 
433
                                string launch_uri =
 
434
                                        EvoUtils.EmailUriFromDropUri (list [0] /* evo account uri */,
 
435
                                                                      list [i] /* message uid */);
 
436
 
 
437
                                Logger.Log ("Evolution: Translating XUid uid='{0}' to uri='{1}'",
 
438
                                            list [i],
 
439
                                            launch_uri);
 
440
 
 
441
                                xuid_list.Add (launch_uri);
 
442
                        }
 
443
                }
 
444
 
 
445
                void InsertMailLinks (int x, int y, ArrayList xuid_list, ArrayList subject_list)
 
446
                {
 
447
                        int message_idx = 0;
 
448
                        bool more_than_one = false;
 
449
 
 
450
                        // Place the cursor in the position where the uri was
 
451
                        // dropped, adjusting x,y by the TextView's VisibleRect.
 
452
                        Gdk.Rectangle rect = Window.Editor.VisibleRect;
 
453
                        x = x + rect.X;
 
454
                        y = y + rect.Y;
 
455
                        Gtk.TextIter cursor = Window.Editor.GetIterAtLocation (x, y);
 
456
                        Buffer.PlaceCursor (cursor);
 
457
 
 
458
                        foreach (string subject in subject_list) {
 
459
                                int start_offset;
 
460
 
 
461
                                if (more_than_one) {
 
462
                                        cursor = Buffer.GetIterAtMark (Buffer.InsertMark);
 
463
 
 
464
                                        if (cursor.LineOffset == 0)
 
465
                                                Buffer.Insert (ref cursor, "\n");
 
466
                                        else
 
467
                                                Buffer.Insert (ref cursor, ", ");
 
468
                                }
 
469
 
 
470
                                string launch_uri = (string) xuid_list [message_idx++];
 
471
 
 
472
                                EmailLink link_tag;
 
473
                                link_tag = (EmailLink) Note.TagTable.CreateDynamicTag ("link:evo-mail");
 
474
                                link_tag.EmailUri = launch_uri;
 
475
 
458
476
                                cursor = Buffer.GetIterAtMark (Buffer.InsertMark);
459
 
 
460
 
                                if (cursor.LineOffset == 0) 
461
 
                                        Buffer.Insert (ref cursor, "\n");
462
 
                                else
463
 
                                        Buffer.Insert (ref cursor, ", ");
 
477
                                start_offset = cursor.Offset;
 
478
                                Buffer.Insert (ref cursor, subject);
 
479
 
 
480
                                Gtk.TextIter start = Buffer.GetIterAtOffset (start_offset);
 
481
                                Gtk.TextIter end = Buffer.GetIterAtMark (Buffer.InsertMark);
 
482
                                Buffer.ApplyTag (link_tag, start, end);
 
483
 
 
484
                                more_than_one = true;
464
485
                        }
465
 
 
466
 
                        string launch_uri = (string) xuid_list [message_idx++];
467
 
                        
468
 
                        EmailLink link_tag;
469
 
                        link_tag = (EmailLink) Note.TagTable.CreateDynamicTag ("link:evo-mail");
470
 
                        link_tag.EmailUri = launch_uri;
471
 
 
472
 
                        cursor = Buffer.GetIterAtMark (Buffer.InsertMark);
473
 
                        start_offset = cursor.Offset;
474
 
                        Buffer.Insert (ref cursor, subject);
475
 
 
476
 
                        Gtk.TextIter start = Buffer.GetIterAtOffset (start_offset);
477
 
                        Gtk.TextIter end = Buffer.GetIterAtMark (Buffer.InsertMark);
478
 
                        Buffer.ApplyTag (link_tag, start, end);
479
 
 
480
 
                        more_than_one = true;
481
486
                }
482
487
        }
483
 
}
484
488
 
485
489
}
 
 
b'\\ No newline at end of file'