Andreas Krennmair:
[apps/madmutt.git] / pgppacket.c
1 /*
2  * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
3  * 
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the Free
16  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17  * MA 02111, USA.
18  */
19
20 #if HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <time.h>
29
30 #include "sha1.h"
31 #include "lib.h"
32 #include "pgplib.h"
33 #include "pgppacket.h"
34
35 #define CHUNKSIZE 1024
36
37 static unsigned char *pbuf = NULL;
38 static size_t plen = 0;
39
40 static int read_material (size_t material, size_t * used, FILE * fp)
41 {
42   if (*used + material >= plen) {
43     unsigned char *p;
44     size_t nplen;
45
46     nplen = *used + material + CHUNKSIZE;
47
48     if (!(p = realloc (pbuf, nplen))) { /* __MEM_CHECKED__ */
49       perror ("realloc");
50       return -1;
51     }
52     plen = nplen;
53     pbuf = p;
54   }
55
56   if (fread (pbuf + *used, 1, material, fp) < material) {
57     perror ("fread");
58     return -1;
59   }
60
61   *used += material;
62   return 0;
63 }
64
65 unsigned char *pgp_read_packet (FILE * fp, size_t * len)
66 {
67   size_t used = 0;
68   long startpos;
69   unsigned char ctb;
70   unsigned char b;
71   size_t material;
72
73   startpos = ftell (fp);
74
75   if (!plen) {
76     plen = CHUNKSIZE;
77     pbuf = safe_malloc (plen);
78   }
79
80   if (fread (&ctb, 1, 1, fp) < 1) {
81     if (!feof (fp))
82       perror ("fread");
83     goto bail;
84   }
85
86   if (!(ctb & 0x80)) {
87     goto bail;
88   }
89
90   if (ctb & 0x40) {             /* handle PGP 5.0 packets. */
91     int partial = 0;
92
93     pbuf[0] = ctb;
94     used++;
95
96     do {
97       if (fread (&b, 1, 1, fp) < 1) {
98         perror ("fread");
99         goto bail;
100       }
101
102       if (b < 192) {
103         material = b;
104         partial = 0;
105         /* material -= 1; */
106       }
107       else if (192 <= b && b <= 223) {
108         material = (b - 192) * 256;
109         if (fread (&b, 1, 1, fp) < 1) {
110           perror ("fread");
111           goto bail;
112         }
113         material += b + 192;
114         partial = 0;
115         /* material -= 2; */
116       }
117       else if (b < 255) {
118         material = 1 << (b & 0x1f);
119         partial = 1;
120         /* material -= 1; */
121       }
122       else
123         /* b == 255 */
124       {
125         unsigned char buf[4];
126
127         if (fread (buf, 4, 1, fp) < 1) {
128           perror ("fread");
129           goto bail;
130         }
131         /*assert( sizeof(material) >= 4 ); */
132         material = buf[0] << 24;
133         material |= buf[1] << 16;
134         material |= buf[2] << 8;
135         material |= buf[3];
136         partial = 0;
137         /* material -= 5; */
138       }
139
140       if (read_material (material, &used, fp) == -1)
141         goto bail;
142
143     }
144     while (partial);
145   }
146   else
147     /* Old-Style PGP */
148   {
149     int bytes = 0;
150
151     pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
152     used++;
153
154     switch (ctb & 0x03) {
155     case 0:
156       {
157         if (fread (&b, 1, 1, fp) < 1) {
158           perror ("fread");
159           goto bail;
160         }
161
162         material = b;
163         break;
164       }
165
166     case 1:
167       bytes = 2;
168
169     case 2:
170       {
171         int i;
172
173         if (!bytes)
174           bytes = 4;
175
176         material = 0;
177
178         for (i = 0; i < bytes; i++) {
179           if (fread (&b, 1, 1, fp) < 1) {
180             perror ("fread");
181             goto bail;
182           }
183
184           material = (material << 8) + b;
185         }
186         break;
187       }
188
189     default:
190       goto bail;
191     }
192
193     if (read_material (material, &used, fp) == -1)
194       goto bail;
195   }
196
197   if (len)
198     *len = used;
199
200   return pbuf;
201
202 bail:
203
204   fseek (fp, startpos, SEEK_SET);
205   return NULL;
206 }
207
208 void pgp_release_packet (void)
209 {
210   plen = 0;
211   FREE (&pbuf);
212 }