/[winpt]/trunk/Src/wptRegistry.cpp
ViewVC logotype

Contents of /trunk/Src/wptRegistry.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 409 - (show annotations)
Mon Feb 6 19:39:00 2012 UTC (13 years ago) by twoaday
File size: 17123 byte(s)
2012-02-06  Timo Schulz  <twoaday@gmx.net>

       * wptGPG.cpp (check_keyring): Improved error checking.
       * wptFileManager.cpp: Removed obsolete code.
		

1 /* wptRegistry.cpp - Windows Registry access
2 * Copyright (C) 2000-2006 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19
20 #include <windows.h>
21 #include <stdio.h>
22
23 #include "wptErrors.h"
24 #include "wptW32API.h"
25 #include "wptGPG.h"
26 #include "wptRegistry.h"
27 #include "wptKeyserver.h"
28 #include "wptTypes.h"
29 #include "wptNLS.h"
30 #include "wptVersion.h"
31 #include "wptHotkey.h"
32
33 #define rc_ok(rc) ((rc) == ERROR_SUCCESS)
34
35 /* WinPT registry path. */
36 #define WINPT_REG "Software\\WinPT"
37
38 /* GPG registry path. */
39 #define GPG_REG "Software\\GNU\\GnuPG"
40
41 #define GPG_MO_REG "Control Panel\\MingW32\\NLS"
42
43 /* GPG file association context. */
44 struct gpg_filetype_s {
45 const char *descr; /* description. */
46 const char *ext; /* extension. */
47 int nicon; /* number of the image icon. */
48 };
49 typedef struct gpg_filetype_s *gpg_filetype_t;
50
51 /* Global WinPT registry prefereneces. */
52 struct winpt_prefs_s reg_prefs;
53
54 /* All valid configuration commands. */
55 const char *cfg [] = {
56 NULL,
57 "CacheTime",
58 "WordWrap",
59 "DefaultExt",
60 "Viewer",
61 "AlwaysTrust",
62 "AutoBackup",
63 "BackupMode",
64 "DisableHotkeys",
65 "NoCompressMultiMedia",
66 "Expert",
67 "FMProgressBar",
68 "BackupSecring"
69 };
70
71 /* Return != 0 if GPG4win is installed. */
72 int
73 is_gpg4win_installed (void)
74 {
75 char *p;
76
77 p = get_reg_entry_gpg4win (NULL);
78 if (!p)
79 return 0;
80 if (dir_exist_check (p)) {
81 free_if_alloc (p);
82 return 0;
83 }
84 free_if_alloc (p);
85 return -1;
86 }
87
88
89 /* Return != 0 if GPGee is installed. */
90 static int
91 is_gpgee_installed (void)
92 {
93 HKEY hk;
94 LONG ec;
95
96 ec = RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\GPGee", 0, KEY_READ, &hk);
97 if (ec == ERROR_SUCCESS) {
98 RegCloseKey (hk);
99 return -1;
100 }
101
102 return 0;
103 }
104
105
106 /* Free all members in the registry preference struct. */
107 void
108 free_reg_prefs (void)
109 {
110 free_if_alloc (reg_prefs.backup.path);
111 free_if_alloc (reg_prefs.kserv_conf);
112 free_if_alloc (reg_prefs.homedir);
113 memset (&reg_prefs, 0, sizeof (reg_prefs));
114 }
115
116
117
118 /* Install the GPG related into the W32 resgistry, if the entry already
119 exists the function returns immediately. */
120 int
121 regist_inst_gnupg (int create_mokey)
122 {
123 int rc;
124 HKEY reg;
125
126 rc = RegOpenKeyEx (HKEY_CURRENT_USER, GPG_REG, 0, KEY_READ, &reg);
127 if (rc == ERROR_SUCCESS) {
128 RegCloseKey (reg);
129 return 0;
130 }
131 rc = RegCreateKey (HKEY_CURRENT_USER, GPG_REG, &reg);
132 if (rc != ERROR_SUCCESS)
133 return WPTERR_REGISTRY;
134 RegCloseKey (reg);
135
136 if (!create_mokey)
137 return 0;
138
139 rc = RegOpenKeyEx (HKEY_CURRENT_USER, GPG_MO_REG, 0, KEY_READ, &reg);
140 if (rc == ERROR_SUCCESS) {
141 RegCloseKey (reg);
142 return 0;
143 }
144 rc = RegCreateKey (HKEY_CURRENT_USER, GPG_MO_REG, &reg);
145 if (rc != ERROR_SUCCESS)
146 return WPTERR_REGISTRY;
147
148 RegCloseKey (reg);
149 return 0;
150 }
151
152
153 /* Create a new filetype in the W32 registry.
154 We should really care of errors! Otherwise we can damage the registry! */
155 static int
156 create_file_type (const char *exefile, const char *ext,
157 const char *extname, char *iconfile)
158 {
159 HKEY reg = NULL;
160 char deficon[MAX_PATH+1];
161 char defexec[MAX_PATH+1];
162 char p_exefile[MAX_PATH+1];
163 int rc;
164
165 rc = RegCreateKey (HKEY_CLASSES_ROOT, ext, &reg);
166 if( rc_ok( rc ) )
167 rc = RegSetValueEx( reg, NULL, 0, REG_SZ, (BYTE *)extname, strlen( extname ) );
168 if( rc_ok( rc ) )
169 rc = RegCloseKey( reg );
170 if( rc_ok( rc ) )
171 rc = RegCreateKey( HKEY_CLASSES_ROOT, extname, &reg );
172 if( rc_ok( rc ) )
173 rc = RegSetValueEx( reg, NULL, 0, REG_SZ, (BYTE *) extname, strlen( extname ) );
174 if( rc_ok( rc ) )
175 rc = RegCloseKey( reg );
176 if( !rc_ok( rc ) ) {
177 rc = WPTERR_REGISTRY;
178 goto leave;
179 }
180
181 memset( &deficon, 0, sizeof deficon );
182 _snprintf( deficon, DIM (deficon) - 1, "%s\\DefaultIcon", extname );
183 memset( &defexec, 0, sizeof defexec );
184 _snprintf( defexec, DIM (defexec) - 1, "%s\\shell\\open\\command", extname );
185 memset( &p_exefile, 0, sizeof p_exefile );
186 _snprintf( p_exefile, DIM (p_exefile) - 1, "%s %%1", exefile );
187
188 rc = RegCreateKey( HKEY_CLASSES_ROOT, deficon, &reg );
189 if( rc_ok( rc ) )
190 rc = RegSetValueEx(reg, NULL, 0, REG_SZ, (BYTE *)iconfile, strlen( iconfile ) );
191 if( rc_ok( rc ) )
192 rc = RegCloseKey( reg );
193 if( rc_ok( rc ) )
194 rc = RegCreateKey( HKEY_CLASSES_ROOT, defexec, &reg );
195 if( rc_ok( rc ) )
196 rc = RegSetValueEx( reg, NULL, 0, REG_SZ, (BYTE *)p_exefile, strlen( exefile ) );
197 if( rc_ok( rc ) )
198 rc = RegCloseKey( reg );
199 if( !rc_ok( rc ) ) {
200 rc = WPTERR_REGISTRY;
201 goto leave;
202 }
203
204 leave:
205 if (reg)
206 RegCloseKey (reg);
207 return rc;
208 }
209
210
211 /* Register the given WinPT filetype. */
212 static int
213 regist_single_filetype (gpg_filetype_t gfile)
214 {
215 char icon[MAX_PATH+1] = {0};
216 char prog[MAX_PATH+1] = {0};
217
218 if (!GetModuleFileName (glob_hinst, prog, DIM (prog)-1))
219 return WPTERR_REGISTRY;
220 _snprintf (icon, DIM (icon) -1, "%s,%d", prog, gfile->nicon);
221 return create_file_type (prog, gfile->ext, gfile->descr, icon);
222 }
223
224 /* Install WinPT into the W32 registry, if the entry already
225 exists the function returns immediately. @with_ext can be
226 used to register some file types (if 1). @created contains
227 1 if the registry key was created.
228 Return value: 0 on success. */
229 int
230 regist_inst_winpt (int with_ext, int *created)
231 {
232 struct gpg_filetype_s gpg_filetypes[] = {
233 {_("GPG Detached Signature"), ".sig", 1},
234 {_("GPG Encrypted Data"), ".gpg", 2},
235 {_("GPG Armored Data"), ".asc", 2},
236 {0}
237 };
238 HKEY reg;
239 char *p = NULL;
240 char modpath[MAX_PATH+1];
241 int rc, i, id, n;
242
243 if (created)
244 *created = 0;
245
246 /* If GPGee is already installed deactivate file extension registering
247 because it is very likely this would overwrite the GPGee settings. */
248 if (is_gpgee_installed ())
249 with_ext = 0;
250
251 rc = RegOpenKeyEx (HKEY_CURRENT_USER, WINPT_REG, 0, KEY_READ, &reg);
252 if (rc == ERROR_SUCCESS) {
253 RegCloseKey (reg);
254 rc = RegOpenKeyEx (HKEY_CURRENT_USER, WINPT_REG"\\Keyserver", 0, KEY_READ, &reg);
255 if (rc != ERROR_SUCCESS) {
256 rc = RegCreateKey (HKEY_CURRENT_USER, WINPT_REG"\\Keyserver", &reg);
257 if (rc == ERROR_SUCCESS)
258 RegCloseKey (reg);
259 }
260 else
261 RegCloseKey (reg);
262 p = get_reg_entry_keyserver ("Default");
263 if (!p) {
264 char buf[16];
265
266 _snprintf (buf, DIM (buf)-1, "%d", HKP_PORT);
267 set_reg_entry_keyserver ("Default_Port", buf);
268 set_reg_entry_keyserver ("Default", DEF_HKP_KEYSERVER);
269 }
270 free_if_alloc (p);
271 return 0;
272 }
273 rc = RegCreateKey (HKEY_CURRENT_USER, WINPT_REG, &reg);
274 if (rc != ERROR_SUCCESS)
275 return WPTERR_REGISTRY;
276 if (created)
277 *created = 1;
278 RegCloseKey (reg);
279 /* FIXME: check this part */
280 if (with_ext) {
281 id = msg_box (NULL, _("WinPT can register some GPG file types for you so they can "
282 "be processed with a double click in the explorer.\n"
283 "Do you want to continue?"), _("WinPT"), MB_YESNO|MB_INFO);
284 if (id == IDYES) {
285 for (i = 0; gpg_filetypes[i].ext; i++) {
286 rc = RegOpenKeyEx (HKEY_CLASSES_ROOT, gpg_filetypes[i].ext, 0, KEY_READ, &reg);
287 if (rc == ERROR_SUCCESS) {
288 RegCloseKey (reg);
289 id = log_box (_("WinPT WARNING"), MB_YESNO|MB_INFO,
290 _("It seems there was already a '%s' file type registered by another application.\n"
291 "Do you want to overwrite it?"), gpg_filetypes[i].ext);
292 if (id == IDNO)
293 continue;
294 }
295 regist_single_filetype (&gpg_filetypes[i]);
296 }
297 }
298 }
299 /* Store the install directory for later use. */
300 n = GetModuleFileName (NULL, modpath, MAX_PATH-1);
301 if (n > 0) {
302 while (n-- > 0) {
303 if (modpath[n] == '\\') {
304 modpath[n] = 0;
305 break;
306 }
307 }
308 log_debug("storing install directory '%s'", modpath);
309 set_reg_entry (HKEY_CURRENT_USER, WINPT_REG, "Install Directory", modpath);
310 }
311 return 0;
312 }
313
314
315 /* Expand a string with %foo% entries so that %foo% will
316 be replaced with its actual value. */
317 static char*
318 expand_path (const char *path)
319 {
320 DWORD len;
321 char *p;
322
323 len = ExpandEnvironmentStrings (path, NULL, 0);
324 if (!len)
325 return NULL;
326 len += 1;
327 p = new char[len+1];
328 if (!p)
329 return NULL;
330 len = ExpandEnvironmentStrings (path, p, len);
331 if (!len) {
332 free_if_alloc (p);
333 return NULL;
334 }
335 return p;
336 }
337
338
339 /* Retrieve a registry entry with the directory given in @dir
340 and the key given in @key.
341 Return value is the value or NULL otherwise. */
342 char*
343 get_reg_entry (HKEY root_key, const char *dir, const char *key)
344 {
345 HKEY reg_key = NULL;
346 char *p = NULL, *pp;
347 DWORD type = REG_SZ, nbytes = 0;
348 int rc;
349
350 rc = RegOpenKeyEx (root_key, dir, 0, KEY_QUERY_VALUE, &reg_key);
351 if (rc != ERROR_SUCCESS)
352 goto leave;
353 rc = RegQueryValueEx (reg_key, key, NULL, &type, NULL, &nbytes);
354 if (rc != ERROR_SUCCESS)
355 goto leave;
356 if (!nbytes)
357 goto leave; /* empty */
358 p = new char[nbytes+1];
359 if (!p)
360 BUG (0);
361 rc = RegQueryValueEx (reg_key, key, NULL, &type, (BYTE*)p, &nbytes);
362 if (rc != ERROR_SUCCESS)
363 goto leave;
364 if (type == REG_EXPAND_SZ && strchr (p, '%')) {
365 pp = p;
366 p = expand_path (pp);
367 free_if_alloc (pp);
368 }
369
370 leave:
371 if (reg_key != NULL)
372 RegCloseKey (reg_key);
373 return p;
374 }
375
376
377 /* XXX: use REG_EXPAND_SZ to support multi user environments.
378 keep this type and do not overwrite it with REG_SZ. */
379
380 /* Set a registry entry. */
381 int
382 set_reg_entry (HKEY root_key, const char *dir, const char *key,
383 const char *value)
384 {
385 HKEY reg_key;
386 int rc;
387
388 rc = RegOpenKeyEx (root_key, dir, 0, KEY_WRITE, &reg_key);
389 if (rc != ERROR_SUCCESS)
390 return WPTERR_REGISTRY;
391 rc = RegSetValueEx (reg_key, key, 0, REG_SZ, (BYTE *)value, strlen (value));
392 if (rc != ERROR_SUCCESS)
393 rc = WPTERR_REGISTRY;
394 RegCloseKey (reg_key);
395 return rc;
396 }
397
398
399 int
400 set_reg_key (HKEY root_key, const char *dir, const char *key,
401 const char *value)
402 {
403 HKEY reg_key;
404 int rc;
405
406 rc = RegOpenKeyEx (root_key, dir, 0, KEY_WRITE, &reg_key);
407 if (rc != ERROR_SUCCESS)
408 return WPTERR_REGISTRY;
409
410 rc = RegSetValueEx (reg_key, key, 0, REG_SZ, (BYTE *)value, strlen (value));
411 if (rc != ERROR_SUCCESS) {
412 if (RegCreateKey (root_key, key, &reg_key) != ERROR_SUCCESS) {
413 rc = WPTERR_REGISTRY;
414 goto leave;
415 }
416 rc = RegSetValueEx (reg_key, key, 0, REG_SZ, (BYTE *)value, strlen (value));
417 if (rc != ERROR_SUCCESS)
418 rc = WPTERR_REGISTRY;
419 }
420
421 leave:
422 RegCloseKey (reg_key);
423 return rc;
424 }
425
426
427 int
428 set_reg_entry_gpg (const char *key, const char *value)
429 {
430 return set_reg_entry (HKEY_CURRENT_USER, GPG_REG, key, value);
431 }
432
433
434
435 char*
436 get_reg_entry_gpg (const char *key)
437 {
438 char *p;
439
440 p = get_reg_entry (HKEY_CURRENT_USER, GPG_REG, key);
441 if (!p || strlen (p) == 0) {
442 free_if_alloc (p);
443 return NULL;
444 }
445 return p;
446 }
447
448
449 /* Return if possible the GPG4Win installation directory concatenated
450 with the string in @path if given. */
451 char*
452 get_reg_entry_gpg4win (const char *path)
453 {
454 const char *fmt;
455 char *p, *pp;
456
457 p = get_reg_entry (HKEY_LOCAL_MACHINE, GPG_REG, "Install Directory");
458 if (!p)
459 return NULL;
460 if (!path)
461 return p;
462 fmt = "%s\\%s";
463 pp = new char[strlen (p) + strlen (path) + strlen (fmt) + 1];
464 if (!pp)
465 BUG (NULL);
466 sprintf (pp, fmt, p, path);
467 free_if_alloc (p);
468 return pp;
469 }
470
471
472 char*
473 get_reg_entry_mo (void)
474 {
475 char *p, *pp;
476 const char *fmt;
477 const char *lang;
478
479 p = get_reg_entry (HKEY_CURRENT_USER, GPG_MO_REG, "MODir");
480 if (p)
481 return p;
482
483 lang = gettext_get_langid ();
484 if (!lang)
485 return NULL;
486 fmt = "share\\locale\\%s\\LC_MESSAGES";
487 pp = new char[strlen (fmt) + strlen (lang) + 4 + 1];
488 if (!pp)
489 BUG (NULL);
490 sprintf (pp, fmt, lang);
491 p = get_reg_entry_gpg4win (pp);
492 free_if_alloc (pp);
493 return p;
494 }
495
496
497 int
498 set_reg_winpt_single (int id, int val)
499 {
500 char buf[64];
501 int rc;
502
503 _snprintf (buf, DIM (buf)-1, "%d", val);
504 rc = set_reg_entry (HKEY_CURRENT_USER, WINPT_REG, cfg[id], buf);
505 return rc;
506 }
507
508
509 int
510 get_reg_winpt_single (int id)
511 {
512 char *buf;
513 int val = 0;
514
515 buf = get_reg_entry (HKEY_CURRENT_USER, WINPT_REG, cfg[id]);
516 if (buf && *buf != ' ')
517 val = 1;
518 else if (!buf)
519 val = -1;
520 free_if_alloc (buf);
521 return val;
522 }
523
524
525 /* Saves the winpt preferences in the registry. */
526 int
527 set_reg_winpt_prefs (winpt_prefs_t opt)
528 {
529 char buf[128];
530 size_t i;
531 int rc = 0;
532
533 for (i=1; i < DIM (cfg); i++) {
534 switch (i) {
535 case CFG_CACHETIME:
536 sprintf (buf, "%d", opt->cache_time);
537 break;
538
539 case CFG_WORDWRAP:
540 sprintf (buf, "%d", opt->word_wrap);
541 break;
542
543 case CFG_FILEEXT:
544 sprintf (buf, "%d", opt->default_ext);
545 break;
546
547 case CFG_NOZIP_MMEDIA:
548 sprintf (buf, "%d", opt->no_zip_mmedia);
549 break;
550
551 case CFG_VIEWER:
552 sprintf (buf, "%d", opt->use_viewer);
553 break;
554
555 case CFG_ALWAYSTRUST:
556 sprintf (buf, "%d", opt->always_trust);
557 break;
558
559 case CFG_AUTOBACKUP:
560 sprintf (buf, "%d", opt->auto_backup);
561 break;
562
563 case CFG_AUTOBAKMODE:
564 sprintf (buf, "%d", opt->backup.mode);
565 break;
566
567 case CFG_DISHOTKEYS:
568 sprintf (buf, "%d", opt->no_hotkeys);
569 break;
570
571 case CFG_EXPERT:
572 sprintf (buf, "%d", opt->expert);
573 break;
574
575 case CFG_FM_PROGRESS:
576 sprintf (buf, "%d", opt->fm.progress);
577 break;
578
579 case CFG_BACKUP_INC_SKR:
580 sprintf (buf, "%d", opt->backup.include_secr);
581 break;
582 }
583 rc = set_reg_entry (HKEY_CURRENT_USER, WINPT_REG, cfg[i], buf);
584 if (rc)
585 goto leave;
586 }
587
588 if (opt->backup.path) {
589 rc = set_reg_entry (HKEY_CURRENT_USER, WINPT_REG, "BackupPath",
590 opt->backup.path);
591 if (rc)
592 goto leave;
593 }
594
595 for (i=0; wpt_hotkeys[i].name != NULL; i++) {
596 if (wpt_hotkeys[i].enabled == 1) {
597 buf[0] = wpt_hotkeys[i].key;
598 buf[1] = 0;
599 }
600 else
601 strcpy (buf, " ");
602 rc = set_reg_key (HKEY_CURRENT_USER, WINPT_REG,
603 wpt_hotkeys[i].name, buf);
604 if (rc)
605 break;
606 }
607
608 leave:
609 if (rc) {
610 msg_box (NULL, _("Could not write to Registry."), _("Preferences"), MB_ERR);
611 return rc;
612 }
613 return 0;
614 }
615
616
617 int
618 set_reg_winpt_flag (const char *name, int val)
619 {
620 return set_reg_entry (HKEY_CURRENT_USER, WINPT_REG, name, val? "1" : "0");
621 }
622
623
624 int
625 get_reg_winpt_flag (const char *name)
626 {
627 char *buf;
628 int flag = 0;
629
630 buf = get_reg_entry (HKEY_CURRENT_USER, WINPT_REG, name);
631 if (buf && buf[0] == '1')
632 flag = 1;
633 else if (!buf || (buf && buf[0] != '0'))
634 flag = -1;
635 free_if_alloc (buf);
636 return flag;
637 }
638
639
640 /* Retrieve the winpt preferences from the registry. */
641 int
642 get_reg_winpt_prefs (winpt_prefs_t opt)
643 {
644 char *val = NULL;
645 size_t i;
646
647 for (i=1; i < DIM (cfg); i++) {
648 val = get_reg_entry (HKEY_CURRENT_USER, WINPT_REG, cfg[i]);
649 if (!val || *val == ' ') {
650 free_if_alloc (val);
651 continue;
652 }
653 switch (i) {
654 case CFG_CACHETIME:
655 opt->cache_time = atoi (val);
656 break;
657 case CFG_WORDWRAP:
658 opt->word_wrap = atoi (val);
659 break;
660 case CFG_FILEEXT:
661 opt->default_ext = atoi (val);
662 break;
663 case CFG_NOZIP_MMEDIA:
664 opt->no_zip_mmedia = atoi (val);
665 break;
666 case CFG_VIEWER:
667 opt->use_viewer = atoi (val);
668 break;
669 case CFG_DISHOTKEYS:
670 opt->no_hotkeys = atoi (val);
671 break;
672 case CFG_ALWAYSTRUST:
673 opt->always_trust = atoi (val);
674 break;
675 case CFG_AUTOBACKUP:
676 opt->auto_backup = atoi (val);
677 break;
678 case CFG_AUTOBAKMODE:
679 opt->backup.mode = atoi (val);
680 break;
681 case CFG_EXPERT:
682 opt->expert = atoi (val);
683 break;
684 case CFG_FM_PROGRESS:
685 opt->fm.progress = atoi (val);
686 break;
687
688 case CFG_BACKUP_INC_SKR:
689 opt->backup.include_secr = atoi (val);
690 break;
691 }
692 free_if_alloc (val);
693 }
694
695 val = get_reg_entry (HKEY_CURRENT_USER, WINPT_REG, "BackupPath");
696 if (val && val[0] != ' ')
697 opt->backup.path = m_strdup (val);
698 free_if_alloc (val);
699
700 for (i=0; wpt_hotkeys[i].name; i++) {
701 wpt_hotkeys[i].enabled = 0;
702 val = get_reg_entry (HKEY_CURRENT_USER, WINPT_REG, wpt_hotkeys[i].name);
703 if (val && val[0] != ' ') {
704 wpt_hotkeys[i].key = *val;
705 wpt_hotkeys[i].enabled = 1;
706 }
707 free_if_alloc (val);
708 }
709 return 0;
710 }
711
712
713 char*
714 get_reg_entry_keyserver (const char *name)
715 {
716 char *p = get_reg_entry (HKEY_CURRENT_USER, WINPT_REG"\\Keyserver", name);
717 if (p && (!strcmp (p, "") || strlen (p) == 0)) {
718 free_if_alloc (p);
719 return NULL;
720 }
721 return p;
722 }
723
724
725 int
726 set_reg_entry_keyserver (const char *name, const char *val)
727 {
728 return set_reg_entry (HKEY_CURRENT_USER, WINPT_REG"\\Keyserver", name, val);
729 }
730

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26