1 package be
.nikiroo
.jvcard
.launcher
;
4 import java
.io
.IOException
;
5 import java
.lang
.reflect
.Field
;
6 import java
.net
.Socket
;
7 import java
.nio
.charset
.Charset
;
8 import java
.util
.LinkedList
;
11 import be
.nikiroo
.jvcard
.Card
;
12 import be
.nikiroo
.jvcard
.launcher
.CardResult
.MergeCallback
;
13 import be
.nikiroo
.jvcard
.parsers
.Format
;
14 import be
.nikiroo
.jvcard
.remote
.Command
;
15 import be
.nikiroo
.jvcard
.remote
.SimpleSocket
;
16 import be
.nikiroo
.jvcard
.resources
.Bundles
;
17 import be
.nikiroo
.jvcard
.resources
.StringUtils
;
18 import be
.nikiroo
.jvcard
.resources
.Trans
;
19 import be
.nikiroo
.jvcard
.resources
.Trans
.StringId
;
22 * This class contains the runnable Main method. It will parse the user supplied
23 * parameters and take action based upon those. Most of the time, it will start
30 static public final String APPLICATION_TITLE
= "jVcard";
31 static public final String APPLICATION_VERSION
= "1.0-beta3-dev";
33 static private final int ERR_NO_FILE
= 1;
34 static private final int ERR_SYNTAX
= 2;
35 static private final int ERR_INTERNAL
= 3;
36 static private Trans transService
;
39 * Translate the given {@link StringId} into user text.
44 * the values to insert instead of the place holders in the
47 * @return the translated text with the given value where required
49 static public String
trans(StringId id
, String
... values
) {
50 return transService
.trans(id
, (String
[]) values
);
54 * Check if unicode characters should be used.
56 * @return TRUE to allow unicode
58 static public boolean isUnicode() {
59 return transService
.isUnicode();
63 * Start the application.
66 * The returned exit codes are:
68 * <li>1: no files to open</li>
69 * <li>2: invalid syntax</li>
70 * <li>3: internal error</li>
75 * the parameters (see <tt>--help</tt> to know which are
78 public static void main(String
[] args
) {
79 Boolean textMode
= null;
80 boolean noMoreParams
= false;
81 boolean filesTried
= false;
83 // get the "system default" language to help translate the --help
85 String language
= null;
86 transService
= new Trans(language
);
88 boolean unicode
= transService
.isUnicode();
89 String i18nDir
= null;
90 List
<String
> files
= new LinkedList
<String
>();
92 for (int index
= 0; index
< args
.length
; index
++) {
93 String arg
= args
[index
];
94 if (!noMoreParams
&& arg
.equals("--")) {
96 } else if (!noMoreParams
&& arg
.equals("--help")) {
98 .println("TODO: implement some help text.\n"
99 + "Usable switches:\n"
100 + "\t--: stop looking for switches\n"
101 + "\t--help: this here thingy\n"
102 + "\t--lang LANGUAGE: choose the language, for instance en_GB\n"
103 + "\t--tui: force pure text mode even if swing treminal is available\n"
104 + "\t--gui: force swing terminal mode\n"
105 + "\t--noutf: force non-utf8 mode if you need it\n"
106 + "\t--config DIRECTORY: force the given directory as a CONFIG_DIR\n"
107 + "\t--server PORT: start a remoting server instead of a client\n"
108 + "\t--i18n DIR: generate the translation file for the given language (can be \"\") to/from the .properties given dir\n"
109 + "everyhing else is either a file to open or a directory to open\n"
110 + "(we will only open 1st level files in given directories)\n"
111 + "('jvcard://hostname:8888/file' links -- or without 'file' -- are also ok)\n");
113 } else if (!noMoreParams
&& arg
.equals("--tui")) {
115 } else if (!noMoreParams
&& arg
.equals("--gui")) {
117 } else if (!noMoreParams
&& arg
.equals("--noutf")) {
119 transService
.setUnicode(unicode
);
120 } else if (!noMoreParams
&& arg
.equals("--lang")) {
122 if (index
>= args
.length
) {
123 System
.err
.println("Syntax error: no language given");
124 System
.exit(ERR_SYNTAX
);
128 language
= args
[index
];
129 transService
= new Trans(language
);
130 transService
.setUnicode(unicode
);
131 } else if (!noMoreParams
&& arg
.equals("--config")) {
133 if (index
>= args
.length
) {
135 .println("Syntax error: no config directory given");
136 System
.exit(ERR_SYNTAX
);
140 Bundles
.setDirectory(args
[index
]);
141 transService
= new Trans(language
);
142 transService
.setUnicode(unicode
);
143 } else if (!noMoreParams
&& arg
.equals("--server")) {
145 if (index
>= args
.length
) {
146 System
.err
.println("Syntax error: no port given");
147 System
.exit(ERR_SYNTAX
);
152 port
= Integer
.parseInt(args
[index
]);
153 } catch (NumberFormatException e
) {
154 System
.err
.println("Invalid port number: " + args
[index
]);
155 System
.exit(ERR_SYNTAX
);
158 } else if (!noMoreParams
&& arg
.equals("--i18n")) {
160 if (index
>= args
.length
) {
162 .println("Syntax error: no .properties directory given");
163 System
.exit(ERR_SYNTAX
);
167 i18nDir
= args
[index
];
170 files
.addAll(open(arg
));
174 // Force headless mode if we run in forced-text mode
175 if (textMode
!= null && textMode
) {
176 // same as -Djava.awt.headless=true
177 System
.setProperty("java.awt.headless", "true");
185 if (port
!= null && files
.size() > 0) {
187 .println("Invalid syntax: you cannot both use --server and provide card files");
188 System
.exit(ERR_SYNTAX
);
189 } else if (i18nDir
!= null && files
.size() > 0) {
191 .println("Invalid syntax: you cannot both use --i18n and provide card files");
192 System
.exit(ERR_SYNTAX
);
193 } else if (port
!= null && i18nDir
!= null) {
195 .println("Invalid syntax: you cannot both use --server and --i18n");
196 System
.exit(ERR_SYNTAX
);
197 } else if (i18nDir
!= null && language
== null) {
199 .println("Invalid syntax: you cannot use --i18n without --lang");
200 System
.exit(ERR_SYNTAX
);
201 } else if (port
== null && i18nDir
== null && files
.size() == 0) {
202 if (files
.size() == 0 && !filesTried
) {
203 files
.addAll(open("."));
206 if (files
.size() == 0) {
207 System
.err
.println("No files to open");
208 System
.exit(ERR_NO_FILE
);
216 Optional
.runServer(port
);
217 } catch (Exception e
) {
218 if (e
instanceof IOException
) {
220 .println("I/O Exception: Cannot start the server");
222 System
.err
.println("Remoting support not available");
223 System
.exit(ERR_INTERNAL
);
226 } else if (i18nDir
!= null) {
228 Trans
.generateTranslationFile(i18nDir
, language
);
229 } catch (IOException e
) {
231 .println("I/O Exception: Cannot create/update a language in directory: "
236 Optional
.startTui(textMode
, files
);
237 } catch (Exception e
) {
238 if (e
instanceof IOException
) {
240 .println("I/O Exception: Cannot start the program with the given cards");
242 System
.err
.println("TUI support not available");
243 System
.exit(ERR_INTERNAL
);
250 * Return the {@link Card} corresponding to the given resource name -- a
251 * file or a remote jvcard URL
254 * a filename or a remote jvcard url with named resource (e.g.:
255 * <tt>jvcard://localhost:4444/coworkers.vcf</tt>)
257 * the {@link MergeCallback} to call in case of conflict, or NULL
258 * to disallow conflict management (the {@link Card} will not be
259 * allowed to synchronise in case of conflicts)
261 * @return the {@link Card}
263 * @throws IOException
264 * in case of IO error or remoting not available
266 static public CardResult
getCard(String input
, MergeCallback callback
)
268 boolean remote
= false;
269 Format format
= Format
.Abook
;
271 if (ext
.contains(".")) {
272 String tab
[] = ext
.split("\\.");
273 if (tab
.length
> 1 && tab
[tab
.length
- 1].equalsIgnoreCase("vcf")) {
274 format
= Format
.VCard21
;
278 if (input
.contains("://")) {
279 format
= Format
.VCard21
;
283 CardResult card
= null;
286 card
= Optional
.syncCard(input
, callback
);
288 card
= new CardResult(new Card(new File(input
), format
), false,
291 } catch (IOException ioe
) {
293 } catch (Exception e
) {
294 throw new IOException("Remoting support not available", e
);
301 * Open the given path and add all its files if it is a directory or just
302 * this one if not to the returned list.
307 * @return the list of opened files
309 static private List
<String
> open(String path
) {
310 List
<String
> files
= new LinkedList
<String
>();
312 if (path
!= null && path
.startsWith("jvcard://")) {
313 if (path
.endsWith("/")) {
314 files
.addAll(list(path
));
319 File file
= new File(path
);
321 if (file
.isDirectory()) {
322 for (File subfile
: file
.listFiles()) {
323 if (!subfile
.isDirectory())
324 files
.add(subfile
.getAbsolutePath());
327 files
.add(file
.getAbsolutePath());
330 System
.err
.println("File or directory not found: \"" + path
339 * List all the available {@link Card}s on the given network location (which
340 * is expected to be a jVCard remote server, obviously).
343 * the jVCard remote server path (e.g.:
344 * <tt>jvcard://localhost:4444/</tt>)
346 * @return the list of {@link Card}s
348 static private List
<String
> list(String path
) {
349 List
<String
> files
= new LinkedList
<String
>();
352 String host
= path
.split("\\:")[1].substring(2);
353 int port
= Integer
.parseInt(path
.split("\\:")[2].replaceAll("/$",
355 SimpleSocket s
= new SimpleSocket(new Socket(host
, port
),
359 s
.sendCommand(Command
.LIST_CARD
);
360 for (String p
: s
.receiveBlock()) {
362 + p
.substring(StringUtils
.fromTime(0).length() + 1));
365 } catch (Exception e
) {
373 * Really, really ask for UTF-8 encoding.
375 static private void utf8() {
377 System
.setProperty("file.encoding", "UTF-8");
378 Field charset
= Charset
.class.getDeclaredField("defaultCharset");
379 charset
.setAccessible(true);
380 charset
.set(null, null);
381 } catch (SecurityException e
) {
382 } catch (NoSuchFieldException e
) {
383 } catch (IllegalArgumentException e
) {
384 } catch (IllegalAccessException e
) {