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

Diff of /trunk/Src/wptKeyPropsDlg.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 33 by twoaday, Tue Oct 25 07:46:20 2005 UTC revision 41 by twoaday, Fri Oct 28 07:15:26 2005 UTC
# Line 1  Line 1 
1  /* wptKeyPropsDlg.cpp - WinPT key properties dialog  /* wptKeyPropsDlg.cpp - WinPT key properties dialog
2   *      Copyright (C) 2000, 2001, 2002, 2003, 2005 Timo Schulz   *      Copyright (C) 2000, 2001, 2002, 2003, 2005 Timo Schulz
3   *   *
4   * This file is part of WinPT.   * This file is part of WinPT.
5   *   *
6   * WinPT is free software; you can redistribute it and/or modify   * WinPT is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
8   * the Free Software Foundation; either version 2 of the License, or   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.   * (at your option) any later version.
10   *   *
11   * WinPT is distributed in the hope that it will be useful,   * WinPT is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.   * GNU General Public License for more details.
15   *   *
16   * You should have received a copy of the GNU General Public License   * You should have received a copy of the GNU General Public License
17   * along with WinPT; if not, write to the Free Software Foundation,   * along with WinPT; if not, write to the Free Software Foundation,
18   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */   */
20    
21  #include <windows.h>  #include <windows.h>
22    
23  #include "../resource.h"  #include "../resource.h"
24  #include "wptErrors.h"  #include "wptErrors.h"
25  #include "wptGPG.h"  #include "wptGPG.h"
26  #include "wptCommonCtl.h"  #include "wptCommonCtl.h"
27  #include "wptContext.h" /* for passphrase_s */  #include "wptContext.h" /* for passphrase_s */
28  #include "wptNLS.h"  #include "wptNLS.h"
29  #include "wptDlgs.h"  #include "wptDlgs.h"
30  #include "wptTypes.h"  #include "wptTypes.h"
31  #include "wptKeylist.h"  #include "wptKeylist.h"
32  #include "wptW32API.h"  #include "wptW32API.h"
33  #include "wptVersion.h"  #include "wptVersion.h"
34  #include "wptKeyEdit.h"  #include "wptKeyEdit.h"
35    
36  static void  
37  do_change_ownertrust (winpt_key_t k, const char *s)  /* Check that the key is not expired or revoked. */
38  {  static int
39      char ot[64];  do_check_key (gpgme_key_t key)
40        {
41      if( strstr( s, "ultimate" ) ) {      int okay = 0;
42          listview_get_item_text (k->callback.ctl, k->callback.idx, 5, ot, DIM (ot)-1);      okay = key->expired;
43          strcpy (ot, "Ultimate");      if (!okay)
44          listview_add_sub_item (k->callback.ctl, k->callback.idx, 5, ot);          okay = key->revoked;
45          /* fixme: If we switch back from Ultimate to a lower level */      return okay;
46      }  }
47  }  
48    
49    /* Convert a trust integer into a string representation. */
50  /* Check that the key is not expired or revoked. */  static const char*
51  static int  ownertrust_to_string (int val)
52  do_check_key (gpgme_key_t key)  {
53  {      const char *inf;
54      int okay = 0;      int id = val;
55      okay = key->expired;  
56      if (!okay)      switch (id) {
57          okay = key->revoked;      case 1: inf = _("Don't know");         break;
58      return okay;      case 2: inf = _("I do NOT trust");     break;
59  }      case 3: inf = _("I trust marginally"); break;
60        case 4: inf = _("I trust fully");      break;
61        case 5:
62  /* Convert a trust integer into a string representation. */      case 6: inf = _("I trust ultimately"); break;
63  static const char*      default:inf = _("Unknown");            break;
64  ownertrust_to_string (int val)      }
65  {      
66      const char * inf;      return inf;
67      int id = val;  }
68      switch (id) {  
69      case 1: inf = _("Don't know");         break;  
70      case 2: inf = _("I do NOT trust");     break;  /* Generate a unique temp name for the photo which
71      case 3: inf = _("I trust marginally"); break;     depends on the dialog handle and return it. */
72      case 4: inf = _("I trust fully");      break;  static const char*
73      case 5:  get_photo_tmpname (HWND dlg)
74      case 6: inf = _("I trust ultimately"); break;  {
75      default:inf = _("Unknown");            break;      static char buf[64];
76      }  
77            _snprintf (buf, sizeof (buf)-1, "winpt_photo_%08lX.tmp", (DWORD)dlg);
78      return inf;      return buf;
79  }  }
80    
81    
82  #define PHOTO_TMPNAME "winpt_temp_photo.jpg"  /* Load the photo from the key @key */
83    static int
84  /* Load the photo from the key @key */  keyprops_load_photo (HWND dlg, gpgme_key_t key, gpgme_validity_t *r_valid)
85  static int  {
86  keyprops_load_photo (gpgme_key_t key, gpgme_validity_t *r_valid)      winpt_key_s k;
87  {      FILE *f;
88      winpt_key_s k;      const BYTE *img;
89      FILE *f;      DWORD imglen = 0;
90      const BYTE *img;      int pos=0;
91      DWORD imglen = 0;  
92      int pos=0;      winpt_get_pubkey (key->subkeys->keyid, &k);
93        img = k.ext->attrib.d;
94      winpt_get_pubkey (key->subkeys->keyid, &k);      imglen = k.ext->attrib.len;
95      img = k.ext->attrib.d;      if (!k.ext->attrib.validity)
96      imglen = k.ext->attrib.len;              get_uat_validity (key->subkeys->keyid, &k.ext->attrib.validity);
97      if (!k.ext->attrib.validity)      *r_valid = k.ext->attrib.validity;
98          get_uat_validity (key->subkeys->keyid, &k.ext->attrib.validity);  
99      *r_valid = k.ext->attrib.validity;      if (!img || !imglen)
100            return -1;
101      if (!img || !imglen)      f = fopen (get_photo_tmpname (dlg), "wb");
102          return -1;      if (f) {
103      f = fopen (PHOTO_TMPNAME, "wb");          for (pos = 0; img[pos] != 0x10; pos++)
104      if (f) {                  ;
105          for (pos = 0; img[pos] != 0x10; pos++)          pos += 16;
106                  ;          fwrite (img + pos, 1, imglen - pos, f);
107          pos += 16;          fwrite (img, 1, imglen, f);
108          fwrite (img + pos, 1, imglen - pos, f);          fclose (f);
109          fwrite (img, 1, imglen, f);      }
110          fclose (f);      return 0;
111      }  }
112      return 0;  
113  }  
114    /* Display the photo in the image control in the dialog @dlg. */
115    static int
116  /* Display the photo in the image control in the dialog @dlg. */  keyprops_show_photo (HWND dlg)
117  static int  {
118  keyprops_show_photo (HWND dlg)      RECT r;    
119  {      POINT p;
120      RECT r;          HWND h;
121      POINT p;  
122      HWND h;      h = GetDlgItem (dlg, IDC_KEYPROPS_IMG);
123        GetWindowRect (h, &r);
124      h = GetDlgItem (dlg, IDC_KEYPROPS_IMG);      p.x = r.left + 5;
125      GetWindowRect (h, &r);      p.y = r.top - 2;
126      p.x = r.left + 5;      memset (&p, 0, sizeof (p));
127      p.y = r.top - 2;      PTD_jpg_show (h, &p, get_photo_tmpname (dlg));
128      memset (&p, 0, sizeof (p));      
129      PTD_jpg_show (h, &p, PHOTO_TMPNAME);      return 0;
130        }
131      return 0;  
132  }  
133    /* Return string representation of the key validity. @key. */
134    static const char*
135  /* Return string representation of the key validity. @key. */  get_validity (gpgme_key_t key)
136  static const char*  {
137  get_validity (gpgme_key_t key)      int val;
138  {      val = key->expired;
139      int val;      if (val)
140      val = key->expired;          return _("Expired");    
141      if (val)      val = key->revoked;
142          return _("Expired");          if (val)
143      val = key->revoked;          return _("Revoked");
144      if (val)      val = key->disabled;
145          return _("Revoked");      if (val)
146      return get_key_trust2 (NULL, key->uids->validity, 0, 0);          return _("Disabled");
147  }      return get_key_trust2 (NULL, key->uids->validity, 0, 0);
148    }
149    
150  /* Return the preferred sym. algorithm from @key as a string. */  
151  static const char*  /* Return the preferred sym. algorithm from @key as a string. */
152  get_pref_cipher (winpt_key_t k)  static const char*
153  {  get_pref_cipher (winpt_key_t k)
154      const char *sym_prefs=NULL;      {
155        const char *sym_prefs=NULL;    
156      if (k->is_v3)  
157          return "IDEA";      if (k->is_v3)
158      if (!k->ext->sym_prefs)          return "IDEA";
159          return "3DES";      if (!k->ext->sym_prefs)
160      switch (*k->ext->sym_prefs) {          return "3DES";
161      case 1: return "IDEA";      switch (*k->ext->sym_prefs) {
162      case 2: return "3DES";      case 1: return "IDEA";
163      case 3: return "CAST5";      case 2: return "3DES";
164      case 4: return "Blowfish";      case 3: return "CAST5";
165      case 7:      case 4: return "Blowfish";
166      case 8:      case 7:
167      case 9: return "AES";      case 8:
168      case 10:return "Twofish";      case 9: return "AES";
169      }      case 10:return "Twofish";
170      return "Unknown";      }
171  }      return "Unknown";
172    }
173    
174  /* Return true if the key has designated revokers. */  
175  static bool  /* Return true if the key has designated revokers. */
176  check_for_desig_rev (gpgme_key_t key)  static bool
177  {  check_for_desig_rev (gpgme_key_t key)
178      winpt_key_s k;  {
179      memset (&k, 0, sizeof (k));      winpt_key_s k;
180      if (!winpt_get_pubkey (key->subkeys->keyid, &k))      memset (&k, 0, sizeof (k));
181          return k.ext->gloflags.has_desig_rev? true : false;      if (!winpt_get_pubkey (key->subkeys->keyid, &k))
182      return false;          return k.ext->gloflags.has_desig_rev? true : false;
183  }      return false;
184    }
185    
186  /* Print information (name) of the smart card. */  
187  static const char*  /* Print information (name) of the smart card. */
188  get_card_type (winpt_key_t k)  static const char*
189  {      get_card_type (winpt_key_t k)
190      static char buf[64];  {    
191        static char buf[64];
192      if (!k->ext->card_type)  
193          return "";      if (!k->ext->card_type)
194      _snprintf (buf, sizeof (buf)-1, _("Card-Type: %s\r\n"), k->ext->card_type);          return "";
195      return buf;      _snprintf (buf, sizeof (buf)-1, _("Card-Type: %s\r\n"), k->ext->card_type);
196  }      return buf;
197    }
198    
199  /* Display the key information for key @k.  
200     Return value: gpgme key on success. */  /* Display the key information for key @k.
201  static void     Return value: gpgme key on success. */
202  display_key_info (HWND dlg, winpt_key_t k, gpgme_key_t *r_key)  static void
203  {  display_key_info (HWND dlg, winpt_key_t k, gpgme_key_t *r_key)
204      struct winpt_key_s k2;  {
205      gpgme_key_t sk, key;      struct winpt_key_s k2;
206      char info[512];      gpgme_key_t sk, key;
207      const char *inf;      char info[512];
208      u32 created, expires;          const char *inf;
209        u32 created, expires;    
210      memset (&k2, 0, sizeof (k2));        
211      if (k->key_pair)      memset (&k2, 0, sizeof (k2));      
212          winpt_get_seckey (k->keyid, &k2);      if (k->key_pair)
213      else              winpt_get_seckey (k->keyid, &k2);
214          winpt_get_pubkey (k->keyid, &k2);      else    
215      sk = k2.ctx;                  winpt_get_pubkey (k->keyid, &k2);
216      if (sk)      sk = k2.ctx;        
217          k->is_protected = k2.is_protected;      if (sk)
218      if (get_pubkey (k->keyid, &key))          k->is_protected = k2.is_protected;
219          BUG (0);          if (get_pubkey (k->keyid, &key))
220      created = key->subkeys->timestamp;            BUG (0);    
221      expires = key->subkeys->expires;          created = key->subkeys->timestamp;  
222      _snprintf (info, DIM (info)-1,      expires = key->subkeys->expires;    
223                 _("Type: %s\r\n"      _snprintf (info, DIM (info)-1,
224                 "Key ID: %s\r\n"                 _("Type: %s\r\n"
225                 "Algorithm: %s\r\n"                 "Key ID: %s\r\n"
226                 "Size: %s\r\n"                 "Algorithm: %s\r\n"
227                 "Created: %s\r\n"                 "Size: %s\r\n"
228                 "Expires: %s\r\n"                 "Created: %s\r\n"
229                 "Validity: %s\r\n"                 "Expires: %s\r\n"
230                 "Cipher: %s\r\n"                 "Validity: %s\r\n"
231                 "%s\r\n"),                 "Cipher: %s\r\n"
232                 get_key_type (key),                 "%s\r\n"),
233                 k->keyid,                 get_key_type (key),
234                 get_key_algo (key, 0),                 k->keyid,
235                 get_key_size (key, 0),                 get_key_algo (key, 0),
236                 get_key_created (created),                 get_key_size (key, 0),
237                 get_key_expire_date (expires),                 get_key_created (created),
238                 get_validity (key),                 get_key_expire_date (expires),
239                 get_pref_cipher (&k2),                 get_validity (key),
240                 get_card_type (&k2));                 get_pref_cipher (&k2),
241                   get_card_type (&k2));
242      SetDlgItemText (dlg, IDC_KEYPROPS_INFO, info);  
243      SetDlgItemText (dlg, IDC_KEYPROPS_FPR, get_key_fpr (key));        SetDlgItemText (dlg, IDC_KEYPROPS_INFO, info);
244      inf = ownertrust_to_string (key->owner_trust);      SetDlgItemText (dlg, IDC_KEYPROPS_FPR, get_key_fpr (key));  
245      SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);      inf = ownertrust_to_string (key->owner_trust);
246        SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);
247      *r_key = key;  
248  }      *r_key = key;
249    }
250    
251  /* Dialog box procedure to show the key properties. */  
252  BOOL CALLBACK  /* Dialog box procedure to show the key properties. */
253  keyprops_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  BOOL CALLBACK
254  {  keyprops_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
255      static winpt_key_t k;  {
256      static gpgme_key_t key;      static winpt_key_t k;
257      static int has_photo = 0;      static gpgme_key_t key;
258      gpgme_validity_t valid;      gpgme_validity_t valid;
259      refresh_cache_s rcs = {0};      refresh_cache_s rcs = {0};
260      const char *inf;      const char *inf;
261      int cancel = 0;      int cancel = 0;
262      int rc;      int rc;
263            
264      switch (msg) {      /* XXX: static variable (k) prevent that the dialog can
265      case WM_INITDIALOG:              be opened twice. */
266          if (!lparam)      switch (msg) {
267              dlg_fatal_error (dlg, "Could not get dialog param!");      case WM_INITDIALOG:
268          k = (winpt_key_t)lparam;          if (!lparam)
269          #ifndef LANG_DE              dlg_fatal_error (dlg, "Could not get dialog param!");
270          SetWindowText (dlg, _("Key Properties"));          k = (winpt_key_t)lparam;
271          SetDlgItemText (dlg, IDC_KEYPROPS_OT_CHANGE, _("&Change"));          #ifndef LANG_DE
272          SetDlgItemText (dlg, IDC_KEYPROPS_REVOKERS, _("&Revokers"));          SetWindowText (dlg, _("Key Properties"));
273          SetDlgItemText (dlg, IDC_KEYPROPS_CHANGE_PWD, _("Change &Passwd"));          SetDlgItemText (dlg, IDC_KEYPROPS_OT_CHANGE, _("&Change"));
274          SetDlgItemText (dlg, IDC_KEYPROPS_OTINF, _("Ownertrust"));          SetDlgItemText (dlg, IDC_KEYPROPS_REVOKERS, _("&Revokers"));
275          #endif            SetDlgItemText (dlg, IDC_KEYPROPS_CHANGE_PWD, _("Change &Passwd"));
276            SetDlgItemText (dlg, IDC_KEYPROPS_OTINF, _("Ownertrust"));
277          display_key_info (dlg, k, &key);          #endif  
278          if (!keyprops_load_photo (key, &valid)) {  
279              has_photo = 1;                display_key_info (dlg, k, &key);
280              if (valid != 0 && valid < GPGME_VALIDITY_MARGINAL)          if (!keyprops_load_photo (dlg, key, &valid)) {
281                  SetDlgItemText (dlg, IDC_KEYPROPS_IMGINF, _("Photo-ID not checked."));              k->has_photo = 1;  
282          }              if (valid < GPGME_VALIDITY_MARGINAL)
283          if (k->key_pair)                  SetDlgItemText (dlg, IDC_KEYPROPS_IMGINF, _("Photo-ID not validated."));
284              EnableWindow (GetDlgItem (dlg, IDC_KEYPROPS_CHANGE_PWD), TRUE);          }
285          if (check_for_desig_rev (key))          if (k->key_pair)
286              EnableWindow (GetDlgItem (dlg, IDC_KEYPROPS_REVOKERS), TRUE);              EnableWindow (GetDlgItem (dlg, IDC_KEYPROPS_CHANGE_PWD), TRUE);
287          center_window (dlg, NULL);          if (check_for_desig_rev (key))
288          SetForegroundWindow (dlg);                    EnableWindow (GetDlgItem (dlg, IDC_KEYPROPS_REVOKERS), TRUE);
289          return TRUE;          center_window (dlg, NULL);
290            SetForegroundWindow (dlg);      
291      case WM_DESTROY:          return TRUE;
292          has_photo = 0;  
293          unlink (PHOTO_TMPNAME);      case WM_DESTROY:
294          break;          unlink (get_photo_tmpname (dlg));
295                  break;
296      case WM_PAINT:        
297          if (has_photo)      case WM_PAINT:
298              keyprops_show_photo (dlg);          if (k->has_photo)
299          break;              keyprops_show_photo (dlg);
300            break;
301      case WM_SYSCOMMAND:  
302          if (LOWORD (wparam) == SC_CLOSE)      case WM_SYSCOMMAND:
303              EndDialog (dlg, TRUE);          if (LOWORD (wparam) == SC_CLOSE)
304          return FALSE;              EndDialog (dlg, TRUE);
305                    return FALSE;
306      case WM_COMMAND:          
307          switch (LOWORD (wparam)) {      case WM_COMMAND:
308          case IDOK:          switch (LOWORD (wparam)) {
309              EndDialog (dlg, TRUE);          case IDOK:
310              return TRUE;              EndDialog (dlg, TRUE);
311                            return TRUE;
312          case IDC_KEYPROPS_OT_CHANGE:              
313              if (do_check_key (key)) {          case IDC_KEYPROPS_OT_CHANGE:
314                  msg_box (dlg, _("The status of this key is 'revoked' or 'expired'.\n"              if (do_check_key (key)) {
315                                  "You cannot change the ownertrust of such keys."),                  msg_box (dlg, _("The status of this key is 'revoked' or 'expired'.\n"
316                                  _("WinPT Warning"), MB_ERR);                                  "You cannot change the ownertrust of such keys."),
317                  return TRUE;                                  _("WinPT Warning"), MB_ERR);
318              }                  return TRUE;
319              if( !k->key_pair && key->uids->validity < 3 ) {              }
320                  rc = msg_box( dlg, _("This is a non-valid key.\n"              if( !k->key_pair && key->uids->validity < 3 ) {
321                                       "Modifying the ownertrust has no effect on such keys.\n\n"                  rc = msg_box( dlg, _("This is a non-valid key.\n"
322                                       "Do you really want to continue?"),                                       "Modifying the ownertrust has no effect on such keys.\n\n"
323                                       _("WinPT Warning"), MB_ICONWARNING|MB_YESNO );                                       "Do you really want to continue?"),
324                  if (rc == IDNO)                                       _("WinPT Warning"), MB_ICONWARNING|MB_YESNO );
325                      return TRUE;                  if (rc == IDNO)
326              }                      return TRUE;
327              //GetDlgItemText (dlg, IDC_KEYPROPS_OT, info, sizeof info -1);              }
328              dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,              //GetDlgItemText (dlg, IDC_KEYPROPS_OT, info, sizeof info -1);
329                                dlg, (DLGPROC)keyedit_ownertrust_dlg_proc,              dialog_box_param (glob_hinst, (LPCSTR)IDD_WINPT_KEYEDIT_OWNERTRUST,
330                                (LPARAM)k, _("Change Ownertrust"),                                dlg, (DLGPROC)keyedit_ownertrust_dlg_proc,
331                                IDS_WINPT_KEYEDIT_OWNERTRUST);                                (LPARAM)k, _("Change Ownertrust"),
332              if (k->callback.new_val == -1) { /* Cancel */                                IDS_WINPT_KEYEDIT_OWNERTRUST);
333                  EndDialog (dlg, FALSE);              if (k->callback.new_val == -1) { /* Cancel */
334                  break;                  EndDialog (dlg, FALSE);
335              }                  break;
336                }
337              inf = ownertrust_to_string (k->callback.new_val);  
338              do_change_ownertrust (k, inf);              inf = ownertrust_to_string (k->callback.new_val);
339              SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);              SetDlgItemText (dlg, IDC_KEYPROPS_OT, inf);
340              msg_box (dlg, _("Ownertrust successfully changed."),              msg_box (dlg, _("Ownertrust successfully changed."),
341                       _("GnuPG Status"), MB_OK);                       _("GnuPG Status"), MB_OK);
342                            
343              /* reload only the keylist */              /* XXX: modified ownertrust values can effect the entire
344              rcs.kr_reload = 1; rcs.kr_update = 1;                      WoT so we reload the cache. But this is very slow. */
345              rcs.tr_update = 0;              memset (&rcs, 0, sizeof (rcs));
346              DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_KEYCACHE, dlg,              rcs.kr_reload = 1; rcs.kr_update = 1; /* reload only keylist */
347                              keycache_dlg_proc, (LPARAM)&rcs);              DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_KEYCACHE, dlg,
348              return TRUE;                              keycache_dlg_proc, (LPARAM)&rcs);
349                            return TRUE;
350          case IDC_KEYPROPS_CHANGE_PWD:              
351              keyedit_change_passwd (k, dlg);                  case IDC_KEYPROPS_CHANGE_PWD:
352              return TRUE;              keyedit_change_passwd (k, dlg);        
353                return TRUE;
354          case IDC_KEYPROPS_REVOKERS:  
355              dialog_box_param (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKERS, dlg,          case IDC_KEYPROPS_REVOKERS:
356                                key_revokers_dlg_proc, (LPARAM)key, _("Key Revokers"),              dialog_box_param (glob_hinst, (LPCTSTR)IDD_WINPT_KEYREVOKERS, dlg,
357                                IDS_WINPT_KEY_REVOKERS);                                key_revokers_dlg_proc, (LPARAM)key,
358              break;                                _("Key Revokers"), IDS_WINPT_KEY_REVOKERS);
359          }              break;
360      }          }
361            }
362      return FALSE;      
363  }      return FALSE;
364    }

Legend:
Removed from v.33  
changed lines
  Added in v.41

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26