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

Annotation of /trunk/Src/wptKeygenDlg.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 314 - (hide annotations)
Sun May 13 09:44:03 2007 UTC (17 years, 9 months ago) by twoaday
File size: 16525 byte(s)


1 werner 36 /* wptKeygenDlg.cpp - Key Generation dialog
2 twoaday 314 * Copyright (C) 2000-2007 Timo Schulz
3 werner 36 *
4     * This file is part of WinPT.
5     *
6     * 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
8     * the Free Software Foundation; either version 2 of the License, or
9     * (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
14     * GNU General Public License for more details.
15     */
16     #ifdef HAVE_CONFIG_H
17     #include <config.h>
18     #endif
19    
20     #include <windows.h>
21 twoaday 225 #include <time.h>
22 werner 36
23 werner 47 #include "resource.h"
24 werner 36 #include "wptTypes.h"
25     #include "wptNLS.h"
26     #include "wptGPG.h"
27     #include "wptCommonCtl.h"
28 twoaday 314 #include "wptContext.h"
29 werner 36 #include "wptDlgs.h"
30     #include "wptW32API.h"
31     #include "wptVersion.h"
32     #include "wptErrors.h"
33 twoaday 314 #include "StringBuffer.h"
34 werner 36
35 twoaday 204
36 werner 36 /* All valid key generation combination. */
37     enum gpg_keytype_t {
38     GPG_KEYGEN_NONE = 0,
39     GPG_KEYGEN_DSA_ELG = 1,
40     GPG_KEYGEN_DSA_RSA = 2,
41     GPG_KEYGEN_DSA_SIG = 3,
42     GPG_KEYGEN_RSA_SIG = 4,
43     GPG_KEYGEN_RSA = 5,
44     GPG_KEYGEN_RSA_RSA = 6 /*PGP*/
45     };
46    
47    
48     /* Generate the GPG specific genkey params with the given information.
49     @keytype: See valid combinations.
50     @bits: Length in bits.
51     @user: user-ID name
52     @comment: comment for the user-ID.
53     @email: email address.
54     @expdata: date of expiration or NULL.
55     @passphrase: the actual passphrase.
56     Return value: the gen. params. */
57     static char*
58 twoaday 314 gpg_genkey_params (int keytype, int bits,
59     const char *user, const char *comment, const char *email,
60     const char *expdate, const char *pass)
61 werner 36 {
62 twoaday 314 StringBuffer p;
63     char *param;
64    
65 werner 36 if (keytype == GPG_KEYGEN_NONE)
66     return NULL;
67    
68 twoaday 314 p = "<GnupgKeyParms format=\"internal\">\n";
69     /* In this phase we set the primary key information fields. */
70     switch (keytype) {
71     case GPG_KEYGEN_DSA_ELG:
72     case GPG_KEYGEN_DSA_RSA:
73     case GPG_KEYGEN_DSA_SIG:
74     p = p + "Key-Type: DSA\n";
75     p = p + "Key-Usage: sign\n";
76     p = p + "Key-Length: 1024\n";
77     break;
78    
79     case GPG_KEYGEN_RSA_SIG:
80     case GPG_KEYGEN_RSA:
81     case GPG_KEYGEN_RSA_RSA:
82     p = p + "Key-Type: RSA\n";
83     if (keytype == GPG_KEYGEN_RSA)
84     p = p + "Key-Usage: sign encrypt\n";
85     else
86     p = p + "Key-Usage: sign\n";
87     p = p + "Key-Length: " + (int)bits + "\n";
88     break;
89    
90     default:
91     break;
92 werner 36 }
93    
94 twoaday 314 /* The next phase is the subkey information if needed. */
95     if (keytype == GPG_KEYGEN_DSA_ELG || keytype == GPG_KEYGEN_DSA_RSA ||
96     keytype == GPG_KEYGEN_RSA_RSA) {
97     if (keytype == GPG_KEYGEN_DSA_ELG)
98     p = p + "Subkey-Type: ELG-E\n";
99     else if (keytype == GPG_KEYGEN_DSA_RSA || keytype == GPG_KEYGEN_RSA_RSA)
100     p = p + "Subkey-Type: RSA\n";
101     p = p + "Subkey-Usage: encrypt\n";
102     p = p + "Subkey-Length: " + (int)bits + "\n";
103 werner 36 }
104 twoaday 314
105     /* Followed by the user ID information. */
106     p = p + "Name-Real: " + user + "\n";
107     if (comment != NULL)
108     p = p + "Name-Comment: " + comment + "\n";
109     p = p + "Name-Email: " + email + "\n";
110    
111     if (expdate != NULL)
112     p = p + "Expire-Date: " + expdate + "\n";
113     else
114     p = p + "Expire-Date: 0\n";
115     p = p + "Passphrase: " + pass + "\n";
116    
117     p = p + "</GnupgKeyParms>\n";
118     param = p.getBufferCopy ();
119     p.wipeContents ();
120    
121     return param;
122 twoaday 32 }
123 werner 36
124    
125     /* Generate a key with the given params @params. @prog_cb is a user defined
126     progress callback which is called during the generation.
127     @fpr will store the fingerprint of the generated key.
128     Return value: 0 on success. */
129     gpgme_error_t
130     gpg_genkey (const char *params, gpgme_progress_cb_t prog_cb, char **fpr)
131     {
132 twoaday 278 gpgme_error_t err;
133 werner 36 gpgme_ctx_t ctx;
134     gpgme_genkey_result_t res;
135    
136     err = gpgme_new(&ctx);
137     if (err)
138     return err;
139     if (prog_cb)
140     gpgme_set_progress_cb (ctx, prog_cb, NULL);
141     err = gpgme_op_genkey (ctx, params, NULL, NULL);
142     if (!err) {
143     res = gpgme_op_genkey_result (ctx);
144 twoaday 225 *fpr = res && res->fpr? m_strdup (res->fpr) : NULL;
145 werner 36 }
146     gpgme_release (ctx);
147     return err;
148     }
149    
150    
151    
152 twoaday 314 /* Reset all dialog fields to its initial value. */
153 werner 36 static void
154 twoaday 314 reset_dlg_fields (HWND dlg)
155 werner 36 {
156     SetDlgItemText (dlg, IDC_KEYGEN_SUBKEYBITS, "");
157     SetDlgItemText (dlg, IDC_KEYGEN_NAME, "");
158     SetDlgItemText (dlg, IDC_KEYGEN_EMAIL, "");
159     SetDlgItemText (dlg, IDC_KEYGEN_COMMENT, "");
160     SetDlgItemText (dlg, IDC_KEYGEN_EXPDATE, "");
161     }
162    
163    
164     /* Ask the user if a keyring backup is wanted and if so,
165 twoaday 314 backup both keyrings to the selected folder.
166     Return value: true on success. */
167     static bool
168 werner 36 backup_keyrings (HWND dlg)
169     {
170 twoaday 130 const char *name;
171 twoaday 314 char *keyring;
172     char *path;
173     bool success = true;
174 werner 36 int id;
175 twoaday 314
176 werner 36 id = msg_box (dlg,
177     _("It is STRONGLY recommend that you backup your keyrings because they both "
178     "contain VERY important data.\nRemember that your hard disk can crash or the "
179     "files can be deleted by accident; so it is a good\nidea to store them on "
180     "a different mass stoarge like a floppy or CDR!\n\n"
181     "Backup your keyrings now?"),
182     _("WARNING - Important hint" ), MB_YESNO);
183 twoaday 314 if (id != IDYES)
184     return false;
185    
186     path = get_gnupg_path ();
187     name = get_filesave_dlg (dlg, _("Destination for Public Keyring"),
188     NULL, "pubring_bak.gpg");
189     if (name != NULL) {
190     keyring = make_filename (path, "pubring", "gpg");
191     if (!CopyFile (keyring, name, FALSE)) {
192     log_box (_("Key Generation"), MB_ERR,
193     _("Could not copy %s -> %s"), keyring, name);
194     success = false;
195     }
196     free_if_alloc (keyring);
197     }
198    
199     name = get_filesave_dlg (dlg, _("Destination for Secret Keyring"),
200     NULL, "secring_bak.gpg");
201     if (name != NULL) {
202     keyring = make_filename (path, "secring", "gpg");
203     if (!CopyFile (keyring, name, FALSE)) {
204     log_box (_("Key Generation"), MB_ERR,
205 twoaday 130 _("Could not copy %s -> %s"), keyring, name);
206 twoaday 314 success = false;
207     }
208     free_if_alloc (keyring);
209 werner 36 }
210 twoaday 130 free_if_alloc (path);
211 twoaday 314 return success;
212 werner 36 }
213    
214    
215     /* Fill in all valid GPG algorithms. */
216     static void
217     fill_keytype_box (HWND dlg)
218     {
219 twoaday 130 HWND cb = GetDlgItem (dlg, IDC_KEYGEN_KEYTYPE);
220 werner 36
221 twoaday 130 #define addstr(cb, str) \
222     SendMessage ((cb), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)(str))
223     addstr (cb, _("DSA and ELG (default)"));
224     addstr (cb, _("DSA and RSA"));
225     addstr (cb, _("DSA sign only"));
226     addstr (cb, _("RSA sign only"));
227     addstr (cb, _("RSA sign and encrypt"));
228     addstr (cb, _("RSA and RSA (PGP)") );
229     SendMessage (cb, CB_SETCURSEL, 0, 0);
230 werner 36 #undef addstr
231     }
232    
233    
234 twoaday 225 time_t w32_mktime (SYSTEMTIME *st);
235    
236 werner 36 /* Check that the given date lies not in the past.
237     Return value: 1 on success. */
238     int
239     keygen_check_date (SYSTEMTIME *st)
240     {
241 twoaday 225 time_t dat, now;
242 werner 36
243 twoaday 225 dat = w32_mktime (st);
244     now = time (NULL);
245     if (dat >= now)
246 werner 36 return 1;
247 twoaday 225 return 0;
248 werner 36 }
249    
250    
251     /* Dialog box procedure for key generation. */
252     BOOL CALLBACK
253     keygen_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
254     {
255     static genkey_s *ctx;
256     SYSTEMTIME st;
257     gpgme_error_t err;
258 twoaday 204 char *utf8_name =NULL, *utf8_comment = NULL;
259 twoaday 314 char email[128], t[64];
260 twoaday 130 char *pwd;
261 twoaday 314 char *expire = NULL, *fpr=NULL;
262 twoaday 130 int bits, use_comment, keytype = 0;
263     int cancel = 0;
264     char *p;
265 werner 36
266 twoaday 225 switch (msg) {
267 werner 36 case WM_INITDIALOG:
268 twoaday 73 if (lparam != 0)
269 werner 36 ctx = (genkey_s *)lparam;
270 twoaday 130 SetWindowText (dlg, _("Key Generation"));
271     SetDlgItemText(dlg, IDC_KEYGEN_INFO,
272 werner 36 _("NOTE: Key generation can be a lengthy process! Please wait until "
273 twoaday 248 "you get the message that key generation has finished."));
274 twoaday 130 SetDlgItemText (dlg, IDC_KEYGEN_SUBKEYINF, _("Subkey size in &bits"));
275     SetDlgItemText (dlg, IDC_KEYGEN_NAMEINF, _("&Real name"));
276     SetDlgItemText (dlg, IDC_KEYGEN_COMMINF, _("&Comment (optional)"));
277     SetDlgItemText (dlg, IDC_KEYGEN_EMAILINF, _("Email &address"));
278     SetDlgItemText (dlg, IDC_KEYGEN_EXPINF, _("&Expire date"));
279     SetDlgItemText (dlg, IDC_KEYGEN_KEYTYPEINF, _("Key &type"));
280 werner 36 SetDlgItemText (dlg, IDC_KEYGEN_EXPNEVER, _("&Never"));
281 twoaday 101 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
282 werner 36
283 twoaday 130 SetDlgItemInt (dlg, IDC_KEYGEN_SUBKEYBITS, DFAULT_KEYSIZE, FALSE);
284 werner 36 CheckDlgButton (dlg, IDC_KEYGEN_HIDEPWD, BST_CHECKED);
285     CheckDlgButton (dlg, IDC_KEYGEN_EXPNEVER, BST_CHECKED);
286     EnableWindow (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE), FALSE);
287     fill_keytype_box (dlg);
288     center_window (dlg, NULL);
289     SetForegroundWindow (dlg);
290     return TRUE;
291    
292     case WM_COMMAND:
293 twoaday 248 if (HIWORD (wparam) == CBN_SELCHANGE &&
294     LOWORD (wparam) == IDC_KEYGEN_KEYTYPE) {
295     keytype = SendMessage ((HWND)lparam, CB_GETCURSEL, 0, 0);
296    
297     if (keytype == GPG_KEYGEN_DSA_SIG-1)
298     bits = 1024;
299     else
300     bits = DFAULT_KEYSIZE;
301     SetDlgItemInt (dlg, IDC_KEYGEN_SUBKEYBITS, bits, FALSE);
302     }
303    
304 werner 36 if (HIWORD (wparam) == BN_CLICKED &&
305     LOWORD (wparam) == IDC_KEYGEN_EXPNEVER) {
306     int never = IsDlgButtonChecked (dlg, IDC_KEYGEN_EXPNEVER);
307     EnableWindow (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE), !never);
308     }
309    
310 twoaday 130 switch (LOWORD (wparam)) {
311 werner 36 case IDOK:
312     bits = GetDlgItemInt (dlg, IDC_KEYGEN_SUBKEYBITS, NULL, FALSE);
313     if (bits < 1024 || bits > 4096) {
314     msg_box (dlg, _("Invalid value. Allowed values 1024-4096 bits."),
315     _("Key Generation"), MB_ERR);
316     return FALSE;
317     }
318     if (bits > DFAULT_KEYSIZE) {
319 twoaday 130 int id = msg_box (dlg, _("Do you really need such a large key?"),
320 werner 36 _("Key Generation"), MB_YESNO);
321     if (id == IDNO)
322     bits = DFAULT_KEYSIZE;
323     }
324 twoaday 204 if (!GetDlgItemText_utf8 (dlg, IDC_KEYGEN_NAME, &utf8_name)) {
325     msg_box (dlg, _("Please enter the name."), _("Key Generation"), MB_ERR);
326 werner 36 return FALSE;
327     }
328 twoaday 204 if (strchr (utf8_name, '@')) {
329 werner 36 msg_box (dlg, _("Please do not enter the email address in the name field."),
330     _("Key Generation"), MB_INFO);
331 twoaday 204 free_if_alloc (utf8_name);
332 werner 36 return FALSE;
333     }
334 twoaday 314 if (!GetDlgItemText (dlg, IDC_KEYGEN_EMAIL, email, DIM (email) -1)
335 twoaday 190 || check_email_address (email)) {
336 twoaday 130 msg_box (dlg, _("Please enter a valid email address."),
337     _("Key Generation"), MB_ERR);
338 twoaday 204 free_if_alloc (utf8_name);
339 werner 36 return FALSE;
340     }
341 twoaday 204 use_comment = GetDlgItemText_utf8 (dlg, IDC_KEYGEN_COMMENT,
342     &utf8_comment);
343     if (use_comment > 0 && strchr (utf8_comment, '@')) {
344 twoaday 130 msg_box (dlg, _("Please do NOT enter the email address in the comment field."),
345     _("Key Generation"), MB_INFO);
346 twoaday 204 free_if_alloc (utf8_name);
347     free_if_alloc (utf8_comment);
348 twoaday 225 return TRUE;
349 werner 36 }
350     keytype = SendDlgItemMessage (dlg, IDC_KEYGEN_KEYTYPE, CB_GETCURSEL, 0, 0) + 1;
351     if (IsDlgButtonChecked (dlg, IDC_KEYGEN_EXPNEVER))
352     expire = NULL;
353     else {
354     DateTime_GetSystemtime (GetDlgItem (dlg, IDC_KEYGEN_EXPDATE), &st);
355 twoaday 225 if (!keygen_check_date (&st)) {
356     free_if_alloc (utf8_name);
357     free_if_alloc (utf8_comment);
358 twoaday 248 msg_box (dlg, _("The date you have chosen has already passed."),
359 twoaday 225 _("Key Generation"), MB_ERR);
360     return TRUE;
361     }
362 werner 36 _snprintf (t, DIM (t)-1, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay);
363     expire = t;
364     }
365 twoaday 130
366 twoaday 314 /* We don't allow empty passphrases during key generation. */
367 twoaday 229 pwd = request_passphrase2 (_("Key Generation"),
368 twoaday 314 PASSDLG_STRICT|PASSDLG_WARN_UTF8|PASSDLG_NOTEMPTY, &cancel);
369 twoaday 130 if (cancel) {
370     sfree_if_alloc (pwd);
371 twoaday 204 free_if_alloc (utf8_name);
372     free_if_alloc (utf8_comment);
373 twoaday 130 return FALSE;
374     }
375     if (!pwd) {
376     msg_box (dlg, _("Please enter the passphrase."),
377     _("Key Generation"), MB_ERR);
378 twoaday 204 free_if_alloc (utf8_name);
379     free_if_alloc (utf8_comment);
380 werner 36 return FALSE;
381     }
382 twoaday 130
383 twoaday 314 p = gpg_genkey_params (keytype, bits, utf8_name,
384     !use_comment && !utf8_comment? NULL :utf8_comment,
385     email, expire, pwd);
386 twoaday 204 free_if_alloc (utf8_name);
387     free_if_alloc (utf8_comment);
388 twoaday 130 keygen_cb_dlg_create ();
389 werner 36 err = gpg_genkey (p, keygen_cb, &fpr);
390 twoaday 130 sfree_if_alloc (pwd);
391 twoaday 314 sfree_if_alloc (p); /* burn the passphrase */
392 twoaday 211 keygen_cb_dlg_destroy (1);
393 twoaday 115 if (err) {
394 twoaday 201 free_if_alloc (fpr);
395 twoaday 115 msg_box (dlg, gpgme_strerror (err), _("Key Generation"), MB_ERR);
396 werner 36 return FALSE;
397     }
398 twoaday 115 status_box (dlg, _("Key Generation completed"), _("GnuPG Status"));
399 werner 36
400     keycache_update (0, fpr);
401     keycache_update (1, fpr);
402 twoaday 201 free_if_alloc (fpr);
403 werner 36
404 twoaday 314 reset_dlg_fields (dlg);
405 werner 36 backup_keyrings (dlg);
406 twoaday 150 if (ctx)
407     ctx->cancel = 0;
408 werner 36 EndDialog (dlg, TRUE);
409     return TRUE;
410    
411     case IDCANCEL:
412 twoaday 150 if (ctx)
413     ctx->cancel = 1;
414     EndDialog (dlg, FALSE);
415 werner 36 return FALSE;
416     }
417     break;
418     }
419    
420     return FALSE;
421     }
422    
423    
424 twoaday 234 /* Wizard like keygen dialog for novice users. */
425 werner 36 BOOL CALLBACK
426     keygen_wizard_dlg_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
427     {
428     static genkey_s *ctx;
429     static int pubkey_algo = GPG_KEYGEN_DSA_ELG;
430     gpgme_error_t err;
431 twoaday 204 char email[128];
432 twoaday 234 char *utf8_name=NULL, *p, *fpr=NULL;
433     char *pass = NULL;
434 werner 36 int cancel = 0;
435    
436 twoaday 234 switch (msg) {
437 werner 36 case WM_INITDIALOG:
438     ctx = (genkey_s *)lparam;
439     SetDlgItemText (dlg, IDC_KEYWIZARD_USERSA, _("&Prefer RSA keys"));
440     SetDlgItemText (dlg, IDC_KEYWIZARD_NAMEINF, _("Real name:"));
441     SetDlgItemText (dlg, IDC_KEYWIZARD_EMAILINF, _("Email address:"));
442     SetDlgItemText (dlg, IDC_KEYWIZARD_TITLEINF, _("Name and E-Mail Assignment"));
443 twoaday 234 SetDlgItemText (dlg, IDC_KEYWIZARD_TEXT1INF, _("Every key pair must have a name associated with it. The name and\nemail address let your correspondents know that your public key they\nare using belongs to us."));
444 twoaday 229 SetDlgItemText (dlg, IDC_KEYWIZARD_TEXT2INF, _("By associating an email address with your key pair, you will enable WinPT to assist your correspondents in selecting the correct public\nkey when communicating with you."));
445 werner 36 SetWindowText (dlg, _("Key Generation Wizard"));
446 twoaday 105 SetDlgItemText (dlg, IDCANCEL, _("&Cancel"));
447 werner 36 SetForegroundWindow (dlg);
448     center_window (dlg, NULL);
449     break;
450    
451     case WM_COMMAND:
452 twoaday 204 switch (LOWORD( wparam)) {
453 werner 36 case IDOK:
454 twoaday 204 if (!GetDlgItemText_utf8 (dlg, IDC_KEYWIZARD_NAME, &utf8_name)) {
455     msg_box (dlg, _("Please enter the name."),
456     _("Key Generation Wizard"), MB_ERR);
457 werner 36 return FALSE;
458     }
459 twoaday 204 if (strchr (utf8_name, '@')) {
460 werner 36 msg_box (dlg, _("Please do not enter the email address in the name field."),
461     _("Key Generation Wizard"), MB_WARN);
462 twoaday 204 free_if_alloc (utf8_name);
463 werner 36 return FALSE;
464     }
465 twoaday 314 if (!GetDlgItemText (dlg, IDC_KEYWIZARD_EMAIL, email, DIM (email)-1)
466 twoaday 190 || check_email_address (email)) {
467     msg_box (dlg, _("Please enter a valid email address."),
468     _("Key Generation Wizard"), MB_ERR);
469 twoaday 204 free_if_alloc (utf8_name);
470 werner 36 return FALSE;
471     }
472     if (strchr (email, '<') || strchr (email, '>')) {
473     msg_box (dlg, _("Please do not add '<' or '>' to the email address."),
474     _("Key Generation Wizard"), MB_WARN);
475 twoaday 204 free_if_alloc (utf8_name);
476 werner 36 return FALSE;
477     }
478 twoaday 314
479     /* We don't allow empty passphrases during key generation. */
480     pass = request_passphrase2 (_("Key Generation"),
481     PASSDLG_STRICT|PASSDLG_WARN_UTF8|PASSDLG_NOTEMPTY, &cancel);
482 twoaday 204 if (cancel) {
483     free_if_alloc (utf8_name);
484 werner 36 return FALSE;
485 twoaday 204 }
486 werner 36 if (IsDlgButtonChecked (dlg, IDC_KEYWIZARD_USERSA))
487     pubkey_algo = GPG_KEYGEN_DSA_RSA;
488     p = gpg_genkey_params (pubkey_algo, DFAULT_KEYSIZE, utf8_name,
489 twoaday 314 NULL, email, NULL, pass);
490 twoaday 201 free_if_alloc (utf8_name);
491 werner 36 keygen_cb_dlg_create();
492     err = gpg_genkey (p, keygen_cb, &fpr);
493 twoaday 211 keygen_cb_dlg_destroy (1);
494 twoaday 225 sfree_if_alloc (p);
495 werner 36 sfree_if_alloc (pass);
496 twoaday 201 if (err) {
497 twoaday 314 msg_box (dlg, gpgme_strerror (err),
498     _("Key Generation Wizard"), MB_ERR);
499 twoaday 201 free_if_alloc (fpr);
500 werner 36 return FALSE;
501     }
502 twoaday 204 status_box (dlg, _("Key Generation completed"), _("GnuPG Status"));
503 werner 36 keycache_update (0, fpr);
504     keycache_update (1, fpr);
505 twoaday 201 free_if_alloc (fpr);
506 twoaday 150
507 werner 36 backup_keyrings (dlg);
508 twoaday 314 if (ctx != NULL)
509 twoaday 256 ctx->cancel = 0;
510 werner 36 EndDialog (dlg, TRUE);
511     break;
512    
513     case IDCANCEL:
514 twoaday 314 if (ctx != NULL)
515 twoaday 150 ctx->cancel = 1;
516     EndDialog (dlg, FALSE);
517 werner 36 break;
518     }
519     break;
520     }
521     return FALSE;
522     }

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26