OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 149 | Rev 182 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.utils;
15
 
16
import org.openconcerto.utils.DesktopEnvironment.Gnome;
17
import org.openconcerto.utils.DesktopEnvironment.KDE;
18
import org.openconcerto.utils.DesktopEnvironment.Mac;
19
import org.openconcerto.utils.DesktopEnvironment.Windows;
180 ilm 20
import org.openconcerto.utils.DesktopEnvironment.XFCE;
21
import org.openconcerto.utils.OSFamily.Unix;
17 ilm 22
import org.openconcerto.utils.io.PercentEncoder;
23
 
24
import java.io.BufferedOutputStream;
25
import java.io.BufferedWriter;
26
import java.io.File;
27
import java.io.IOException;
28
import java.io.OutputStreamWriter;
29
import java.io.PrintStream;
30
import java.io.Writer;
31
import java.net.URI;
32
import java.net.URISyntaxException;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35
import java.util.List;
36
import java.util.regex.Matcher;
37
import java.util.regex.Pattern;
38
 
39
public abstract class EmailClient {
40
 
41
    public static enum EmailClientType {
149 ilm 42
        Thunderbird, AppleMail, Outlook, XDG
17 ilm 43
    }
44
 
45
    private static EmailClient PREFERRED = null;
46
 
47
    /**
48
     * Find the preferred email client.
49
     *
50
     * @return the preferred email client, never <code>null</code>.
51
     * @throws IOException if an error occurs.
52
     */
53
    public static final EmailClient getPreferred() throws IOException {
54
        if (PREFERRED == null) {
55
            PREFERRED = findPreferred();
56
            // should at least return MailTo
57
            assert PREFERRED != null;
58
        }
59
        return PREFERRED;
60
    }
61
 
62
    /**
63
     * Clear the preferred client.
64
     */
65
    public static final void resetPreferred() {
66
        PREFERRED = null;
67
    }
68
 
69
    // XP used tabs, but not 7
70
    // MULTILINE since there's several lines in addition to the wanted one
71
    private static final Pattern registryPattern = Pattern.compile("\\s+REG_SZ\\s+(.*)$", Pattern.MULTILINE);
72
    private static final Pattern cmdLinePattern = Pattern.compile("(\"(.*?)\")|([^\\s\"]+)\\b");
28 ilm 73
    // any whitespace except space and tab
74
    private static final Pattern wsPattern = Pattern.compile("[\\s&&[^ \t]]");
17 ilm 75
    private static final Pattern dictPattern;
76
    private static final String AppleMailBundleID = "com.apple.mail";
77
    private static final String ThunderbirdBundleID = "org.mozilla.thunderbird";
78
    static {
79
        final String rolePattern = "(?:LSHandlerRoleAll\\s*=\\s*\"([\\w\\.]+)\";\\s*)?";
80
        dictPattern = Pattern.compile("\\{\\s*" + rolePattern + "LSHandlerURLScheme = mailto;\\s*" + rolePattern + "\\}");
81
    }
82
 
28 ilm 83
    private final static String createEncodedParam(final String name, final String value) {
84
        return name + "=" + PercentEncoder.encode(value, StringUtils.UTF8);
17 ilm 85
    }
86
 
87
    private final static String createASParam(final String name, final String value) {
28 ilm 88
        return name + ":" + StringUtils.doubleQuote(value);
17 ilm 89
    }
90
 
91
    private final static String createVBParam(final String name, final String value) {
92
        final String switchName = "/" + name + ":";
93
        if (value == null || value.length() == 0)
94
            return switchName;
95
        // we need to encode the value since when invoking cscript.exe we cannot pass "
96
        // since all arguments are re-parsed
97
        final String encoded = PercentEncoder.encodeUTF16(value);
98
        assert encoded.indexOf('"') < 0 : "Encoded contains a double quote, this will confuse cscript";
99
        return switchName + '"' + encoded + '"';
100
    }
101
 
102
    /**
103
     * Create a mailto URI.
104
     *
105
     * @param to the recipient, can be <code>null</code>.
106
     * @param subject the subject, can be <code>null</code>.
107
     * @param body the body of the email, can be <code>null</code>.
28 ilm 108
     * @param attachments files to attach, for security reason this parameter is ignored by at least
109
     *        Outlook 2007, Apple Mail and Thunderbird.
17 ilm 110
     * @return the mailto URI.
111
     * @throws IOException if an encoding error happens.
112
     * @see <a href="http://tools.ietf.org/html/rfc2368">RFC 2368</a>
61 ilm 113
     * @see <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=67254">Don&apos;t allow attachment
114
     *      of local file from non-local link</a>
17 ilm 115
     */
28 ilm 116
    public final static URI getMailToURI(final String to, final String subject, final String body, final File... attachments) throws IOException {
17 ilm 117
        // mailto:p.dupond@example.com?subject=Sujet%20du%20courrier&cc=pierre@example.org&bcc=jacques@example.net&body=Bonjour
118
 
119
        // Outlook doesn't support the to header as mandated by 2. of the RFC
28 ilm 120
        final String encodedTo = to == null ? "" : PercentEncoder.encode(to, StringUtils.UTF8);
17 ilm 121
        final List<String> l = new ArrayList<String>(4);
122
        if (subject != null)
123
            l.add(createEncodedParam("subject", subject));
124
        if (body != null)
125
            l.add(createEncodedParam("body", body));
28 ilm 126
        for (final File attachment : attachments)
17 ilm 127
            l.add(createEncodedParam("attachment", attachment.getAbsolutePath()));
128
        final String query = CollectionUtils.join(l, "&");
129
        try {
130
            return new URI("mailto:" + encodedTo + "?" + query);
131
        } catch (URISyntaxException e) {
132
            throw new IOException("Couldn't create mailto URI", e);
133
        }
134
    }
135
 
28 ilm 136
    // see http://kb.mozillazine.org/Command_line_arguments_(Thunderbird)
137
    // The escape mechanism isn't specified, it turns out we can pass percent encoded strings
138
    private final static String getTBParam(final String to, final String subject, final String body, final File... attachments) {
149 ilm 139
        /**
140
         * <pre>
141
          "to='john@example.com,kathy@example.com',cc='britney@example.com',subject='dinner',body='How about dinner tonight?',attachment='file:///C:/cygwin/Cygwin.bat,file:///C:/cygwin/Cygwin.ico'";
142
         * </pre>
143
         */
17 ilm 144
 
145
        final List<String> l = new ArrayList<String>(4);
146
        if (to != null)
28 ilm 147
            l.add(createEncodedParam("to", to));
17 ilm 148
        if (subject != null)
28 ilm 149
            l.add(createEncodedParam("subject", subject));
17 ilm 150
        if (body != null)
28 ilm 151
            l.add(createEncodedParam("body", body));
152
        final List<String> urls = new ArrayList<String>(attachments.length);
153
        for (final File attachment : attachments) {
17 ilm 154
            // Thunderbird doesn't parse java URI file:/C:/
61 ilm 155
            final String rawPath = attachment.toURI().getRawPath();
156
            // handle UNC paths
157
            final String tbURL = (rawPath.startsWith("//") ? "file:///" : "file://") + rawPath;
28 ilm 158
            urls.add(tbURL);
17 ilm 159
        }
28 ilm 160
        l.add(createEncodedParam("attachment", CollectionUtils.join(urls, ",")));
17 ilm 161
 
28 ilm 162
        return DesktopEnvironment.getDE().quoteParamForExec(CollectionUtils.join(l, ","));
17 ilm 163
    }
164
 
165
    private final static String getAppleMailParam(final String subject, final String body) {
166
        final List<String> l = new ArrayList<String>(3);
167
        l.add("visible:true");
168
        if (subject != null)
169
            l.add(createASParam("subject", subject));
170
        if (body != null)
171
            l.add(createASParam("content", body));
172
 
173
        return CollectionUtils.join(l, ", ");
174
    }
175
 
176
    // @param cmdLine "C:\Program Files\Mozilla Thunderbird\thunderbird.exe" -osint -compose "%1"
177
    // @param toReplace "%1"
28 ilm 178
    private static String[] tbCommand(final String cmdLine, final String toReplace, final String to, final String subject, final String body, final File... attachments) {
179
        final String composeArg = getTBParam(to, subject, body, attachments);
17 ilm 180
 
181
        final List<String> arguments = new ArrayList<String>();
182
        final Matcher cmdMatcher = cmdLinePattern.matcher(cmdLine);
183
        while (cmdMatcher.find()) {
184
            final String quoted = cmdMatcher.group(2);
185
            final String unquoted = cmdMatcher.group(3);
186
            assert quoted == null ^ unquoted == null : "Both quoted and unquoted, or neither quoted nor quoted: " + quoted + " and " + unquoted;
187
            final String arg = quoted != null ? quoted : unquoted;
188
 
189
            final boolean replace = arg.equals(toReplace);
190
            // e.g. on Linux
191
            if (replace && !arguments.contains("-compose"))
192
                arguments.add("-compose");
193
            arguments.add(replace ? composeArg : arg);
194
        }
195
 
196
        return arguments.toArray(new String[arguments.size()]);
197
    }
198
 
199
    /**
200
     * Open a composing window in the default email client.
201
     *
202
     * @param to the recipient, can be <code>null</code>.
203
     * @param subject the subject, can be <code>null</code>.
204
     * @param body the body of the email, can be <code>null</code>.
28 ilm 205
     * @param attachments files to attach, ATTN can be ignored if mailto: is used
206
     *        {@link #getMailToURI(String, String, String, File...)}.
17 ilm 207
     * @throws IOException if a program cannot be executed.
208
     * @throws InterruptedException if the thread is interrupted while waiting for a native program.
209
     */
28 ilm 210
    public void compose(final String to, String subject, final String body, final File... attachments) throws IOException, InterruptedException {
17 ilm 211
        // check now as letting the native commands do is a lot less reliable
28 ilm 212
        for (File attachment : attachments) {
213
            if (!attachment.exists())
214
                throw new IOException("Attachment doesn't exist: '" + attachment.getAbsolutePath() + "'");
215
        }
17 ilm 216
 
28 ilm 217
        // a subject should only be one line (Thunderbird strips newlines anyway and Outlook sends a
218
        // malformed email)
219
        subject = wsPattern.matcher(subject).replaceAll(" ");
17 ilm 220
        final boolean handled;
221
        // was only trying native if necessary, but mailto url has length limitations and can have
222
        // encoding issues
28 ilm 223
        handled = composeNative(to, subject, body, attachments);
17 ilm 224
 
225
        if (!handled) {
28 ilm 226
            final URI mailto = getMailToURI(to, subject, body, attachments);
17 ilm 227
            java.awt.Desktop.getDesktop().mail(mailto);
228
        }
229
    }
230
 
231
    static private String cmdSubstitution(String... args) throws IOException {
232
        return DesktopEnvironment.cmdSubstitution(Runtime.getRuntime().exec(args));
233
    }
234
 
235
    private static EmailClient findPreferred() throws IOException {
236
        final DesktopEnvironment de = DesktopEnvironment.getDE();
237
        if (de instanceof Windows) {
238
            // Tested on XP and 7
239
            // <SANS NOM> REG_SZ "C:\Program Files\Mozilla
240
            // Thunderbird\thunderbird.exe" -osint -compose "%1"
241
            final String out = cmdSubstitution("reg", "query", "HKEY_CLASSES_ROOT\\mailto\\shell\\open\\command");
242
 
243
            final Matcher registryMatcher = registryPattern.matcher(out);
244
            if (registryMatcher.find()) {
245
                final String cmdLine = registryMatcher.group(1);
246
                if (cmdLine.contains("thunderbird")) {
247
                    return new ThunderbirdCommandLine(cmdLine, "%1");
248
                } else if (cmdLine.toLowerCase().contains("outlook")) {
249
                    return Outlook;
250
                }
251
            }
252
        } else if (de instanceof Mac) {
253
            // (
254
            // {
255
            // LSHandlerRoleAll = "com.apple.mail";
256
            // LSHandlerURLScheme = mailto;
257
            // }
258
            // )
259
            final String bundleID;
260
            final String dict = cmdSubstitution("defaults", "read", "com.apple.LaunchServices", "LSHandlers");
261
            final Matcher dictMatcher = dictPattern.matcher(dict);
262
            if (dictMatcher.find()) {
263
                // LSHandlerRoleAll can be before or after LSHandlerURLScheme
264
                final String before = dictMatcher.group(1);
265
                final String after = dictMatcher.group(2);
266
                assert before == null ^ after == null : "Both before and after, or neither before nor after: " + before + " and " + after;
267
                bundleID = before != null ? before : after;
268
            } else
269
                // the default
270
                bundleID = AppleMailBundleID;
271
 
272
            if (bundleID.equals(AppleMailBundleID)) {
273
                return AppleMail;
274
            } else if (bundleID.equals(ThunderbirdBundleID)) {
275
                // doesn't work if Thunderbird is already open:
276
                // https://bugzilla.mozilla.org/show_bug.cgi?id=424155
277
                // https://bugzilla.mozilla.org/show_bug.cgi?id=472891
278
                // MAYBE find out if launched and let handled=false
28 ilm 279
 
61 ilm 280
                final File appDir = ((Mac) de).getAppDir(bundleID);
17 ilm 281
                final File exe = new File(appDir, "Contents/MacOS/thunderbird-bin");
282
 
283
                return new ThunderbirdPath(exe);
284
            }
285
        } else if (de instanceof Gnome) {
149 ilm 286
            if (de.getVersion().startsWith("2.")) {
287
                // evolution %s
288
                final String cmdLine = cmdSubstitution("gconftool", "-g", "/desktop/gnome/url-handlers/mailto/command");
289
                if (cmdLine.contains("thunderbird")) {
290
                    return new ThunderbirdCommandLine(cmdLine, "%s");
291
                }
17 ilm 292
            }
149 ilm 293
            return XDG;
17 ilm 294
        } else if (de instanceof KDE) {
295
            // TODO look for EmailClient=/usr/bin/thunderbird in
296
            // ~/.kde/share/config/emaildefaults or /etc/kde (ou /usr/share/config qui est un
297
            // lien symbolique vers /etc/kde)
149 ilm 298
            return XDG;
180 ilm 299
        } else if (de instanceof XFCE) {
300
            // .config/xfce4/helpers.rc contains "MailReader=desktopName"
301
            // A custom one can be created in .local/share/xfce4/helpers/custom-MailReader.desktop
302
            return XDG;
303
        } else if (OSFamily.getInstance() instanceof Unix) {
304
            return XDG;
17 ilm 305
        }
306
 
307
        return MailTo;
308
    }
309
 
310
    public static final EmailClient MailTo = new EmailClient(null) {
311
        @Override
28 ilm 312
        public boolean composeNative(String to, String subject, String body, File... attachments) {
17 ilm 313
            return false;
314
        }
315
    };
316
 
149 ilm 317
    public static final EmailClient XDG = new EmailClient(EmailClientType.XDG) {
318
        @Override
319
        public boolean composeNative(String to, String subject, String body, File... attachments) throws IOException, InterruptedException {
320
            final ProcessBuilder pb = new ProcessBuilder("xdg-email");
321
            if (subject != null) {
322
                pb.command().add("--subject");
323
                pb.command().add(subject);
324
            }
325
            if (body != null) {
326
                pb.command().add("--body");
327
                pb.command().add(body);
328
            }
329
            for (File attachment : attachments) {
330
                pb.command().add("--attach");
331
                pb.command().add(attachment.getAbsolutePath());
332
            }
333
            pb.command().add(to);
334
            pb.inheritIO();
335
            final Process process = pb.start();
336
            process.getOutputStream().close();
337
            final int returnCode = process.waitFor();
338
            if (returnCode != 0)
339
                throw new IllegalStateException("Non zero return code: " + returnCode);
340
            return true;
341
        }
342
    };
343
 
17 ilm 344
    public static final EmailClient Outlook = new EmailClient(EmailClientType.Outlook) {
345
        @Override
28 ilm 346
        protected boolean composeNative(String to, String subject, String body, File... attachments) throws IOException, InterruptedException {
347
            final DesktopEnvironment de = DesktopEnvironment.getDE();
17 ilm 348
            final File vbs = FileUtils.getFile(EmailClient.class.getResource("OutlookEmail.vbs"));
349
            final List<String> l = new ArrayList<String>(6);
350
            l.add("cscript");
28 ilm 351
            l.add(de.quoteParamForExec(vbs.getAbsolutePath()));
17 ilm 352
            if (to != null)
353
                l.add(createVBParam("to", to));
354
            if (subject != null)
355
                l.add(createVBParam("subject", subject));
356
            // at least set a parameter otherwise the usage get displayed
357
            l.add(createVBParam("unicodeStdIn", "1"));
28 ilm 358
            for (File attachment : attachments) {
359
                l.add(de.quoteParamForExec(attachment.getAbsolutePath()));
360
            }
17 ilm 361
 
362
            final Process process = new ProcessBuilder(l).start();
363
            // VBScript only knows ASCII and UTF-16
28 ilm 364
            final Writer writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), StringUtils.UTF16));
17 ilm 365
            writer.write(body);
366
            writer.close();
367
            final int returnCode = process.waitFor();
368
            if (returnCode != 0)
369
                throw new IllegalStateException("Non zero return code: " + returnCode);
370
            return true;
371
        }
372
    };
373
 
374
    public static final EmailClient AppleMail = new EmailClient(EmailClientType.AppleMail) {
375
        @Override
28 ilm 376
        protected boolean composeNative(String to, String subject, String body, File... attachments) throws IOException, InterruptedException {
17 ilm 377
            final Process process = Runtime.getRuntime().exec(new String[] { "osascript" });
378
            final PrintStream w = new PrintStream(new BufferedOutputStream(process.getOutputStream()));
379
            // use ID to handle application renaming (always a slight delay after a rename for
380
            // this to work, though)
381
            w.println("tell application id \"" + AppleMailBundleID + "\"");
382
            w.println(" set theMessage to make new outgoing message with properties {" + getAppleMailParam(subject, body) + "}");
383
            if (to != null)
28 ilm 384
                w.println(" tell theMessage to make new to recipient with properties {address:" + StringUtils.doubleQuote(to) + "}");
385
            for (File attachment : attachments) {
386
                w.println(" tell content of theMessage to make new attachment with properties {file name:" + StringUtils.doubleQuote(attachment.getAbsolutePath()) + "} at after last paragraph");
17 ilm 387
            }
388
            w.println("end tell");
389
            w.close();
67 ilm 390
            if (w.checkError())
391
                throw new IOException();
17 ilm 392
 
393
            final int returnCode = process.waitFor();
394
            if (returnCode != 0)
395
                throw new IllegalStateException("Non zero return code: " + returnCode);
396
            return true;
397
        }
398
    };
399
 
400
    public static abstract class Thunderbird extends EmailClient {
401
 
402
        public static Thunderbird createFromExe(final File exe) {
83 ilm 403
            if (exe == null)
404
                throw new NullPointerException();
405
            if (!exe.isFile())
406
                return null;
17 ilm 407
            return new ThunderbirdPath(exe);
408
        }
409
 
410
        public static Thunderbird createFromCommandLine(final String cmdLine, final String toReplace) {
411
            return new ThunderbirdCommandLine(cmdLine, toReplace);
412
        }
413
 
414
        protected Thunderbird() {
415
            super(EmailClientType.Thunderbird);
416
        }
149 ilm 417
 
418
        @Override
419
        public String toString() {
420
            return this.getClass().getSimpleName();
421
        }
17 ilm 422
    }
423
 
424
    private static final class ThunderbirdCommandLine extends Thunderbird {
425
 
426
        private final String cmdLine;
427
        private final String toReplace;
428
 
429
        private ThunderbirdCommandLine(final String cmdLine, final String toReplace) {
430
            this.cmdLine = cmdLine;
431
            this.toReplace = toReplace;
432
        }
433
 
434
        @Override
28 ilm 435
        protected boolean composeNative(String to, String subject, String body, File... attachments) throws IOException {
436
            Runtime.getRuntime().exec(tbCommand(this.cmdLine, this.toReplace, to, subject, body, attachments));
17 ilm 437
            // don't wait for Thunderbird to quit if it wasn't launched
438
            // (BTW return code of 1 means the program was already launched)
439
            return true;
440
        }
149 ilm 441
 
442
        @Override
443
        public String toString() {
444
            return super.toString() + " " + this.cmdLine;
445
        }
17 ilm 446
    }
447
 
448
    private static final class ThunderbirdPath extends Thunderbird {
449
 
450
        private final File exe;
451
 
452
        private ThunderbirdPath(File exe) {
453
            this.exe = exe;
454
        }
455
 
456
        @Override
28 ilm 457
        protected boolean composeNative(String to, String subject, String body, File... attachments) throws IOException {
458
            final String composeArg = getTBParam(to, subject, body, attachments);
17 ilm 459
            Runtime.getRuntime().exec(new String[] { this.exe.getPath(), "-compose", composeArg });
460
            return true;
461
        }
149 ilm 462
 
463
        @Override
464
        public String toString() {
465
            return super.toString() + " " + this.exe;
466
        }
17 ilm 467
    }
468
 
469
    private final EmailClientType type;
470
 
471
    public EmailClient(EmailClientType type) {
472
        this.type = type;
473
    }
474
 
475
    public final EmailClientType getType() {
476
        return this.type;
477
    }
478
 
28 ilm 479
    protected abstract boolean composeNative(final String to, final String subject, final String body, final File... attachments) throws IOException, InterruptedException;
17 ilm 480
 
149 ilm 481
    @Override
482
    public String toString() {
483
        final EmailClientType t = this.getType();
484
        return t == null ? "mailto" : t.toString();
485
    }
486
 
17 ilm 487
    public final static void main(String[] args) throws Exception {
488
        if (args.length == 1 && "--help".equals(args[0])) {
489
            System.out.println("Usage: java [-Dparam=value] " + EmailClient.class.getName() + " [EmailClientType args]");
490
            System.out.println("\tEmailClientType: mailto or " + Arrays.asList(EmailClientType.values()));
28 ilm 491
            System.out.println("\tparam: to, subject, body, files (seprated by ',' double it to escape)");
17 ilm 492
            return;
493
        }
494
 
495
        final EmailClient client = createFromString(args);
149 ilm 496
        System.out.println("Using " + (args.length == 0 ? "preferred" : "passed") + " client : " + client);
28 ilm 497
        final String to = System.getProperty("to", "Pierre Dupond <p.dupond@example.com>, p.dupont@server.com");
498
        // ',to=' to test escaping of Thunderbird (passing subject='foo'bar' works)
499
        final String subject = System.getProperty("subject", "Sujé € du courrier ',to='&;\\<> \"autre'\n2nd line");
500
        final String body = System.getProperty("body", "Bonjour,\n\tsingle ' double \" backslash(arrière) \\ slash /");
501
        final String filesPath = System.getProperty("files");
502
        final String[] paths = filesPath == null || filesPath.length() == 0 ? new String[0] : filesPath.split("(?<!,),(?!,)");
503
        final File[] f = new File[paths.length];
504
        for (int i = 0; i < f.length; i++) {
505
            f[i] = new File(paths[i].replace(",,", ","));
506
        }
17 ilm 507
        client.compose(to, subject, body, f);
508
    }
509
 
510
    private static final EmailClient createFromString(final String... args) throws IOException {
511
        // switch doesn't support null
512
        if (args.length == 0)
513
            return getPreferred();
514
        else if ("mailto".equals(args[0]))
515
            return MailTo;
516
 
517
        final EmailClientType t = EmailClientType.valueOf(args[0]);
518
        switch (t) {
149 ilm 519
        case XDG:
520
            return XDG;
17 ilm 521
        case Outlook:
522
            return Outlook;
523
        case AppleMail:
524
            return AppleMail;
525
        case Thunderbird:
83 ilm 526
            EmailClient res = null;
527
            if (args.length == 2) {
528
                final File exe = new File(args[1]);
529
                res = Thunderbird.createFromExe(exe);
530
                if (res == null)
531
                    throw new IOException("Invalid exe : " + exe);
532
            } else if (args.length == 3) {
533
                res = Thunderbird.createFromCommandLine(args[1], args[2]);
534
            } else {
17 ilm 535
                throw new IllegalArgumentException(t + " needs 1 or 2 arguments");
83 ilm 536
            }
537
            return res;
17 ilm 538
        default:
539
            throw new IllegalStateException("Unknown type " + t);
540
        }
541
    }
542
}