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