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

Annotation of /trunk/Src/wptClipboard.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 465 - (hide annotations)
Tue Oct 9 09:28:15 2012 UTC (12 years, 4 months ago) by twoaday
File size: 12791 byte(s)


1 twoaday 273 /* wptClipboard.cpp - GPG related clipboard functions
2 twoaday 328 * Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Timo Schulz
3 twoaday 121 * Copyright (C) 2005 g10 Code GmbH
4     *
5     * This file is part of WinPT.
6     *
7     * WinPT is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * WinPT is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     */
17    
18     #ifdef HAVE_CONFIG_H
19     #include <config.h>
20     #endif
21    
22     #include <windows.h>
23     #include <gpgme.h>
24    
25     #include "wptW32API.h"
26     #include "wptCrypto.h"
27     #include "wptVersion.h"
28     #include "wptGPG.h"
29 twoaday 271 #include "wptTypes.h"
30 twoaday 328 #include "wptUTF8.h"
31 twoaday 462 #include "wptErrors.h"
32 twoaday 121
33 twoaday 271 /* Default buffer size. */
34     #define BUFSIZE 192
35    
36 twoaday 121 gpgme_error_t gpg_data_wrap_lines (gpgme_data_t *r_dh, size_t wraplen);
37    
38     /* XXX: define clipboard errors. */
39    
40     /* Check if the clipboard contains text. @r_val contains
41     one text data is available.
42     Return value: 0 on success. */
43     gpgme_error_t
44     gpg_clip_istext_avail (int *r_val)
45     {
46     HANDLE clipmem;
47     char *clipdata;
48    
49     if (!r_val)
50     return gpg_error (GPG_ERR_INV_ARG);
51 twoaday 328 *r_val = 0;
52 twoaday 121 if (OpenClipboard (NULL) == FALSE)
53 twoaday 328 return gpg_error (GPG_ERR_INTERNAL);
54 twoaday 121
55     clipmem = GetClipboardData (CF_TEXT);
56 twoaday 328 if (!clipmem) {
57     CloseClipboard();
58     return gpg_error (GPG_ERR_NO_DATA);
59     }
60 twoaday 121
61     clipdata = (char *) GlobalLock (clipmem);
62 twoaday 328 if (!clipdata) {
63     CloseClipboard ();
64     return gpg_error (GPG_ERR_INTERNAL);
65     }
66    
67 twoaday 121 if (strlen (clipdata) > 0)
68     *r_val = 1;
69     GlobalUnlock (clipmem);
70     CloseClipboard ();
71     return 0;
72     }
73    
74    
75     /* Figure out what kind of PGP data is stored in @data.
76     @r_type contains the ORed types on success.
77     Return value: 0 on success. */
78     gpgme_error_t
79     gpg_clip_parse_pgpid (const char *data, int *r_type)
80     {
81     int type;
82    
83     if (!data)
84     return gpg_error (GPG_ERR_INV_ARG);
85     if (strlen (data) < 19) {
86     *r_type = 0;
87     return 0;
88     }
89     type = 0;
90 twoaday 328 if (strstr (data, "BEGIN PGP MESSAGE"))
91 twoaday 121 type |= PGP_MESSAGE;
92     if (strstr (data, "BEGIN PGP SIGNED MESSAGE"))
93     type |= PGP_CLEARSIG;
94     if (strstr (data, "BEGIN PGP SIGNATURE"))
95     type |= PGP_SIG;
96     if (strstr (data, "BEGIN PGP PUBLIC KEY BLOCK"))
97     type |= PGP_PUBKEY;
98 twoaday 226 if (strstr (data, "BEGIN PGP PRIVATE KEY BLOCK") ||
99     strstr (data, "BEGIN PGP SECRET KEY BLOCK"))
100 twoaday 121 type |= PGP_SECKEY;
101 twoaday 328 // Actually this is no type but rather a flag to
102     // indicate the that the data is 'dash escaped'
103 twoaday 121 if (strstr (data, "- -----BEGIN"))
104     type |= PGP_DASH_ESCAPED;
105     *r_type = type;
106     return 0;
107     }
108    
109    
110     /* Check if the clipboard is already OpenPGP protected.
111     @r_type optional returns the type and @r_val contains
112     1 for yes.
113     Return value: 0 on success. */
114     gpgme_error_t
115     gpg_clip_is_secured (int *r_type, int *r_val)
116     {
117     HANDLE clipmem;
118     char *clipdata;
119    
120     if (!r_val)
121     return gpg_error (GPG_ERR_INV_ARG);
122 twoaday 271 if (OpenClipboard (NULL) == FALSE)
123 twoaday 121 return gpg_error (GPG_ERR_INTERNAL);
124 twoaday 271 clipmem = GetClipboardData (CF_TEXT);
125     if (!clipmem) {
126 twoaday 121 *r_val = 0;
127 twoaday 328 CloseClipboard();
128     return gpg_error (GPG_ERR_NO_DATA);
129 twoaday 121 }
130 twoaday 271 clipdata = (char *) GlobalLock (clipmem);
131 twoaday 121 if (!clipdata) {
132 twoaday 328 *r_val = 0;
133     CloseClipboard();
134     return gpg_error (GPG_ERR_INTERNAL);
135 twoaday 121 }
136 twoaday 328 if (strlen (clipdata) > 32 &&
137     strstr (clipdata, "-----BEGIN PGP") &&
138     strstr (clipdata, "-----END PGP"))
139 twoaday 121 *r_val = 1;
140     GlobalUnlock (clipmem);
141     gpg_clip_parse_pgpid (clipdata, r_type);
142     CloseClipboard ();
143 twoaday 328 return gpg_error (GPG_ERR_NO_ERROR);
144 twoaday 121 }
145    
146    
147 twoaday 271 /* Return the OpenPGP data format of the clipboard in @r_type.
148     Return 0 on success. */
149 twoaday 121 gpgme_error_t
150     gpg_clip_get_pgptype (int *r_type)
151     {
152     HANDLE clipmem;
153     char *clipdata;
154    
155     if (OpenClipboard (NULL) == FALSE)
156     return gpg_error (GPG_ERR_INTERNAL);
157     clipmem = GetClipboardData (CF_TEXT);
158     if (!clipmem) {
159 twoaday 328 CloseClipboard ();
160     return gpg_error (GPG_ERR_NO_DATA);
161 twoaday 121 }
162 twoaday 328 clipdata = (char *)GlobalLock (clipmem);
163 twoaday 121 if (!clipdata) {
164 twoaday 328 CloseClipboard ();
165     return gpg_error (GPG_ERR_INTERNAL);
166 twoaday 121 }
167     gpg_clip_parse_pgpid (clipdata, r_type);
168     GlobalUnlock (clipmem);
169     CloseClipboard ();
170 twoaday 328 return gpg_error (GPG_ERR_NO_ERROR);
171 twoaday 121 }
172    
173    
174 twoaday 319 /* Retrieve the text of the clipboard.
175 twoaday 121 Return value: the text as a string, NULL otherwise. */
176     static char*
177     get_w32_clip_text (void)
178     {
179 twoaday 328 char *private_clip;
180     char *clip;
181 twoaday 121 size_t size;
182     HANDLE cb;
183    
184     if (!OpenClipboard (NULL))
185     return NULL;
186     cb = GetClipboardData (CF_TEXT);
187 twoaday 328 if (!cb) {
188     CloseClipboard ();
189     return NULL;
190     }
191 twoaday 121 private_clip = (char *)GlobalLock (cb);
192 twoaday 328 if (!private_clip) {
193     CloseClipboard ();
194     return NULL;
195     }
196 twoaday 121 size = strlen (private_clip);
197 twoaday 328 clip = new char[size+1];
198     if (!clip)
199     BUG (NULL);
200     memset (clip, 0, size+1);
201 twoaday 121 memcpy (clip, private_clip, size);
202     GlobalUnlock(cb);
203     CloseClipboard ();
204     return clip;
205     }
206    
207    
208 twoaday 465 static gpgme_error_t
209 twoaday 462 set_clip_text(wchar_t *data, size_t size)
210     {
211 twoaday 465 if (!OpenClipboard(NULL))
212     return gpg_error(GPG_ERR_INTERNAL);
213    
214     HANDLE cb = GlobalAlloc(GHND, size * sizeof(wchar_t));
215 twoaday 462 wchar_t *ptr = (wchar_t*)GlobalLock(cb);
216 twoaday 465 if (ptr != NULL) {
217     EmptyClipboard();
218     memcpy(ptr, data, size * sizeof(wchar_t));
219     SetClipboardData(CF_UNICODETEXT, cb);
220     GlobalUnlock(ptr);
221     }
222 twoaday 462 CloseClipboard();
223     GlobalFree(cb);
224 twoaday 465 return gpg_error(GPG_ERR_NO_ERROR);
225 twoaday 462 }
226    
227    
228 twoaday 121 /* Set the new clipboard data to @data. */
229 twoaday 465 static gpgme_error_t
230 twoaday 121 set_w32_clip_text (const char *data, int size)
231     {
232     HANDLE cb;
233     char *private_data;
234    
235     if (!OpenClipboard(NULL))
236 twoaday 465 return gpg_error(GPG_ERR_INTERNAL);
237 twoaday 121 cb = GlobalAlloc (GHND, size+1);
238     if (!cb)
239 twoaday 328 BUG (NULL);
240 twoaday 121 private_data = (char*)GlobalLock (cb);
241 twoaday 328 if (private_data != NULL) {
242     EmptyClipboard ();
243     memset (private_data, 0, size+1);
244     memcpy (private_data, data, size);
245     SetClipboardData (CF_TEXT, cb);
246     GlobalUnlock (cb);
247     }
248 twoaday 121
249     CloseClipboard ();
250     GlobalFree (cb);
251 twoaday 465 return gpg_error(GPG_ERR_NO_ERROR);
252 twoaday 121 }
253    
254    
255     /* Search for the armor header 'Version:' in @r_dh and
256     add the WinPT version. On success @r_dh is replaced
257     with the modified data.
258     Return value: 0 on success. */
259 twoaday 462 gpgme_error_t
260 twoaday 121 gpg_data_change_version (gpgme_data_t *r_dh)
261     {
262 twoaday 271 gpgme_error_t err;
263 twoaday 121 gpgme_data_t mdh;
264 twoaday 271 const char *s;
265 twoaday 328 char line[BUFSIZE+256];
266     int found_version, hash_seen;
267 twoaday 121 int n;
268    
269     if (!r_dh)
270     return gpg_error (GPG_ERR_INV_ARG);
271    
272     err = gpgme_data_new (&mdh);
273     if (err)
274     return err;
275 twoaday 328
276     found_version = 0;
277     hash_seen = 0;
278 twoaday 271 /* Pattern we search for. */
279     s = "Version: GnuPG";
280 twoaday 121 gpgme_data_rewind (*r_dh);
281 twoaday 328 while ((n = gpg_data_readline (*r_dh, line, BUFSIZE-1)) > 0) {
282     if (found_version == 0 && !strncmp (line, "Hash:", 5)) {
283     // If we found a cleartext signature, we do not add a
284     // charset header in the signed area since it would broke
285     // the signature
286     hash_seen = 1;
287     }
288    
289     if (!strncmp (line, "\r\n", 2) && found_version == 0 &&
290     hash_seen == 0) {
291     // If the user decided she will not tell what client she
292     // used, we will also omit the version and just output
293     // the charset info
294     line[strlen (line)- 2]=0;
295     strcat (line, /*"Version: WinPT "PGM_VERSION"\r\n"*/
296     "Charset: UTF-8\r\n"
297     "\r\n");
298     found_version = 1;
299     }
300 twoaday 271 if (strlen (line) > strlen (s) &&
301     !strncmp (line, s, strlen (s)) &&
302     !stristr (line, "WinPT "PGM_VERSION)) {
303     /* Do not assume a \r\n sequence. */
304     if (strstr (line, "\r\n"))
305     line[strlen (line) - 2] = '\0';
306     if (strstr (line, "\n"))
307 twoaday 328 line[strlen (line) - 1] = '\0';
308     // We add a charset header to indicate that the application
309     // on the recipients side is able to properly decode it
310     strcat (line, " - WinPT "PGM_VERSION"\r\n"
311     "Charset: UTF-8\r\n");
312     found_version = 1;
313 twoaday 121 }
314     gpgme_data_write (mdh, line, strlen (line));
315     }
316    
317     gpgme_data_write (mdh, "", 1);
318     gpgme_data_rewind (mdh);
319     gpgme_data_release (*r_dh);
320     *r_dh = mdh;
321     return err;
322     }
323    
324 twoaday 328
325     /* The problem is, that it might be also possible that we
326     received an ciphertext which is not encoded with UTF-8.
327     Thus, we check explicitly for the 'Charset: UTF-8' header.
328     If it is not found, we assume a different encoding and
329     no decoding is performed. */
330     static int
331     has_utf8_charset (gpgme_data_t dh)
332     {
333     char buf[BUFSIZE+1];
334     int found = 0;
335    
336     for (;;) {
337     int n = gpg_data_readline (dh, buf, BUFSIZE);
338     if (n < 1)
339     break;
340     // Read until the first blank line, if the
341     // header has not been found yet, it does not exist
342     if ((n == 1 && buf[0] == '\n') ||
343     (n == 2 && buf[0] == '\r'))
344     break;
345     if (!memcmp (buf, "Charset:", 8) && strstr (buf, "UTF-8")) {
346     found = 1;
347     break;
348     }
349     }
350 twoaday 462
351 twoaday 328 gpgme_data_rewind (dh);
352     return found;
353     }
354    
355    
356     /* Retrieve the clipboard data and create a new gpgme
357     data object @r_dh and return it. If @wraplen is > 0
358     wrap lines of the buffer.
359     Return value: 0 on success. */
360     gpgme_error_t
361     gpg_data_new_from_clipboard (gpgme_data_t *r_dh, int wraplen)
362     {
363 twoaday 462 gpgme_error_t err;
364 twoaday 328 gpgme_data_t dh;
365     char *clip_text = NULL;
366    
367     if (!r_dh)
368     return gpg_error (GPG_ERR_INV_ARG);
369     *r_dh = NULL;
370     clip_text = get_w32_clip_text ();
371     if (!clip_text)
372     return gpg_error (GPG_ERR_NO_DATA);
373     err = gpgme_data_new_from_mem (&dh, clip_text, strlen (clip_text), 1);
374     if (clip_text)
375     free (clip_text);
376     if (wraplen > 0)
377     gpg_data_wrap_lines (&dh, wraplen);
378    
379     *r_dh = dh;
380     return err;
381     }
382    
383     /* Retrieve the clipboard data and create a new gpgme
384     data object @r_dh and return it. If @wraplen is > 0
385     wrap lines of the buffer.
386     Return value: 0 on success. */
387     gpgme_error_t
388     gpg_data_utf8_new_from_clipboard (gpgme_data_t *r_dh,
389     int wraplen, int *r_is_utf8)
390     {
391     gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
392     gpgme_data_t dh;
393     char *clip_text, *utf8_text;
394    
395     if (!r_dh)
396     return gpg_error (GPG_ERR_INV_ARG);
397     *r_dh = NULL;
398     clip_text = get_w32_clip_text ();
399     if (!clip_text)
400     return gpg_error (GPG_ERR_NO_DATA);
401    
402    
403     /* We automatically encode all clipboard data
404     into the UTF-8 format for a portable transportation. */
405     utf8_text = native_to_utf8 (clip_text);
406     free_if_alloc (clip_text); clip_text = utf8_text;
407    
408     err = gpgme_data_new_from_mem (&dh, clip_text, strlen (clip_text), 1);
409     free_if_alloc (clip_text);
410     if (wraplen > 0)
411     gpg_data_wrap_lines (&dh, wraplen);
412    
413     // for ARMORED data find out if the Charset header is set to UTF8
414     if (r_is_utf8)
415     *r_is_utf8 = has_utf8_charset (dh);
416    
417     *r_dh = dh;
418     return err;
419     }
420    
421    
422    
423 twoaday 462 wchar_t* utf8_to_utf16(const char *string, size_t *retlen);
424    
425 twoaday 328 gpgme_error_t
426     gpg_data_release_utf8_to_clipboard (gpgme_data_t dh)
427     {
428 twoaday 462 //char *clip_text;
429     char *utf8_text;
430 twoaday 328 size_t n;
431    
432     if (!dh)
433     return gpg_error (GPG_ERR_INV_ARG);
434    
435     gpgme_data_write (dh, "", 1); // make sure it's a string!
436     utf8_text = gpgme_data_release_and_get_mem (dh, &n);
437     if (!utf8_text)
438     return gpg_error (GPG_ERR_INV_VALUE);
439     if (n < 0) {
440     gpgme_free (utf8_text);
441     return gpg_error (GPG_ERR_NO_DATA);
442     }
443    
444     /* We assume that all data from GPG is in UTF-8 and
445     need to be decoded. If the charset is US-ASCII,
446     this wouldn't do any harm, but if the data is ISO-XXX-XX
447     we get scrambled output. */
448     utf8_text[n] = '\0';
449 twoaday 462
450     size_t nlen = 0;
451     wchar_t *dat = utf8_to_utf16(utf8_text, &nlen);
452     set_clip_text(dat, nlen);
453     wipememory(dat, nlen);
454     free_if_alloc(dat);
455    
456     #if 0 /* old utf8 code */
457     clip_text = utf8_to_native (utf8_text);
458     n = strlen(clip_text);
459     //set_w32_clip_text (clip_text, n);
460 twoaday 328 wipememory (clip_text, n);
461     free_if_alloc (clip_text);
462 twoaday 462 #endif
463    
464     wipememory(utf8_text, n);
465     gpgme_free(utf8_text);
466    
467 twoaday 328 return gpg_error (GPG_ERR_NO_ERROR);
468     }
469    
470    
471 twoaday 121 /* Release a gpgme data object @dh and write the contents of
472 twoaday 462 the object to the clipboard. If @change_version is set, modify the
473 twoaday 121 Version: header and add WinPT information. */
474 twoaday 328 gpgme_error_t
475 twoaday 462 gpg_data_release_to_clipboard (gpgme_data_t dh, int change_version)
476 twoaday 121 {
477     gpgme_data_t in;
478     char *clip_text;
479     size_t n;
480    
481     if (!dh)
482 twoaday 328 return gpg_error (GPG_ERR_INV_ARG);
483    
484 twoaday 121 in = dh;
485 twoaday 462 if (change_version)
486 twoaday 121 gpg_data_change_version (&in);
487 twoaday 328
488 twoaday 121 clip_text = gpgme_data_release_and_get_mem (in, &n);
489     if (clip_text && *clip_text) {
490     set_w32_clip_text (clip_text, n);
491 twoaday 271 wipememory (clip_text, n);
492 twoaday 121 gpgme_free (clip_text);
493     }
494 twoaday 328
495     return gpg_error (GPG_ERR_NO_ERROR);
496 twoaday 121 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26