1 /********************************************************************
2 * $Author: jgoerzen $
3 * $Revision: 1.3 $
4 * $Date: 2001/01/17 21:16:35 $
5 * $Source: /home/jgoerzen/tmp/gopher-umn/gopher/head/object/BLblock.c,v $
6 * $State: Exp $
7 *
8 * Paul Lindner, University of Minnesota CIS.
9 *
10 * Copyright 1991, 1992, 1993 by the Regents of the University of Minnesota
11 * see the file "Copyright" in the distribution for conditions of use.
12 *********************************************************************
13 * MODULE: BLblock.c
14 * Implementation of Block handling routines.
15 *********************************************************************
16 * Revision History:
17 * $Log: BLblock.c,v $
18 * Revision 1.3 2001/01/17 21:16:35 jgoerzen
19 * More psinrtf -> snprintf changes
20 *
21 * Revision 1.2 2000/12/20 01:19:20 jgoerzen
22 * Added patches from David Allen <s2mdalle@titan.vcu.edu>
23 *
24 * Revision 1.1.1.1 2000/08/19 00:28:56 jgoerzen
25 * Import from UMN Gopher 2.3.1 after GPLization
26 *
27 * Revision 3.14 1995/09/25 22:07:15 lindner
28 * Ansification
29 *
30 * Revision 3.13 1995/04/15 06:50:46 lindner
31 * check error return on BLblock
32 *
33 * Revision 3.12 1995/02/17 18:29:36 lindner
34 * Abstract display support
35 *
36 * Revision 3.11 1994/08/08 20:26:35 lindner
37 * fix bug for Abstract= lines.
38 *
39 * Revision 3.10 1994/06/29 05:45:24 lindner
40 * Mods for tickets
41 *
42 * Revision 3.9 1994/02/20 21:49:09 lindner
43 * deal with malformed views lines better
44 *
45 * Revision 3.8 1993/11/02 06:13:36 lindner
46 * Fix for HTML mods
47 *
48 * Revision 3.7 1993/07/29 19:59:23 lindner
49 * Removed extraneous variables
50 *
51 * Revision 3.6 1993/07/27 05:30:17 lindner
52 * Mondo Debug overhaul from Mitra
53 *
54 * Revision 3.5 1993/06/15 06:10:34 lindner
55 * Moved string.h include
56 *
57 * Revision 3.4 1993/04/27 20:54:32 lindner
58 * really fixed BLtoNet()
59 *
60 * Revision 3.3 1993/04/23 20:14:48 lindner
61 * Fix for BltoNet(), using wrong datatype
62 *
63 * Revision 3.2 1993/03/26 19:49:34 lindner
64 * More comments, memory leak fix, etc
65 *
66 * Revision 3.1.1.1 1993/02/11 18:03:06 lindner
67 * Gopher+1.2beta release
68 *
69 * Revision 2.1 1993/02/09 22:45:54 lindner
70 * Fixes for retrieving from the net. New BLAsearch
71 *
72 * Revision 1.1 1993/01/31 00:22:51 lindner
73 * Initial revision
74 *
75 *
76 *********************************************************************/
77
78 #include "String.h"
79 #include "BLblock.h"
80 #include "Malloc.h"
81 #include <stdio.h>
82
83 /*
84 * Make a new Block Object
85 */
86
87 Blockobj *
BLnew()88 BLnew()
89 {
90 Blockobj *temp;
91
92 temp = (Blockobj *) malloc(sizeof(Blockobj));
93
94 temp->btype = BLOCK_UNKNOWN;
95 temp->Blockname = STRnew();
96 temp->datatype = BDATA_NONE;
97
98 return(temp);
99 }
100
101
102 /*
103 * Initialize the block structure
104 */
105
106 void
BLinit(Blockobj * bl)107 BLinit(Blockobj *bl)
108 {
109 STRinit(bl->Blockname);
110 switch (BLgetDatatype(bl)) {
111 case BDATA_FILE:
112 STRinit(bl->data.filename);
113 break;
114 case BDATA_GREF:
115 GSinit(bl->data.gs);
116 break;
117 case BDATA_TEXT:
118 STAinit(bl->data.text);
119 break;
120 case BDATA_NONE:
121 break;}
122 }
123
124 /*
125 * Calls the right destory fcn depending on the object in the union.
126 *
127 * wouldn't c++ be nice right here? :-)
128 */
129
130 static void
BLdatadestroy(Blockobj * bl)131 BLdatadestroy(Blockobj *bl)
132 {
133 switch (BLgetDatatype(bl)) {
134 case BDATA_FILE:
135 STRdestroy(bl->data.filename);
136 break;
137 case BDATA_TEXT:
138 STAdestroy(bl->data.text);
139 break;
140 case BDATA_GREF:
141 GSdestroy(bl->data.gs);
142 break;
143 case BDATA_NONE:
144 break;
145 }
146 }
147
148 /*
149 * Free memory of BlockObj
150 */
151
152 void
BLdestroy(Blockobj * bl)153 BLdestroy(Blockobj *bl)
154 {
155 STRdestroy(bl->Blockname);
156 BLdatadestroy(bl);
157 free(bl);
158 }
159
160
161 void
BLcpy(Blockobj * dest,Blockobj * orig)162 BLcpy(Blockobj *dest, Blockobj *orig)
163 {
164 BLsetName(dest,BLgetName(orig));
165 dest->btype = orig->btype;
166
167 switch (BLgetDatatype(orig)) {
168 case BDATA_FILE:
169 BLsetFile(dest, STRget(orig->data.filename));
170 break;
171 case BDATA_GREF:
172 BLsetGref(dest, orig->data.gs);
173 break;
174 case BDATA_TEXT:
175 BLsetText(dest, orig->data.text);
176 break;
177 case BDATA_NONE:
178 break;
179 }
180 }
181
182
183 /*
184 * BLgetNumLines() returns the number of lines for the Text record
185 * It returns -1 if this isn't the type of record.
186 */
187
188 int
BLgetNumLines(Blockobj * bl)189 BLgetNumLines(Blockobj *bl)
190 {
191 switch (BLgetDatatype(bl)) {
192 case BDATA_TEXT:
193 return(STAgetTop(bl->data.text));
194 default:
195 return(-1);
196 }
197 ;
198 }
199
200
201 /*
202 * BLgetLine() returns a character pointer to the line for the Text data type
203 */
204
205 char*
BLgetLine(Blockobj * bl,int lineno)206 BLgetLine(Blockobj *bl, int lineno)
207 {
208 switch (BLgetDatatype(bl)) {
209 case BDATA_TEXT:
210 return(STRget(STAgetEntry(bl->data.text, lineno)));
211 case BDATA_NONE:
212 case BDATA_FILE:
213 case BDATA_GREF:
214 break;
215 }
216 return(NULL);
217 }
218
219
220 /*
221 * BLsetFile() sets up a block to contain a file reference.
222 * Really handy for the server.
223 */
224
225 void
BLsetFile(Blockobj * bl,char * filename)226 BLsetFile(Blockobj *bl, char *filename)
227 {
228 /** Reset data field and put in new values **/
229
230 BLdatadestroy(bl);
231
232 bl->datatype = BDATA_FILE;
233 bl->data.filename = STRnew();
234
235 STRset(bl->data.filename, filename);
236 }
237
238
239 /*
240 * BLsetText sets everything up for storing text, if the optional parameter
241 * sta is set, it copies it in.
242 */
243
244 void
BLsetText(Blockobj * bl,StrArray * sta)245 BLsetText(Blockobj *bl, StrArray *sta)
246 {
247 /** Reset data field and put in new values **/
248 if (BLgetDatatype(bl) != BDATA_TEXT) {
249 BLdatadestroy(bl);
250
251 bl->datatype = BDATA_TEXT;
252 bl->data.text = STAnew(10);
253 }
254 if (sta != NULL) {
255 STAcpy(bl->data.text, sta);
256 }
257 }
258
259
260 /*
261 * Keep data in memory, text is a line to be added to the text
262 */
263
264 void
BLaddText(Blockobj * bl,char * text)265 BLaddText(Blockobj *bl, char *text)
266 {
267 String *tempstr;
268
269 BLsetText(bl, NULL);
270
271 tempstr = STRnew();
272
273 STRset(tempstr, text);
274 STApush(bl->data.text, tempstr);
275
276 STRdestroy(tempstr);
277 }
278
279 /*
280 * Make the block a gopher-reference
281 */
282
283 void
BLsetGref(Blockobj * bl,GopherObj * gs)284 BLsetGref(Blockobj *bl, GopherObj *gs)
285 {
286 /** Reset data field and put in new values **/
287 BLdatadestroy(bl);
288
289 bl->datatype = BDATA_GREF;
290
291 bl->data.gs = GSnew();
292
293 GScpy(bl->data.gs, gs);
294
295 GSdestroy(gs);
296 }
297
298
299 /*
300 * BLtoNet() transmits the block as per gopher+ protocol
301 * if the data field is a file, it opens it and sends it out
302 */
303
304 void
BLtoNet(Blockobj * bl,int fd,boolean showheader)305 BLtoNet(Blockobj *bl, int fd, boolean showheader)
306 {
307 FILE *infile;
308 int i;
309 char outputline[512];
310
311 /** Switch on data type **/
312
313 if (showheader) {
314 snprintf(outputline, sizeof(outputline), "+%s:", BLgetName(bl));
315 writestring(fd, outputline);
316 }
317
318 switch (BLgetDatatype(bl)) {
319
320 case BDATA_GREF:
321 writestring(fd, " ");
322 GStoNet(bl->data.gs,fd, GSFORM_G0, NULL);
323 break;
324
325 case BDATA_TEXT:
326 writestring(fd, "\r\n");
327 for (i=0; i<STAgetTop(bl->data.text); i++) {
328 writestring(fd, " ");
329 writestring(fd, STRget(STAgetEntry(bl->data.text, i)));
330 writestring(fd, "\r\n");
331 }
332 break;
333
334 case BDATA_FILE:
335 writestring(fd, "\r\n");
336
337 if ((infile = fopen(STRget(bl->data.filename), "r"))==NULL)
338 break;
339
340 while (fgets(outputline, sizeof(outputline), infile)!=NULL) {
341 ZapCRLF(outputline);
342 writestring(fd, " ");
343 writestring(fd, outputline);
344 writestring(fd, "\r\n");
345 }
346 fclose(infile);
347 break;
348 case BDATA_NONE:
349 break;
350 }
351 }
352
353
354 /*
355 * BLfromNet() assumes that the initial '+' in the data stream has been read,
356 * along with the blockname, up to the ':', but not anything after..
357 *
358 * It then executes most of the state diagram, it returns when it has
359 * encountered EOF, or encounters the next '+', or '.'
360 *
361 * Returns the following:
362 * 0 for EOF encountered, block retrieved successfully
363 * 1 for successful retrieve, and another block coming
364 * neg value for error conditions from read routines and botched block vals
365 */
366
367 int
BLfromNet(Blockobj * bl,int fd,char * blockname)368 BLfromNet(Blockobj *bl, int fd, char *blockname)
369 {
370 char inputline[512];
371 int err;
372
373
374 /*** State: _GotBlockName_ ***/
375
376 BLsetName(bl, blockname);
377
378 /** Find out if there's a gopher reference **/
379 if ((err = readrecvbuf(fd, inputline, 1)) <=0) {
380 return(err);
381 }
382
383 if (*inputline == ' ') {
384 /** GREF coming up, State: _GotBnameSpace_ **/
385 GopherObj *gs;
386
387 gs = GSnew();
388 GSfromNet(gs, fd);
389 BLsetGref(bl, gs);
390 /** read up to the next \r\n+ **/
391 while (1) {
392 if ((err= readrecvbuf(fd, inputline, 1)) <= 0)
393 return(err);
394 if (*inputline == '+')
395 return(1);
396 else {
397 err = readline(fd, inputline, sizeof(inputline));
398 if (err <= 0)
399 return(err); /*** Error ***/
400 }
401 }
402 }
403
404 /** Okay, let's just stick the text in verbatim **/
405
406 /** get rid of remaining newline **/
407 readline(fd, inputline, sizeof(inputline));
408
409 /** State: _FirstChar_ **/
410
411 while (1) {
412 /** Check for plus **/
413 if ((err= readrecvbuf(fd, inputline, 1)) <=0)
414 return(err);
415
416 if (*inputline == '+')
417 return(1);
418 /*** Return to state _NewBlock_ ***/
419
420 if (*inputline == '.') {
421 readline(fd, inputline, sizeof(inputline));
422 return(0);
423 }
424
425 if (*inputline == ' ') {
426 /** add a line otherwise State: _Addline_ **/
427 readline(fd, inputline, sizeof(inputline));
428 ZapCRLF(inputline);
429 BLaddText(bl, inputline);
430 } else {
431 /** malformed block line received
432 proceed as if it was OK, but don't add the line **/
433 readline(fd, inputline, sizeof(inputline));
434 }
435 }
436 }
437
438
439 int
BLAsearch(BlockArray * bla,char * bname)440 BLAsearch(BlockArray *bla, char *bname)
441 {
442 int i;
443
444 if (bla == NULL)
445 return(-1);
446
447 for (i=0; i<BLAgetTop(bla); i++) {
448 if (strcmp(BLgetName(BLAgetEntry(bla,i)), bname)==0)
449 return(i);
450 }
451
452 return(-1);
453 }
454
455