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 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <time.h>
26
27 #include "sha1.h"
28 #include "lib.h"
29 #include "pgplib.h"
30 #include "pgppacket.h"
31
32 #define CHUNKSIZE 1024
33
34 static unsigned char *pbuf = NULL;
35 static size_t plen = 0;
36
37 static int read_material (size_t material, size_t * used, FILE * fp)
38 {
39   if (*used + material >= plen)
40   {
41     unsigned char *p;
42     size_t nplen;
43
44     nplen = *used + material + CHUNKSIZE;
45
46     if (!(p = realloc (pbuf, nplen)))   /* __MEM_CHECKED__ */
47     {
48       perror ("realloc");
49       return -1;
50     }
51     plen = nplen;
52     pbuf = p;
53   }
54
55   if (fread (pbuf + *used, 1, material, fp) < material)
56   {
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   {
77     plen = CHUNKSIZE;
78     pbuf = safe_malloc (plen);
79   }
80
81   if (fread (&ctb, 1, 1, fp) < 1)
82   {
83     if (!feof (fp))
84       perror ("fread");
85     goto bail;
86   }
87
88   if (!(ctb & 0x80))
89   {
90     goto bail;
91   }
92
93   if (ctb & 0x40)               /* handle PGP 5.0 packets. */
94   {
95     int partial = 0;
96     pbuf[0] = ctb;
97     used++;
98
99     do
100     {
101       if (fread (&b, 1, 1, fp) < 1)
102       {
103         perror ("fread");
104         goto bail;
105       }
106
107       if (b < 192)
108       {
109         material = b;
110         partial = 0;
111         /* material -= 1; */
112       }
113       else if (192 <= b && b <= 223)
114       {
115         material = (b - 192) * 256;
116         if (fread (&b, 1, 1, fp) < 1)
117         {
118           perror ("fread");
119           goto bail;
120         }
121         material += b + 192;
122         partial = 0;
123         /* material -= 2; */
124       }
125       else if (b < 255)
126       {
127         material = 1 << (b & 0x1f);
128         partial = 1;
129         /* material -= 1; */
130       }
131       else
132         /* b == 255 */
133       {
134         unsigned char buf[4];
135         if (fread (buf, 4, 1, fp) < 1)
136         {
137           perror ("fread");
138           goto bail;
139         }
140         /*assert( sizeof(material) >= 4 ); */
141         material = buf[0] << 24;
142         material |= buf[1] << 16;
143         material |= buf[2] << 8;
144         material |= buf[3];
145         partial = 0;
146         /* material -= 5; */
147       }
148
149       if (read_material (material, &used, fp) == -1)
150         goto bail;
151
152     }
153     while (partial);
154   }
155   else
156     /* Old-Style PGP */
157   {
158     int bytes = 0;
159     pbuf[0] = 0x80 | ((ctb >> 2) & 0x0f);
160     used++;
161
162     switch (ctb & 0x03)
163     {
164       case 0:
165       {
166         if (fread (&b, 1, 1, fp) < 1)
167         {
168           perror ("fread");
169           goto bail;
170         }
171
172         material = b;
173         break;
174       }
175
176       case 1:
177       bytes = 2;
178
179       case 2:
180       {
181         int i;
182
183         if (!bytes)
184           bytes = 4;
185
186         material = 0;
187
188         for (i = 0; i < bytes; i++)
189         {
190           if (fread (&b, 1, 1, fp) < 1)
191           {
192             perror ("fread");
193             goto bail;
194           }
195
196           material = (material << 8) + b;
197         }
198         break;
199       }
200
201       default:
202       goto bail;
203     }
204
205     if (read_material (material, &used, fp) == -1)
206       goto bail;
207   }
208
209   if (len)
210     *len = used;
211
212   return pbuf;
213
214 bail:
215
216   fseek (fp, startpos, SEEK_SET);
217   return NULL;
218 }
219
220 void pgp_release_packet (void)
221 {
222   plen = 0;
223   FREE (&pbuf);
224 }
225