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

Diff of /trunk/Src/wptClipboard.cpp

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

revision 327 by twoaday, Mon Jul 23 17:13:38 2007 UTC revision 328 by twoaday, Fri Sep 25 16:07:38 2009 UTC
# Line 1  Line 1 
1  /* wptClipboard.cpp - GPG related clipboard functions  /* wptClipboard.cpp - GPG related clipboard functions
2   *      Copyright (C) 2001, 2002, 2003, 2005, 2006 Timo Schulz   *      Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Timo Schulz
3   *      Copyright (C) 2005 g10 Code GmbH   *      Copyright (C) 2005 g10 Code GmbH
4   *   *
5   * This file is part of WinPT.   * This file is part of WinPT.
# Line 13  Line 13 
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.   * GNU General Public License for more details.
  *  
  * You should have received a copy of the GNU General Public License  
  * along with WinPT; if not, write to the Free Software Foundation,  
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA  
16   */   */
17    
18  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
# Line 31  Line 27 
27  #include "wptVersion.h"  #include "wptVersion.h"
28  #include "wptGPG.h"  #include "wptGPG.h"
29  #include "wptTypes.h"  #include "wptTypes.h"
30    #include "wptUTF8.h"
31    
32  /* Default buffer size. */  /* Default buffer size. */
33  #define BUFSIZE 192  #define BUFSIZE 192
# Line 50  gpg_clip_istext_avail (int *r_val) Line 47  gpg_clip_istext_avail (int *r_val)
47            
48      if (!r_val)      if (!r_val)
49          return gpg_error (GPG_ERR_INV_ARG);          return gpg_error (GPG_ERR_INV_ARG);
50        *r_val = 0;
51      if (OpenClipboard (NULL) == FALSE)      if (OpenClipboard (NULL) == FALSE)
52          return gpg_error (GPG_ERR_NO_DATA);          return gpg_error (GPG_ERR_INTERNAL);
53            
     *r_val = 0;  
54      clipmem = GetClipboardData (CF_TEXT);      clipmem = GetClipboardData (CF_TEXT);
55      if (!clipmem)      if (!clipmem) {
56          goto leave;          CloseClipboard();
57            return gpg_error (GPG_ERR_NO_DATA);
58        }
59    
60      clipdata = (char *) GlobalLock (clipmem);      clipdata = (char *) GlobalLock (clipmem);
61      if (!clipdata)      if (!clipdata) {
62          goto leave;          CloseClipboard ();
63            return gpg_error (GPG_ERR_INTERNAL);
64        }
65        
66      if (strlen (clipdata) > 0)      if (strlen (clipdata) > 0)
67          *r_val = 1;          *r_val = 1;
68      GlobalUnlock (clipmem);      GlobalUnlock (clipmem);
   
 leave:  
69      CloseClipboard ();      CloseClipboard ();
70      return 0;      return 0;
71  }  }
# Line 86  gpg_clip_parse_pgpid (const char *data, Line 86  gpg_clip_parse_pgpid (const char *data,
86          return 0;          return 0;
87      }      }
88      type = 0;      type = 0;
89      if (strstr( data, "BEGIN PGP MESSAGE") )      if (strstr (data, "BEGIN PGP MESSAGE"))
90          type |= PGP_MESSAGE;          type |= PGP_MESSAGE;
91      if (strstr (data, "BEGIN PGP SIGNED MESSAGE"))      if (strstr (data, "BEGIN PGP SIGNED MESSAGE"))
92          type |= PGP_CLEARSIG;          type |= PGP_CLEARSIG;
# Line 97  gpg_clip_parse_pgpid (const char *data, Line 97  gpg_clip_parse_pgpid (const char *data,
97      if (strstr (data, "BEGIN PGP PRIVATE KEY BLOCK") ||      if (strstr (data, "BEGIN PGP PRIVATE KEY BLOCK") ||
98          strstr (data, "BEGIN PGP SECRET KEY BLOCK"))          strstr (data, "BEGIN PGP SECRET KEY BLOCK"))
99          type |= PGP_SECKEY;          type |= PGP_SECKEY;
100        // Actually this is no type but rather a flag to
101        // indicate the that the data is 'dash escaped'
102      if (strstr (data, "- -----BEGIN"))      if (strstr (data, "- -----BEGIN"))
103          type |= PGP_DASH_ESCAPED;          type |= PGP_DASH_ESCAPED;
104      *r_type = type;      *r_type = type;
# Line 111  gpg_clip_parse_pgpid (const char *data, Line 113  gpg_clip_parse_pgpid (const char *data,
113  gpgme_error_t  gpgme_error_t
114  gpg_clip_is_secured (int *r_type, int *r_val)  gpg_clip_is_secured (int *r_type, int *r_val)
115  {  {
     int rc = 0;  
116      HANDLE clipmem;      HANDLE clipmem;
117      char *clipdata;      char *clipdata;
118            
# Line 122  gpg_clip_is_secured (int *r_type, int *r Line 123  gpg_clip_is_secured (int *r_type, int *r
123      clipmem = GetClipboardData (CF_TEXT);      clipmem = GetClipboardData (CF_TEXT);
124      if (!clipmem) {      if (!clipmem) {
125          *r_val = 0;          *r_val = 0;
126          goto leave;          CloseClipboard();
127            return gpg_error (GPG_ERR_NO_DATA);
128      }      }
129      clipdata = (char *) GlobalLock (clipmem);      clipdata = (char *) GlobalLock (clipmem);
130      if (!clipdata) {      if (!clipdata) {
131          *r_val = 0;              *r_val = 0;
132          goto leave;              CloseClipboard();
133            return gpg_error (GPG_ERR_INTERNAL);
134      }      }
135      if (strstr (clipdata, "-----BEGIN PGP")      if (strlen (clipdata) > 32 &&
136          && strstr (clipdata, "-----END PGP"))          strstr (clipdata, "-----BEGIN PGP") &&
137            strstr (clipdata, "-----END PGP"))
138          *r_val = 1;          *r_val = 1;
139      GlobalUnlock (clipmem);      GlobalUnlock (clipmem);
140      gpg_clip_parse_pgpid (clipdata, r_type);      gpg_clip_parse_pgpid (clipdata, r_type);
   
 leave:  
141      CloseClipboard ();      CloseClipboard ();
142      return rc;      return gpg_error (GPG_ERR_NO_ERROR);
143  }  }
144    
145    
# Line 146  leave: Line 148  leave:
148  gpgme_error_t  gpgme_error_t
149  gpg_clip_get_pgptype (int *r_type)  gpg_clip_get_pgptype (int *r_type)
150  {  {
     gpgme_error_t rc = 0;  
151      HANDLE clipmem;      HANDLE clipmem;
152      char *clipdata;      char *clipdata;
153            
# Line 154  gpg_clip_get_pgptype (int *r_type) Line 155  gpg_clip_get_pgptype (int *r_type)
155          return gpg_error (GPG_ERR_INTERNAL);          return gpg_error (GPG_ERR_INTERNAL);
156      clipmem = GetClipboardData (CF_TEXT);      clipmem = GetClipboardData (CF_TEXT);
157      if (!clipmem) {      if (!clipmem) {
158          rc = gpg_error (GPG_ERR_NO_DATA);          CloseClipboard ();
159          goto leave;          return gpg_error (GPG_ERR_NO_DATA);
160      }      }
161      clipdata = (char *)GlobalLock( clipmem );      clipdata = (char *)GlobalLock (clipmem);
162      if (!clipdata) {      if (!clipdata) {
163          rc = gpg_error (GPG_ERR_NO_DATA);          CloseClipboard ();
164          goto leave;          return gpg_error (GPG_ERR_INTERNAL);
165      }          }    
166      gpg_clip_parse_pgpid (clipdata, r_type);      gpg_clip_parse_pgpid (clipdata, r_type);
167      GlobalUnlock (clipmem);      GlobalUnlock (clipmem);
       
 leave:  
168      CloseClipboard ();      CloseClipboard ();
169      return rc;      return gpg_error (GPG_ERR_NO_ERROR);
170  }  }
171    
172    
# Line 176  leave: Line 175  leave:
175  static char*  static char*
176  get_w32_clip_text (void)  get_w32_clip_text (void)
177  {  {
178      char *private_clip = NULL;      char *private_clip;
179      char *clip = NULL;      char *clip;
180      size_t size;      size_t size;
181      HANDLE cb;      HANDLE cb;
182            
183      if (!OpenClipboard (NULL))      if (!OpenClipboard (NULL))
184          return NULL;          return NULL;
185      cb = GetClipboardData (CF_TEXT);      cb = GetClipboardData (CF_TEXT);
186      if (!cb)      if (!cb) {
187          goto leave;          CloseClipboard ();
188            return NULL;
189        }
190      private_clip = (char *)GlobalLock (cb);      private_clip = (char *)GlobalLock (cb);
191      if (!private_clip)      if (!private_clip) {
192          goto leave;          CloseClipboard ();
193      size = strlen (private_clip);          return NULL;
     clip = (char*)calloc (1, size + 1);  
     if (!clip) {  
         GlobalUnlock (cb);  
         goto leave;  
194      }      }
195        size = strlen (private_clip);
196        clip = new char[size+1];
197        if (!clip)
198            BUG (NULL);
199        memset (clip, 0, size+1);
200      memcpy (clip, private_clip, size);      memcpy (clip, private_clip, size);
201      GlobalUnlock(cb);      GlobalUnlock(cb);
       
 leave:  
202      CloseClipboard ();      CloseClipboard ();
203      return clip;      return clip;
204  }  }
# Line 212  set_w32_clip_text (const char *data, int Line 212  set_w32_clip_text (const char *data, int
212      char *private_data;      char *private_data;
213            
214      if (!OpenClipboard(NULL))      if (!OpenClipboard(NULL))
215          return;          return;        
     EmptyClipboard ();  
216      cb = GlobalAlloc (GHND, size+1);      cb = GlobalAlloc (GHND, size+1);
217      if (!cb)      if (!cb)
218          goto leave;          BUG (NULL);
219      private_data = (char*)GlobalLock (cb);      private_data = (char*)GlobalLock (cb);
220      if (!private_data)      if (private_data != NULL) {
221          goto leave;          EmptyClipboard ();
222      memcpy (private_data, data, size);          memset (private_data, 0, size+1);
223      private_data[size] = '\0';          memcpy (private_data, data, size);
224      SetClipboardData (CF_TEXT, cb);          SetClipboardData (CF_TEXT, cb);
225      GlobalUnlock (cb);          GlobalUnlock (cb);
226        }
227            
 leave:      
228      CloseClipboard ();      CloseClipboard ();
229      GlobalFree (cb);      GlobalFree (cb);
230  }  }
231    
232    
 /* Retrieve the clipboard data and create a new gpgme  
    data object @r_dh and return it. If @wraplen is > 0  
    wrap lines of the buffer.  
    Return value: 0 on success. */  
 gpgme_error_t  
 gpg_data_new_from_clipboard (gpgme_data_t *r_dh, int wraplen)  
 {  
     gpgme_error_t err = 0;  
     gpgme_data_t dh;  
     char *clip_text = NULL;  
   
     if (!r_dh)  
         return gpg_error (GPG_ERR_INV_ARG);  
     *r_dh = NULL;  
     clip_text = get_w32_clip_text ();  
     if (!clip_text)  
         return gpg_error (GPG_ERR_NO_DATA);  
     err = gpgme_data_new_from_mem (&dh, clip_text, strlen (clip_text), 1);  
     if (clip_text)  
         free (clip_text);  
     if (wraplen > 0)  
         gpg_data_wrap_lines (&dh, wraplen);  
       
     *r_dh = dh;  
     return err;  
 }  
   
   
233  /* Search for the armor header 'Version:' in @r_dh and  /* Search for the armor header 'Version:' in @r_dh and
234     add the WinPT version. On success @r_dh is replaced     add the WinPT version. On success @r_dh is replaced
235     with the modified data.     with the modified data.
# Line 269  gpg_data_change_version (gpgme_data_t *r Line 240  gpg_data_change_version (gpgme_data_t *r
240      gpgme_error_t err;      gpgme_error_t err;
241      gpgme_data_t mdh;      gpgme_data_t mdh;
242      const char *s;      const char *s;
243      char line[BUFSIZE+32];      char line[BUFSIZE+256];
244        int found_version, hash_seen;
245      int n;      int n;
246    
247      if (!r_dh)      if (!r_dh)
# Line 278  gpg_data_change_version (gpgme_data_t *r Line 250  gpg_data_change_version (gpgme_data_t *r
250      err = gpgme_data_new (&mdh);      err = gpgme_data_new (&mdh);
251      if (err)      if (err)
252          return err;          return err;
253        
254        found_version = 0;
255        hash_seen = 0;
256      /* Pattern we search for. */      /* Pattern we search for. */
257      s = "Version: GnuPG";      s = "Version: GnuPG";
258      gpgme_data_rewind (*r_dh);      gpgme_data_rewind (*r_dh);
259      while ((n=gpg_data_readline (*r_dh, line, BUFSIZE-1)) > 0) {      while ((n = gpg_data_readline (*r_dh, line, BUFSIZE-1)) > 0) {
260            if (found_version == 0 && !strncmp (line, "Hash:", 5)) {
261                // If we found a cleartext signature, we do not add a
262                // charset header in the signed area since it would broke
263                // the signature
264                hash_seen = 1;
265            }
266            
267            if (!strncmp (line, "\r\n", 2) && found_version == 0 &&
268                hash_seen == 0) {
269                // If the user decided she will not tell what client she
270                // used, we will also omit the version and just output
271                // the charset info
272                line[strlen (line)- 2]=0;
273                strcat (line, /*"Version: WinPT "PGM_VERSION"\r\n"*/
274                              "Charset: UTF-8\r\n"
275                              "\r\n");
276                found_version = 1;
277            }
278          if (strlen (line) > strlen (s) &&          if (strlen (line) > strlen (s) &&
279              !strncmp (line, s, strlen (s))  &&              !strncmp (line, s, strlen (s))  &&
280              !stristr (line, "WinPT "PGM_VERSION)) {              !stristr (line, "WinPT "PGM_VERSION)) {
# Line 290  gpg_data_change_version (gpgme_data_t *r Line 282  gpg_data_change_version (gpgme_data_t *r
282              if (strstr (line, "\r\n"))              if (strstr (line, "\r\n"))
283                  line[strlen (line) - 2] = '\0';                  line[strlen (line) - 2] = '\0';
284              if (strstr (line, "\n"))              if (strstr (line, "\n"))
285                  line[strlen (line)-1] = '\0';                  line[strlen (line) - 1] = '\0';
286              strcat (line, " - WinPT "PGM_VERSION"\r\n");              // We add a charset header to indicate that the application
287                // on the recipients side is able to properly decode it
288                strcat (line, " - WinPT "PGM_VERSION"\r\n"      
289                              "Charset: UTF-8\r\n");
290                found_version = 1;
291          }          }
292          gpgme_data_write (mdh, line, strlen (line));          gpgme_data_write (mdh, line, strlen (line));
293      }      }
# Line 303  gpg_data_change_version (gpgme_data_t *r Line 299  gpg_data_change_version (gpgme_data_t *r
299      return err;      return err;
300  }  }
301    
302    
303    /* The problem is, that it might be also possible that we
304       received an ciphertext which is not encoded with UTF-8.
305       Thus, we check explicitly for the 'Charset: UTF-8' header.
306       If it is not found, we assume a different encoding and
307       no decoding is performed. */
308    static int
309    has_utf8_charset (gpgme_data_t dh)
310    {    
311        char buf[BUFSIZE+1];
312        int found = 0;
313        
314        for (;;) {
315            int n = gpg_data_readline (dh, buf, BUFSIZE);
316            if (n < 1)
317                break;
318            // Read until the first blank line, if the
319            // header has not been found yet, it does not exist
320            if ((n == 1 && buf[0] == '\n') ||
321                (n == 2 && buf[0] == '\r'))
322                break;
323            if (!memcmp (buf, "Charset:", 8) && strstr (buf, "UTF-8")) {
324                found = 1;
325                break;
326            }
327        }
328        gpgme_data_rewind (dh);
329        return found;
330    }
331    
332    
333    /* Retrieve the clipboard data and create a new gpgme
334       data object @r_dh and return it. If @wraplen is > 0
335       wrap lines of the buffer.
336       Return value: 0 on success. */
337    gpgme_error_t
338    gpg_data_new_from_clipboard (gpgme_data_t *r_dh, int wraplen)
339    {
340        gpgme_error_t err = 0;
341        gpgme_data_t dh;
342        char *clip_text = NULL;
343    
344        if (!r_dh)
345            return gpg_error (GPG_ERR_INV_ARG);
346        *r_dh = NULL;
347        clip_text = get_w32_clip_text ();
348        if (!clip_text)
349            return gpg_error (GPG_ERR_NO_DATA);
350        err = gpgme_data_new_from_mem (&dh, clip_text, strlen (clip_text), 1);
351        if (clip_text)
352            free (clip_text);
353        if (wraplen > 0)
354            gpg_data_wrap_lines (&dh, wraplen);
355        
356        *r_dh = dh;
357        return err;
358    }
359    
360    /* Retrieve the clipboard data and create a new gpgme
361       data object @r_dh and return it. If @wraplen is > 0
362       wrap lines of the buffer.
363       Return value: 0 on success. */
364    gpgme_error_t
365    gpg_data_utf8_new_from_clipboard (gpgme_data_t *r_dh,
366                                      int wraplen, int *r_is_utf8)
367    {
368        gpgme_error_t err = gpg_error (GPG_ERR_NO_ERROR);
369        gpgme_data_t dh;
370        char *clip_text, *utf8_text;
371    
372        if (!r_dh)
373            return gpg_error (GPG_ERR_INV_ARG);
374        *r_dh = NULL;
375        clip_text = get_w32_clip_text ();
376        if (!clip_text)
377            return gpg_error (GPG_ERR_NO_DATA);
378            
379        
380        /* We automatically encode all clipboard data
381           into the UTF-8 format for a portable transportation. */
382        utf8_text = native_to_utf8 (clip_text);
383        free_if_alloc (clip_text); clip_text = utf8_text;
384        
385        err = gpgme_data_new_from_mem (&dh, clip_text, strlen (clip_text), 1);
386        free_if_alloc (clip_text);
387        if (wraplen > 0)
388            gpg_data_wrap_lines (&dh, wraplen);
389        
390        // for ARMORED data find out if the Charset header is set to UTF8
391        if (r_is_utf8)
392            *r_is_utf8 = has_utf8_charset (dh);
393        
394        *r_dh = dh;
395        return err;
396    }
397    
398    
399    
400    gpgme_error_t
401    gpg_data_release_utf8_to_clipboard (gpgme_data_t dh)
402    {
403        char *clip_text, *utf8_text;
404        size_t n;
405        
406        if (!dh)
407            return gpg_error (GPG_ERR_INV_ARG);
408    
409        gpgme_data_write (dh, "", 1); // make sure it's a string!
410        utf8_text = gpgme_data_release_and_get_mem (dh, &n);
411        if (!utf8_text)
412            return gpg_error (GPG_ERR_INV_VALUE);
413        if (n < 0) {
414            gpgme_free (utf8_text);
415            return gpg_error (GPG_ERR_NO_DATA);
416        }
417    
418        /* We assume that all data from GPG is in UTF-8 and
419         need to be decoded. If the charset is US-ASCII,
420         this wouldn't do any harm, but if the data is ISO-XXX-XX
421         we get scrambled output. */
422        utf8_text[n] = '\0';
423        clip_text = utf8_to_native (utf8_text);
424        wipememory (utf8_text, n);
425        gpgme_free (utf8_text);
426        n = strlen (clip_text);
427        set_w32_clip_text (clip_text, n);
428        wipememory (clip_text, n);
429        free_if_alloc (clip_text);
430        return gpg_error (GPG_ERR_NO_ERROR);
431    }
432    
433    
434  /* Release a gpgme data object @dh and write the contents of  /* Release a gpgme data object @dh and write the contents of
435     the object to the clipboard. If @chg_ver is set, modify the     the object to the clipboard. If @chg_ver is set, modify the
436     Version: header and add WinPT information. */     Version: header and add WinPT information. */
437  void  gpgme_error_t
438  gpg_data_release_and_set_clipboard (gpgme_data_t dh, int chg_ver)  gpg_data_release_to_clipboard (gpgme_data_t dh, int chg_ver)
439  {  {
440      gpgme_data_t in;      gpgme_data_t in;
441      char *clip_text;      char *clip_text;
442      size_t n;      size_t n;
443            
444      if (!dh)      if (!dh)
445          return;          return gpg_error (GPG_ERR_INV_ARG);
446        
447      in = dh;      in = dh;
448      if (chg_ver)      if (chg_ver)
449          gpg_data_change_version (&in);          gpg_data_change_version (&in);
450        
451      clip_text = gpgme_data_release_and_get_mem (in, &n);      clip_text = gpgme_data_release_and_get_mem (in, &n);
452      if (clip_text && *clip_text) {      if (clip_text && *clip_text) {
453          set_w32_clip_text (clip_text, n);          set_w32_clip_text (clip_text, n);
454          wipememory (clip_text, n);          wipememory (clip_text, n);
455          gpgme_free (clip_text);          gpgme_free (clip_text);
456      }      }
457        
458        return gpg_error (GPG_ERR_NO_ERROR);
459  }  }

Legend:
Removed from v.327  
changed lines
  Added in v.328

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26