9d484706ac628ff5f26a33cc120f63ec953edb3f
[apps/madmutt.git] / pgppacket.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <time.h>
19
20 #include "sha1.h"
21 #include "lib.h"
22 #include "pgplib.h"
23 #include "pgppacket.h"
24
25 #include "lib/mem.h"
26
27 #define CHUNKSIZE 1024
28
29 static unsigned char *pbuf = NULL;
30 static size_t plen = 0;
31
32 static int read_material (size_t material, size_t * used, FILE * fp)
33 {
34   if (*used + material >= plen) {
35     unsigned char *p;
36     size_t nplen;
37
38     nplen = *used + material + CHUNKSIZE;
39
40     if (!(p = realloc (pbuf, nplen))) { /* __MEM_CHECKED__ */
41       perror ("realloc");
42       return -1;
43     }
44     plen = nplen;
45     pbuf = p;
46   }
47
48   if (fread (pbuf + *used, 1, material, fp) < material) {
49     perror ("fread");
50     return -1;
51   }
52
53   *used += material;
54   return 0;
55 }
56
57 unsigned char *pgp_read_packet (FILE * fp, size_t * len)
58 {
59   size_t used = 0;
60   off_t startpos;
61   unsigned char ctb;
62   unsigned char b;
63   size_t material;
64
65   startpos = ftello (fp);
66
67   if (!plen) {
68     plen = CHUNKSIZE;
69     pbuf = mem_malloc (plen);
70   }
71
72   if (fread (&ctb, 1, 1, fp) < 1) {
73     if (!feof (fp))
74       perror ("fread");
75     goto bail;
76   }
77
78   if (!(ctb & 0x80)) {
79     goto bail;
80   }
81
82   if (ctb & 0x40) {             /* handle PGP 5.0 packets. */
83     int partial = 0;
84
85     pbuf[0] = ctb;
86     used++;
87
88     do {
89       if (fread (&b, 1, 1, fp) < 1) {
90         perror ("fread");
91         goto bail;
92       }
93
94       if (b < 192) {
95         material = b;
96         partial = 0;
97         /* material -= 1; */
98       }
99       else if (192 <= b && b <= 223) {
100         material = (b - 192) * 256;
101         if (fread (&b, 1, 1, fp) < 1) {
102           perror ("fread");
103           goto bail;
104         }
105         material += b + 192;
106         partial = 0;
107         /* material -= 2; */
108       }
109       else if (b < 255) {
110         material = 1 << (b & 0x1f);
111         partial = 1;
112         /* material -= 1; */
113       }
114       else
115         /* b == 255 */
116       {
117         unsigned char buf[4];
118
119         if (fread (buf, 4, 1, fp) < 1) {
120           perror ("fread");
121           goto bail;
122         }
123         /*assert( sizeof(material) >= 4 ); */
124         material = buf[0] << 24;
125         material |= buf[1] << 16;
126         material |= buf[2] << 8;
127         material |= buf[3];
128         partial = 0;
129         /* material -= 5; */
130       }
131
132       if (read_material (material, &used, fp) == -1)
133         goto bail;
134
135     }
136     while (partial);
137   }
138   else
139     /* Old-Style PGP */
140   {
141     int bytes = 0;
142
143     pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
144     used++;
145
146     switch (ctb & 0x03) {
147     case 0:
148       {
149         if (fread (&b, 1, 1, fp) < 1) {
150           perror ("fread");
151           goto bail;
152         }
153
154         material = b;
155         break;
156       }
157
158     case 1:
159       bytes = 2;
160
161     case 2:
162       {
163         int i;
164
165         if (!bytes)
166           bytes = 4;
167
168         material = 0;
169
170         for (i = 0; i < bytes; i++) {
171           if (fread (&b, 1, 1, fp) < 1) {
172             perror ("fread");
173             goto bail;
174           }
175
176           material = (material << 8) + b;
177         }
178         break;
179       }
180
181     default:
182       goto bail;
183     }
184
185     if (read_material (material, &used, fp) == -1)
186       goto bail;
187   }
188
189   if (len)
190     *len = used;
191
192   return pbuf;
193
194 bail:
195
196   fseeko (fp, startpos, SEEK_SET);
197   return NULL;
198 }
199
200 void pgp_release_packet (void)
201 {
202   plen = 0;
203   mem_free (&pbuf);
204 }