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