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

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26