New SAVE_TO option
[jvcard.git] / src / be / nikiroo / jvcard / launcher / Main.java
CommitLineData
7da41ecd
NR
1package be.nikiroo.jvcard.launcher;
2
3import java.io.File;
f06c8100 4import java.io.FileInputStream;
7da41ecd 5import java.io.IOException;
f06c8100 6import java.io.InputStream;
7da41ecd 7import java.lang.reflect.Field;
7da41ecd
NR
8import java.net.Socket;
9import java.nio.charset.Charset;
10import java.util.LinkedList;
11import java.util.List;
12
26d254a3
NR
13import javax.imageio.ImageIO;
14
7da41ecd 15import be.nikiroo.jvcard.Card;
26d254a3
NR
16import be.nikiroo.jvcard.Contact;
17import be.nikiroo.jvcard.Data;
18import be.nikiroo.jvcard.TypeInfo;
5ad0e17e 19import be.nikiroo.jvcard.launcher.CardResult.MergeCallback;
e643219c 20import be.nikiroo.jvcard.launcher.Optional.NotSupportedException;
7da41ecd 21import be.nikiroo.jvcard.parsers.Format;
845fb1d7 22import be.nikiroo.jvcard.remote.Command;
7da41ecd 23import be.nikiroo.jvcard.remote.SimpleSocket;
f06c8100
NR
24import be.nikiroo.jvcard.resources.DisplayBundle;
25import be.nikiroo.jvcard.resources.DisplayOption;
26import be.nikiroo.jvcard.resources.RemoteBundle;
27import be.nikiroo.jvcard.resources.StringId;
28import be.nikiroo.jvcard.resources.TransBundle;
29import be.nikiroo.utils.ImageUtils;
30import be.nikiroo.utils.StringUtils;
31import be.nikiroo.utils.Version;
32import be.nikiroo.utils.resources.Bundles;
7da41ecd
NR
33
34/**
35 * This class contains the runnable Main method. It will parse the user supplied
36 * parameters and take action based upon those. Most of the time, it will start
37 * a MainWindow.
38 *
39 * @author niki
f06c8100 40 *
7da41ecd
NR
41 */
42public class Main {
43 static public final String APPLICATION_TITLE = "jVcard";
7da41ecd
NR
44
45 static private final int ERR_NO_FILE = 1;
46 static private final int ERR_SYNTAX = 2;
47 static private final int ERR_INTERNAL = 3;
e119a1c1 48 static private TransBundle transService;
7da41ecd 49
30a4aa17
NR
50 static private String defaultFn;
51 static private boolean forceComputedFn;
52
26d254a3 53 enum Mode {
812124d1 54 CONTACT_MANAGER, I18N, SERVER, LOAD_PHOTO, SAVE_PHOTO, SAVE_CONFIG, HELP, SAVE_TO,
26d254a3
NR
55 }
56
7da41ecd 57 /**
9b8cb729 58 * Translate the given {@link StringId} into user text.
7da41ecd 59 *
5c5abfd2 60 * @param id
7da41ecd 61 * the ID to translate
9b8cb729
NR
62 * @param values
63 * the values to insert instead of the place holders in the
64 * translation
7da41ecd 65 *
9b8cb729 66 * @return the translated text with the given value where required
7da41ecd 67 */
e119a1c1 68 static public String trans(StringId id, Object... values) {
59597d59 69 return transService.getString(id, values);
7da41ecd
NR
70 }
71
72 /**
73 * Check if unicode characters should be used.
74 *
75 * @return TRUE to allow unicode
76 */
77 static public boolean isUnicode() {
78 return transService.isUnicode();
79 }
80
81 /**
82 * Start the application.
83 *
84 * <p>
85 * The returned exit codes are:
86 * <ul>
87 * <li>1: no files to open</li>
88 * <li>2: invalid syntax</li>
89 * <li>3: internal error</li>
90 * </ul>
91 * </p>
92 *
93 * @param args
94 * the parameters (see <tt>--help</tt> to know which are
95 * supported)
96 */
97 public static void main(String[] args) {
98 Boolean textMode = null;
99 boolean noMoreParams = false;
100 boolean filesTried = false;
101
102 // get the "system default" language to help translate the --help
103 // message if needed
104 String language = null;
e119a1c1 105 transService = new TransBundle(language);
7da41ecd
NR
106
107 boolean unicode = transService.isUnicode();
26d254a3 108 String dir = null;
7da41ecd 109 List<String> files = new LinkedList<String>();
26d254a3
NR
110 int port = -1;
111 Mode mode = Mode.CONTACT_MANAGER;
112 String format = null;
812124d1 113 String output = null;
7da41ecd
NR
114 for (int index = 0; index < args.length; index++) {
115 String arg = args[index];
116 if (!noMoreParams && arg.equals("--")) {
117 noMoreParams = true;
118 } else if (!noMoreParams && arg.equals("--help")) {
88eb8122
NR
119 if (mode != Mode.CONTACT_MANAGER) {
120 SERR(StringId.CLI_SERR_MODES);
121 return;
122 }
123 mode = Mode.HELP;
7da41ecd
NR
124 } else if (!noMoreParams && arg.equals("--tui")) {
125 textMode = true;
126 } else if (!noMoreParams && arg.equals("--gui")) {
127 textMode = false;
128 } else if (!noMoreParams && arg.equals("--noutf")) {
129 unicode = false;
130 transService.setUnicode(unicode);
131 } else if (!noMoreParams && arg.equals("--lang")) {
132 index++;
133 if (index >= args.length) {
88eb8122 134 SERR(StringId.CLI_SERR_NOLANG);
7da41ecd
NR
135 return;
136 }
137
138 language = args[index];
e119a1c1 139 transService = new TransBundle(language);
7da41ecd
NR
140 transService.setUnicode(unicode);
141 } else if (!noMoreParams && arg.equals("--config")) {
142 index++;
143 if (index >= args.length) {
88eb8122 144 SERR(StringId.CLI_SERR_NODIR);
7da41ecd
NR
145 return;
146 }
147
148 Bundles.setDirectory(args[index]);
e119a1c1 149 transService = new TransBundle(language);
7da41ecd 150 transService.setUnicode(unicode);
e119a1c1
NR
151 } else if (!noMoreParams && arg.equals("--save-config")) {
152 index++;
153 if (index >= args.length) {
88eb8122 154 SERR(StringId.CLI_SERR_NODIR);
e119a1c1
NR
155 return;
156 }
157 dir = args[index];
158
159 if (mode != Mode.CONTACT_MANAGER) {
88eb8122 160 SERR(StringId.CLI_SERR_MODES);
e119a1c1
NR
161 return;
162 }
163 mode = Mode.SAVE_CONFIG;
7da41ecd 164 } else if (!noMoreParams && arg.equals("--server")) {
26d254a3 165 if (mode != Mode.CONTACT_MANAGER) {
88eb8122 166 SERR(StringId.CLI_SERR_MODES);
26d254a3
NR
167 return;
168 }
169 mode = Mode.SERVER;
170
7da41ecd
NR
171 index++;
172 if (index >= args.length) {
88eb8122 173 SERR(StringId.CLI_SERR_NOPORT);
7da41ecd
NR
174 return;
175 }
176
177 try {
178 port = Integer.parseInt(args[index]);
179 } catch (NumberFormatException e) {
88eb8122 180 SERR(StringId.CLI_SERR_BADPORT, "" + args[index]);
7da41ecd
NR
181 return;
182 }
183 } else if (!noMoreParams && arg.equals("--i18n")) {
26d254a3 184 if (mode != Mode.CONTACT_MANAGER) {
88eb8122 185 SERR(StringId.CLI_SERR_MODES);
26d254a3
NR
186 return;
187 }
188 mode = Mode.I18N;
189
7da41ecd
NR
190 index++;
191 if (index >= args.length) {
88eb8122 192 SERR(StringId.CLI_SERR_NODIR);
7da41ecd
NR
193 return;
194 }
9b8cb729 195
26d254a3
NR
196 dir = args[index];
197 } else if (!noMoreParams
198 && (arg.equals("--load-photo")
199 || arg.equals("--save-photo") || arg
200 .equals("--only-photo"))) {
201 if (mode != Mode.CONTACT_MANAGER) {
88eb8122 202 SERR(StringId.CLI_SERR_MODES);
26d254a3
NR
203 return;
204 }
205
206 if (arg.equals("--load-photo")) {
207 mode = Mode.LOAD_PHOTO;
208 } else if (arg.equals("--save-photo")) {
209 mode = Mode.SAVE_PHOTO;
26d254a3
NR
210 }
211
212 index++;
213 if (index >= args.length) {
88eb8122 214 SERR(StringId.CLI_SERR_NODIR);
26d254a3
NR
215 return;
216 }
217
218 dir = args[index];
219
220 index++;
221 if (index >= args.length) {
88eb8122 222 SERR(StringId.CLI_SERR_NOFORMAT);
26d254a3
NR
223 return;
224 }
225
226 format = args[index];
812124d1
NR
227 } else if (!noMoreParams && (arg.equals("--save-to"))) {
228 if (mode != Mode.CONTACT_MANAGER) {
229 SERR(StringId.CLI_SERR_MODES);
230 return;
231 }
232 mode = Mode.SAVE_TO;
233
234 index++;
235 if (index >= args.length) {
236 SERR(StringId.CLI_ERR_NOFILES);
237 return;
238 }
239
240 output = args[index];
7da41ecd
NR
241 } else {
242 filesTried = true;
243 files.addAll(open(arg));
244 }
245 }
9b8cb729 246
f578f3af 247 // Force headless mode if we run in forced-text mode
26d254a3 248 if (mode != Mode.CONTACT_MANAGER || (textMode != null && textMode)) {
f578f3af
NR
249 // same as -Djava.awt.headless=true
250 System.setProperty("java.awt.headless", "true");
251 }
7da41ecd
NR
252
253 if (unicode) {
254 utf8();
255 }
256
30a4aa17
NR
257 // N/FN fix information:
258 readNFN();
259
7da41ecd 260 // Error management:
26d254a3 261 if (mode == Mode.SERVER && files.size() > 0) {
88eb8122
NR
262 SERR(StringId.CLI_SERR_NOLANG, "--server");
263 return;
26d254a3 264 } else if (mode == Mode.I18N && files.size() > 0) {
88eb8122
NR
265 SERR(StringId.CLI_SERR_NOLANG, "--i18n");
266 return;
26d254a3 267 } else if (mode == Mode.I18N && language == null) {
88eb8122 268 SERR(StringId.CLI_SERR_NOLANG);
26d254a3
NR
269 } else if ((mode == Mode.CONTACT_MANAGER || mode == Mode.SAVE_PHOTO || mode == Mode.LOAD_PHOTO)
270 && files.size() == 0) {
7da41ecd
NR
271 if (files.size() == 0 && !filesTried) {
272 files.addAll(open("."));
273 }
274
275 if (files.size() == 0) {
88eb8122 276 ERR(StringId.CLI_ERR, StringId.CLI_ERR_NOFILES, ERR_NO_FILE);
7da41ecd
NR
277 return;
278 }
279 }
280 //
281
26d254a3 282 switch (mode) {
e119a1c1
NR
283 case SAVE_CONFIG: {
284 try {
285 if (!new File(dir).isDirectory()) {
286 if (!new File(dir).mkdir()) {
88eb8122
NR
287 System.err.println(trans(
288 StringId.CLI_ERR_CANNOT_CREATE_CONFDIR, dir));
e119a1c1
NR
289 }
290 }
291
e27d1404 292 new TransBundle().updateFile(dir); // default locale
f06c8100 293 for (String lang : new TransBundle().getKnownLanguages()) {
e27d1404
NR
294 new TransBundle(lang).updateFile(dir);
295 }
296
f06c8100 297 // new UIColors().updateFile(dir);
e119a1c1
NR
298 new DisplayBundle().updateFile(dir);
299 new RemoteBundle().updateFile(dir);
300 } catch (IOException e) {
301 e.printStackTrace();
59597d59 302 System.err.flush();
e119a1c1
NR
303 System.exit(ERR_INTERNAL);
304 }
305 break;
306 }
26d254a3 307 case SERVER: {
7da41ecd 308 try {
02b341aa 309 Optional.runServer(port);
e643219c
NR
310 } catch (IOException e) {
311 ERR(StringId.CLI_ERR, StringId.CLI_ERR_CANNOT_START,
312 ERR_INTERNAL);
313 return;
314 } catch (NotSupportedException e) {
315 if (!e.isCompiledIn()) {
88eb8122
NR
316 ERR(StringId.CLI_ERR, StringId.CLI_ERR_NO_REMOTING,
317 ERR_INTERNAL);
318 return;
7da41ecd 319 }
d5260eeb
NR
320 e.printStackTrace();
321 ERR(StringId.CLI_ERR, StringId.CLI_ERR, ERR_INTERNAL);
322 return;
7da41ecd 323 }
26d254a3
NR
324 break;
325 }
326 case I18N: {
7da41ecd 327 try {
e119a1c1 328 transService.updateFile(dir);
7da41ecd 329 } catch (IOException e) {
d459d7e1
NR
330 ERR(StringId.CLI_ERR, StringId.CLI_ERR_CANNOT_CREATE_LANG,
331 ERR_INTERNAL);
332 return;
7da41ecd 333 }
26d254a3
NR
334 break;
335 }
26d254a3
NR
336 case LOAD_PHOTO: {
337 for (String file : files) {
338 try {
339 Card card = getCard(file, null).getCard();
340 for (Contact contact : card) {
341 String filename = contact.toString(format, "");
f29274a7 342 File f = new File(dir, filename);
26d254a3
NR
343
344 if (f.exists()) {
e3fe9834 345 System.out.println("Loading " + f);
26d254a3 346 try {
a1783d00
NR
347 String type = "jpeg";
348 int dotIndex = filename.indexOf('.');
349 if (dotIndex >= 0
350 && (dotIndex + 1) < filename.length()) {
351 type = filename.substring(dotIndex + 1)
352 .toLowerCase();
353 }
354
f06c8100
NR
355 String b64;
356 InputStream in = null;
357 try {
358 in = new FileInputStream(f);
359 b64 = ImageUtils.toBase64(in);
360 } finally {
361 if (in != null) {
362 in.close();
363 }
364 }
26d254a3 365
88eb8122
NR
366 // remove previous photos:
367 for (Data photo = contact
368 .getPreferredData("PHOTO"); photo != null; photo = contact
369 .getPreferredData("PHOTO")) {
370 photo.delete();
26d254a3 371 }
88eb8122 372 //
26d254a3
NR
373
374 List<TypeInfo> types = new LinkedList<TypeInfo>();
375 types.add(new TypeInfo("ENCODING", "b"));
a1783d00 376 types.add(new TypeInfo("TYPE", type));
26d254a3
NR
377 Data photo = new Data(types, "PHOTO", b64, null);
378 contact.add(photo);
379 } catch (IOException e) {
380 System.err.println("Cannot read photo: "
381 + filename);
382 }
383 }
384 }
385 card.save();
386 } catch (IOException e) {
88eb8122
NR
387 System.err
388 .println(trans(StringId.CLI_ERR_CANNOT_OPEN, file));
26d254a3
NR
389 }
390 }
391 break;
392 }
393 case SAVE_PHOTO: {
394 for (String file : files) {
395 try {
396 Card card = getCard(file, null).getCard();
397 for (Contact contact : card) {
398 Data photo = contact.getPreferredData("PHOTO");
399 if (photo != null) {
400 String filename = contact.toString(format, "");
401 File f = new File(dir, filename + ".png");
e3fe9834 402 System.out.println("Saving " + f);
26d254a3
NR
403 try {
404 ImageIO.write(
f06c8100 405 ImageUtils.fromBase64(photo.getValue()),
26d254a3
NR
406 "png", f);
407 } catch (IOException e) {
88eb8122
NR
408 System.err.println(trans(
409 StringId.CLI_ERR_CANNOT_SAVE_PHOTO,
410 contact.getPreferredDataValue("FN")));
26d254a3
NR
411 }
412 }
413 }
414 } catch (IOException e) {
88eb8122
NR
415 System.err
416 .println(trans(StringId.CLI_ERR_CANNOT_OPEN, file));
26d254a3
NR
417 }
418 }
419 break;
420 }
421 case CONTACT_MANAGER: {
7da41ecd 422 try {
02b341aa 423 Optional.startTui(textMode, files);
e643219c
NR
424 } catch (IOException e) {
425 ERR(StringId.CLI_ERR, StringId.CLI_ERR_CANNOT_START,
426 ERR_NO_FILE);
427 return;
428 } catch (NotSupportedException e) {
429 if (!e.isCompiledIn()) {
88eb8122
NR
430 ERR(StringId.CLI_ERR, StringId.CLI_ERR_NO_TUI, ERR_INTERNAL);
431 return;
7da41ecd 432 }
d5260eeb
NR
433 e.printStackTrace();
434 ERR(StringId.CLI_ERR, StringId.CLI_ERR, ERR_INTERNAL);
435 return;
7da41ecd 436 }
26d254a3
NR
437 break;
438 }
812124d1
NR
439 case SAVE_TO: {
440 try {
441 Card total = new Card(null, getCardFormat(output));
442
443 for (String file : files) {
444 try {
445 Card card = getCard(file, null).getCard();
446 card.unlink();
447 while (card.size() > 0) {
448 total.add(card.remove(0));
449 }
450 } catch (IOException e) {
451 System.err.println(trans(StringId.CLI_ERR_CANNOT_OPEN,
452 file));
453 }
454 }
455
456 total.saveAs(new File(output), getCardFormat(output));
457 } catch (IOException e) {
458 System.err.println(trans(StringId.CLI_ERR_CANNOT_OPEN, output));
459 }
460
461 break;
462 }
88eb8122 463 case HELP: {
f06c8100
NR
464 System.out.println(APPLICATION_TITLE + " "
465 + Version.getCurrentVersion());
88eb8122
NR
466 System.out.println();
467
468 System.out.println(trans(StringId.CLI_HELP));
469 System.out.println();
470
471 System.out.println(trans(StringId.CLI_HELP_MODES));
472 System.out.println("\t--help : "
473 + trans(StringId.CLI_HELP_MODE_HELP));
474 System.out.println("\t(--tui|--gui) (--noutf) ... : "
475 + trans(StringId.CLI_HELP_MODE_CONTACT_MANAGER));
476 System.out.println("\t--server PORT ... : "
477 + trans(StringId.CLI_HELP_MODE_SERVER));
478 System.out.println("\t--save-config DIR : "
479 + trans(StringId.CLI_HELP_MODE_SAVE_CONFIG));
480 System.out.println("\t--i18n DIR ---lang LANG : "
481 + trans(StringId.CLI_HELP_MODE_I18N));
482 System.out.println("\t--load-photo DIR FORMAT ... : "
483 + trans(StringId.CLI_HELP_MODE_LOAD_PHOTO));
484 System.out.println("\t--save-photo DIR FORMAT ... : "
485 + trans(StringId.CLI_HELP_MODE_SAVE_PHOTO));
812124d1
NR
486 System.out.println("\t--save-to output(.vcf) ... : "
487 + trans(StringId.CLI_HELP_MODE_SAVE_TO));
88eb8122
NR
488 System.out.println();
489
490 System.out.println(trans(StringId.CLI_HELP_OPTIONS));
491 System.out.println("\t-- : " + trans(StringId.CLI_HELP_DD));
492 System.out.println("\t--lang LANG : "
493 + trans(StringId.CLI_HELP_LANG));
494 System.out.println("\t--tui : " + trans(StringId.CLI_HELP_TUI));
495 System.out.println("\t--gui : " + trans(StringId.CLI_HELP_GUI));
99f631de
NR
496 System.out.println("\t--noutf : "
497 + trans(StringId.CLI_HELP_NOUTF_OPTION));
88eb8122
NR
498 System.out.println("\t--config : "
499 + trans(StringId.CLI_HELP_CONFIG));
500 System.out.println();
501
502 System.out.println(trans(StringId.CLI_HELP_FOOTER));
503 System.out.println();
504
812124d1 505 break;
88eb8122 506 }
7da41ecd
NR
507 }
508 }
509
510 /**
511 * Return the {@link Card} corresponding to the given resource name -- a
30a4aa17
NR
512 * file or a remote jvcard URL.
513 *
514 * <p>
515 * Will also fix the FN if required (see display.properties).
516 * </p>
7da41ecd
NR
517 *
518 * @param input
519 * a filename or a remote jvcard url with named resource (e.g.:
520 * <tt>jvcard://localhost:4444/coworkers.vcf</tt>)
5ad0e17e
NR
521 * @param callback
522 * the {@link MergeCallback} to call in case of conflict, or NULL
523 * to disallow conflict management (the {@link Card} will not be
524 * allowed to synchronise in case of conflicts)
7da41ecd
NR
525 *
526 * @return the {@link Card}
527 *
528 * @throws IOException
529 * in case of IO error or remoting not available
530 */
5ad0e17e
NR
531 static public CardResult getCard(String input, MergeCallback callback)
532 throws IOException {
812124d1
NR
533 boolean remote = isFileRemote(input);
534 Format format = getCardFormat(input);
7da41ecd 535
5ad0e17e 536 CardResult card = null;
7da41ecd
NR
537 try {
538 if (remote) {
5ad0e17e 539 card = Optional.syncCard(input, callback);
7da41ecd 540 } else {
5ad0e17e
NR
541 card = new CardResult(new Card(new File(input), format), false,
542 false, false);
7da41ecd
NR
543 }
544 } catch (IOException ioe) {
545 throw ioe;
e643219c 546 } catch (NotSupportedException e) {
4298276a 547 throw new IOException("Remoting support not available", e);
7da41ecd
NR
548 }
549
30a4aa17
NR
550 // Fix the FN value
551 if (defaultFn != null) {
552 try {
553 for (Contact contact : card.getCard()) {
554 Data name = contact.getPreferredData("FN");
812124d1
NR
555 Data n = contact.getPreferredData("N");
556 boolean hasN = n != null && n.getValue().length() > 0;
30a4aa17 557 if (name == null || name.getValue().length() == 0
812124d1 558 || (forceComputedFn && hasN)) {
99f631de 559 name.setValue(contact.toString(defaultFn, "").trim());
30a4aa17
NR
560 }
561 }
562 } catch (Exception e) {
563 // sync failed -> getCard() throws.
564 // do not update.
565 }
566 }
567
7da41ecd
NR
568 return card;
569 }
570
812124d1
NR
571 static private boolean isFileRemote(String input) {
572 return input.contains("://");
573 }
574
575 static Format getCardFormat(String input) {
576 if (isFileRemote(input)) {
577 return Format.VCard21;
578 }
579
580 Format format = Format.Abook;
581 String ext = input;
582 if (ext.contains(".")) {
583 String tab[] = ext.split("\\.");
584 if (tab.length > 1 && tab[tab.length - 1].equalsIgnoreCase("vcf")) {
585 format = Format.VCard21;
586 }
587 }
588
589 return format;
590 }
591
7da41ecd
NR
592 /**
593 * Open the given path and add all its files if it is a directory or just
594 * this one if not to the returned list.
595 *
596 * @param path
597 * the path to open
598 *
599 * @return the list of opened files
600 */
601 static private List<String> open(String path) {
602 List<String> files = new LinkedList<String>();
603
604 if (path != null && path.startsWith("jvcard://")) {
605 if (path.endsWith("/")) {
606 files.addAll(list(path));
607 } else {
608 files.add(path);
609 }
610 } else {
611 File file = new File(path);
612 if (file.exists()) {
613 if (file.isDirectory()) {
614 for (File subfile : file.listFiles()) {
615 if (!subfile.isDirectory())
616 files.add(subfile.getAbsolutePath());
617 }
618 } else {
619 files.add(file.getAbsolutePath());
620 }
621 } else {
622 System.err.println("File or directory not found: \"" + path
623 + "\"");
624 }
625 }
626
627 return files;
628 }
629
630 /**
631 * List all the available {@link Card}s on the given network location (which
632 * is expected to be a jVCard remote server, obviously).
633 *
634 * @param path
635 * the jVCard remote server path (e.g.:
636 * <tt>jvcard://localhost:4444/</tt>)
637 *
638 * @return the list of {@link Card}s
639 */
640 static private List<String> list(String path) {
641 List<String> files = new LinkedList<String>();
642
643 try {
644 String host = path.split("\\:")[1].substring(2);
645 int port = Integer.parseInt(path.split("\\:")[2].replaceAll("/$",
646 ""));
647 SimpleSocket s = new SimpleSocket(new Socket(host, port),
648 "sync client");
649 s.open(true);
650
845fb1d7 651 s.sendCommand(Command.LIST_CARD);
7da41ecd
NR
652 for (String p : s.receiveBlock()) {
653 files.add(path
654 + p.substring(StringUtils.fromTime(0).length() + 1));
655 }
656 s.close();
657 } catch (Exception e) {
658 e.printStackTrace();
659 }
660
661 return files;
662 }
663
664 /**
665 * Really, really ask for UTF-8 encoding.
666 */
667 static private void utf8() {
668 try {
669 System.setProperty("file.encoding", "UTF-8");
670 Field charset = Charset.class.getDeclaredField("defaultCharset");
671 charset.setAccessible(true);
672 charset.set(null, null);
673 } catch (SecurityException e) {
674 } catch (NoSuchFieldException e) {
675 } catch (IllegalArgumentException e) {
676 } catch (IllegalAccessException e) {
677 }
678 }
30a4aa17
NR
679
680 /**
681 * Read display.properties to know if we should fix the FN field when empty,
682 * or always, or never.
683 */
684 static private void readNFN() {
e119a1c1 685 DisplayBundle map = new DisplayBundle();
30a4aa17 686
e119a1c1
NR
687 defaultFn = map.getString(DisplayOption.CONTACT_DETAILS_DEFAULT_FN);
688
689 forceComputedFn = map.getBoolean(
690 DisplayOption.CONTACT_DETAILS_SHOW_COMPUTED_FN, false);
30a4aa17 691 }
88eb8122
NR
692
693 /**
694 * Syntax error detected, closing the application with an error message.
695 *
696 * @param err
697 * the syntax error case
698 */
699 static private void SERR(StringId err, Object... values) {
700 ERR(StringId.CLI_SERR, err, ERR_SYNTAX, values);
701 }
702
703 /**
704 * Error detected, closing the application with an error message.
705 *
706 * @param err
707 * the error case
708 * @param suberr
709 * the suberror or NULL if none
710 * @param CODE
711 * the error code as declared above
712 */
713 static private void ERR(StringId err, StringId suberr, int CODE,
714 Object... subvalues) {
715 if (suberr == null)
716 System.err.println(trans(err));
717 else
718 System.err.println(trans(err, trans(suberr, subvalues)));
719
59597d59 720 System.err.flush();
88eb8122
NR
721 System.exit(CODE);
722 }
7da41ecd 723}