refdb  0.9.9-1
About: RefDB is a reference database and bibliography tool for SGML, XML, and LaTeX documents.
  Fossies Dox: refdb-0.9.9-1.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
refdb-client.c
Go to the documentation of this file.
1 /*+++++++++++++++++
2  refdb-client.c - functions common to all client applications
3  markus@mhoenicka.de 2000-07-03
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 
19  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
20 
21 /* socket related includes */
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <sys/un.h>
27 #include <netdb.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "refdb.h"
34 #include "connect.h"
35 #include "page.h"
36 #include "readln.h" /* for COMMAND definition */
37 #include "refdb-client.h"
38 #include "linklist.h" /* linked lists, needed by cgi.h */
39 #include "pref.h" /* for PREFS_BUF_LEN, depends on linklist.h */
40 #include "enigma.h" /* for password encryption */
41 #include "cgi.h" /* cgi-related stuff */
42 #include "strfncs.h" /* mstrcat */
43 #include "readris.h"
44 
45 extern int n_verbose;
46 extern int n_done;
47 extern int n_broken_pipe;
48 extern int n_abort_connect;
49 extern int n_cgi;
50 extern char server_ip[];
51 extern char port_address[];
52 extern char the_pager[];
53 extern char username[];
54 extern char passwd[];
55 extern const char cs_term[];
56 
57 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
58  connect_to_server(): establish a connection to the application server
59 
60  int connect_to_server 0 if successful, not zero if failure
61 
62  int *n_sockfd pointer to the variable which receives the socket
63  file descriptor if successful
64 
65  char *server_ip ip address of server
66 
67  char *port_address port address of server
68 
69  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
70 int connect_to_server (int* n_sockfd, char* server_ip, char* port_address)
71 {
72  int n_len; /* length of the address structure */
73  struct sockaddr_in address; /* the server address */
74  int n_result; /* connection result */
75  FILE* errstream;
76 
77  errstream = (n_cgi) ? stdout : stderr;
78 
79  *n_sockfd = socket(AF_INET, SOCK_STREAM, 0);
80  address.sin_family = AF_INET;
81  address.sin_addr.s_addr = inet_addr(server_ip);
82  address.sin_port = htons(atoi(port_address));
83  n_len = sizeof(address);
84 
85  n_result = connect(*n_sockfd, (struct sockaddr *)&address, n_len);
86 
87  if (n_result != 0) {
89  fprintf(errstream, "could not establish server connection\n");
90  if (n_verbose) {
91  fprintf(errstream, "(1) Check the settings for the server IP address and the port. You can set these either on the command line or in your init file\n(2)The refdb server may be stopped or crashed or otherwise unwilling to process the request.\n(3) The machine running the server may be down or overloaded.\n");
92  }
93  }
94 
95  return n_result;
96 }
97 
98 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
99  init_dialog(): starts the client-server dialog
100 
101  int init_dialog returns 0 if ok, 1 if an error occurred
102 
103  int n_sockfd file descriptor of the socket of our connection
104 
105  char* passwd ptr to a string with the unencrypted password
106 
107  char* inbuffer ptr to a string that will receive the server response
108  string must hold at least COMMAND_INBUF_LEN chars
109 
110  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
111 int init_dialog(int n_sockfd, char* passwd, char* inbuffer) {
112  int numbyte;
113  int cs_status;
114  char outbuffer[16]; /* should be way enough for version numbers */
115  char scrambled_passwd[PASSWD_LENGTH+1];
116  FILE* errstream;
117 
118  errstream = (n_cgi) ? stdout : stderr;
119 
120  /* initialize string with zeros to terminate it*/
121  memset((void*)scrambled_passwd, (int)'\0', (size_t)(PASSWD_LENGTH+1));
122 
123  /* send our protocol version to server */
124  sprintf(outbuffer, "%d", REFDB_PROTOCOL_VERSION);
125 
126  numbyte = tiwrite(n_sockfd, outbuffer, TERM_YES);
127  if (numbyte == -1) {
129  fprintf(errstream, "could not write to refdbd\n");
130  return 1;
131  }
132 
133  /* read status */
134  if ((cs_status = read_status(n_sockfd))) {
136  fprintf(errstream, get_status_msg(cs_status));
137  fprintf(errstream, "\n");
138  return 1;
139  }
140 
141  /* read pseudo-random string for password encryption */
142  numbyte = tread(n_sockfd, inbuffer, COMMAND_INBUF_LEN);
143 
144  if (numbyte == -1) {
146  fprintf(errstream, "could not read from refdbd\n");
147  return 1;
148  }
149 
150  if (strlen(inbuffer) != 12) {
152  fprintf(errstream, "server error: incorrect scramble string\n");
153  return 1;
154  }
155 
156  if (enigma_encrypt(passwd, scrambled_passwd, inbuffer)) {
158  fprintf(errstream, "password encryption error\n");
159  return 1;
160  }
161 
162  numberize_passwd(passwd, scrambled_passwd);
163 
164 /* strcpy(passwd, scrambled_passwd); */
165 
166  return 0;
167 }
168 
169 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
170  listvalue(): lists various things
171 
172  int listvalue 0 if successful, 1 if error
173 
174  char *arg search string; if this is a cgi request, this ptr must be
175  cast to struct liliform* to access the linked list with
176  form values
177 
178  char *command the command name
179 
180  char *help_string the string to display with the -h option
181 
182  char *err_string a string that identifies an error condition returned
183  by the application server
184 
185  int n_with_summary if 1, summary will be retrieved
186 
187  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
188 int listvalue (char* arg, char* command, char* help_string, char* err_string, int n_with_summary)
189 {
190  struct simplelistvals slvals;
191  struct liliform* ptr_current;
192  char scrambled_passwd[PASSWD_LENGTH*3+1];
193  char inbuffer[COMMAND_INBUF_LEN] = "";
194  int retval;
195  FILE* errstream;
196 
197  if (!command || !*command) {
198  /* nothing to do */
199  return 1;
200  }
201 
202  errstream = (n_cgi) ? stdout : stderr;
203 
204  slvals.n_file_open = 0;
205  slvals.n_file_append = 0;
206  slvals.n_pipe = 0;
207  slvals.outfile = NULL;
208  slvals.outpipe = NULL;
209 
210  /* get us some buffer for output */
211  slvals.outbuffer = malloc(strlen(arg) + strlen(command) + 128);
212  if (slvals.outbuffer == NULL) {
213  return 1;
214  }
215  slvals.outbuffer[0] = '\0';
216 
217  if (!n_cgi) {
218  if (strncmp(arg, "-h", 2) == 0) {
220  fprintf(errstream, help_string);
221  free(slvals.outbuffer);
222  return 0;
223  }
224  }
225 
226  if (connect_to_server(&slvals.n_sockfd, server_ip, port_address) != 0) {
228  fprintf(errstream, "could not connect to server\n");
229  free(slvals.outbuffer);
230  return 1;
231  }
232 
233  strcpy(scrambled_passwd, passwd);
234 
235  if (init_dialog(slvals.n_sockfd, scrambled_passwd, inbuffer)) {
237  fprintf(errstream, "password transfer failed\n");
238  close(slvals.n_sockfd);
239  free(slvals.outbuffer);
240  return 1;
241  }
242 
243  sprintf(slvals.outbuffer, "%s ", command);
244  if (!n_cgi) {
245  if (arg && *arg) {
246  strcat(slvals.outbuffer, arg);
247  }
248  }
249  else {
250  ptr_current = get_liliform((struct liliform*)arg, "dbregexp");
251  if (ptr_current) {
252  strcat(slvals.outbuffer, ptr_current->value);
253  }
254  }
255  strcat(slvals.outbuffer, " -u ");
256  strcat(slvals.outbuffer, username);
257  if (strlen(passwd) > 0) {
258  strcat(slvals.outbuffer, " -w ");
259  strcat(slvals.outbuffer, scrambled_passwd);
260  }
261 
262  if (n_cgi) {
263  strcat(slvals.outbuffer, " -t cgi");
264  }
265 
266  retval = getsimplelist(&slvals, n_with_summary);
267 
268  if (!retval && err_string && *err_string
269  && strncmp(slvals.inbuffer, err_string, strlen(err_string)) == 0) {
270  retval = 1;
271  }
272  close(slvals.n_sockfd);
273  free(slvals.outbuffer);
274 
275  return retval;
276 }
277 
278 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
279  getsimplelist(): convenience fn to retrieve data from the server
280  based on a simple command, followed by data from
281  the server, followed by an acknowledgement by the
282  client
283 
284  int getsimplelist 1 if failed, 0 if ok
285 
286  struct simplelistvals* slvals ptr to a structure containing all necessary
287  values to run the command and collect the data
288 
289  int n_with_summary if 1, the fn reads a summary from the server
290  after the data proper are transmitted; if 2, the fn
291  continues to read the result string even if a previous
292  error was signalled
293 
294  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
295 int getsimplelist(struct simplelistvals* slvals, int n_with_summary) {
296  int numbyte;
297  int n_read_done = 0;
298  size_t byte_written = 0;
299  FILE *pagerfp; /* ptr to file */
300  FILE* errstream;
301  int n_curr_trailing_z = 0;
302  int n_last_trailing_z = 0;
303  int cs_status;
304 
305  slvals->inbuffer[0] = '\0'; /* terminate just in case we fail and the
306  caller checks the contents */
307  errstream = (n_cgi) ? stdout : stderr;
308 
309  send_status(slvals->n_sockfd, 0, TERM_NO);
310 
311  numbyte = tiwrite(slvals->n_sockfd, slvals->outbuffer, TERM_YES);
312  if (numbyte == -1) {
314  fprintf(errstream, get_status_msg(110));
315  fprintf(errstream, "\n");
316  return 1;
317  }
318 
319  /* check server status */
320 
321  /* ToDo: must continue even if createdb returns error */
322  cs_status = read_status(slvals->n_sockfd);
323 
324  if (cs_status != 0 /* success */
325  && cs_status != 803) { /* partial success */
327  fprintf(errstream, get_status_msg(cs_status));
328  fprintf(errstream, "\n");
329  if (n_with_summary != 2) {
330  return 1;
331  }
332  }
333 
334  /* openpager and open_outfile are guaranteed to return a valid file/pipe -
335  and be it stdout */
336  if (slvals->n_file_open) {
337  pagerfp = open_outfile(slvals->outfile, 0);
338  }
339  else if (slvals->n_file_append) {
340  pagerfp = open_outfile(slvals->outfile, 1);
341  }
342  else if (slvals->n_pipe) {
343  pagerfp = openpager(slvals->outpipe);
344  }
345  else {
346  pagerfp = openpager(the_pager);
347  }
348 
349  do {
350  numbyte = tread(slvals->n_sockfd, slvals->inbuffer, OUTBUF_LEN);
351  if (numbyte == -1) {
352  fprintf(stderr, "could not read from refdbd. Stop\n");
353  if (slvals->n_file_open || slvals->n_file_append) {
354  close_outfile(pagerfp);
355  }
356  else {
357  closepager(pagerfp);
358  }
359  n_broken_pipe = 0;
360  return 1;
361  }
362 
363  n_curr_trailing_z = get_trailz(slvals->inbuffer, numbyte);
364 
365  if (numbyte >= TERM_LEN) {
366  if (n_curr_trailing_z >= TERM_LEN) {
367  /* terminator is complete */
368  n_read_done++;
369  /* send back confirmation to the server */
370  send_status(slvals->n_sockfd, 0, TERM_NO);
371  }
372  }
373  else if (n_curr_trailing_z == numbyte
374  && n_curr_trailing_z + n_last_trailing_z >= TERM_LEN) {
375  /* terminator is complete including the previous cycle */
376  n_read_done++;
377  /* send back confirmation to the server */
378  send_status(slvals->n_sockfd, 0, TERM_NO);
379  }
380  else if (n_curr_trailing_z == numbyte) {
381  /* terminator is still incomplete */
382  n_last_trailing_z += n_curr_trailing_z;
383  continue;
384  }
385 
386  /* write numbyte chars to output, unless this is the last chunk: we do not
387  want to write the terminating \0 */
388  if (!n_broken_pipe) {
389  if (n_last_trailing_z) {
390  byte_written += fwrite(cs_term, sizeof(char), n_last_trailing_z, pagerfp);
391  }
392  byte_written += fwrite(slvals->inbuffer, sizeof(char), numbyte-n_curr_trailing_z, pagerfp);
393  }
394 /* printf("%s<<\n", slvals->inbuffer); */
395  if (n_read_done && n_with_summary ==1) {
396  send_status(slvals->n_sockfd, 0, TERM_NO);
397  cs_status = read_status(slvals->n_sockfd);
398 
399  if (cs_status != 0 /* success */
400  && cs_status != 803) { /* partial success */
402  fprintf(errstream, get_status_msg(cs_status));
403  return 1;
404  }
405 
406  numbyte = tread(slvals->n_sockfd, slvals->inbuffer, OUTBUF_LEN);
407  if (numbyte == -1) {
408  fprintf(stderr, "could not read from refdbd. Stop\n");
409  n_broken_pipe = 0;
410  return 1;
411  }
412 
413  send_status(slvals->n_sockfd, 0, TERM_NO);
414  }
415 
416  if (!n_read_done) {
417  n_last_trailing_z = n_curr_trailing_z;
418  }
419  } while (!n_read_done);
420 
421  if (slvals->n_file_open || slvals->n_file_append) {
422  close_outfile(pagerfp);
423  fprintf(errstream, "%d byte written to %s\n", byte_written, slvals->outfile);
424  }
425  else {
426  closepager(pagerfp);
427  }
428 
429  if (n_with_summary == 1) {
430  fprintf(errstream, "%s", slvals->inbuffer);
431  }
432 
433  /* reset */
434  n_broken_pipe = 0;
435 
436  return 0;
437 }
438 
439 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
440  build_batchcommand(): assembles a command string for commands run
441  in batch mode that contains only the relevant
442  options and parameters. Must be called after
443  getopt has dealt with all options relevant to
444  the main program.
445 
446  char* build_batchcommand returns a ptr to a string containing the
447  command string or NULL in case of an error.
448  The returned string is allocated with malloc()
449  and must be freed by the calling function
450 
451  int argc number of arguments
452 
453  char** argv array of strings containing the arguments
454 
455  int optind index into argv
456 
457  char* s string containing the command
458 
459  char* the_command string containing all command options
460 
461  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
462 char* build_batchcommand(int argc, char** argv, int optind, char* s, char* the_command) {
463  char *batchstring, *new_batchstring;
464  size_t stringsize;
465 
466  stringsize = strlen(s)+2;
467  batchstring = malloc(stringsize);
468  if (batchstring == NULL) {
469  return NULL;
470  }
471  strcpy(batchstring, s);
472 
473  if (*the_command) {
474  if ((new_batchstring = mstrcat(batchstring, the_command, &stringsize, 0)) == NULL) {
475  free(batchstring);
476  return NULL;
477  }
478  else {
479  batchstring = new_batchstring;
480  }
481  }
482 
483  if (argv[optind] && argv[optind][0]) {
484  int i = optind;
485  while (argv[i] && argv[i][0]) {
486  if ((new_batchstring = mstrcat(batchstring, " ", &stringsize, 0)) == NULL) {
487  free(batchstring);
488  return NULL;
489  }
490  else {
491  batchstring = new_batchstring;
492  }
493  if ((new_batchstring = mstrcat(batchstring, argv[i], &stringsize, 0)) == NULL) {
494  free(batchstring);
495  return NULL;
496  }
497  else {
498  batchstring = new_batchstring;
499  }
500  i++;
501  }
502  }
503  return batchstring;
504 }
505 
506 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
507  send_xml_data(): reads xml data from an input stream and sends the
508  data chunk-wise to the server
509 
510  int send_xml_data returns 0 if ok, > 0 if there was an error
511  error codes: 1 = data read error
512  2 = write to server error
513  3 = read from server error
514  4 = server error
515  5 = out of memory
516 
517  FILE *infp ptr to a FILE struct for the data input stream
518 
519  FILE *pagerfp ptr to a FILE struct for the output stream for server
520  messages
521 
522  FILE *errstream ptr to a FILE struct for error messages
523 
524  int n_sockfd file descriptor of client/server socket connection
525 
526  size_t* ptr_byte_written ptr to var that will be incremented by the number
527  of bytes written to a stream
528 
529  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
530 int send_xml_data(FILE *infp, FILE *pagerfp, FILE *errstream, int n_sockfd, size_t* ptr_byte_written) {
531  int n_style_file_done = 0;
532  int numbyte;
533  int n_read_done = 0;
534  int n_chunk_count = 0;
535  int num_trailz;
536  int cs_status;
537  size_t n_result;
538  size_t n_chunksize;
539  char* buffer;
540  char thebytes[11];
541  char inbuffer[COMMAND_INBUF_LEN];
542 
543 
544  n_chunksize = XMLPARSE_CHUNKSIZE;
545  buffer = malloc(n_chunksize);
546  if (buffer == NULL) {
547  return 5;
548  }
549 
550  buffer[0] = '\0';
551 
552  do {
553  /* ------------------------------------------------------------ */
554  /* PHASE 1 */
555  /* read next chunk and count the bytes */
556  /* the data will be parsed by expat. This can handle XML data chunk-wise, so we don't have to worry about the document structure here */
557  /* printf("start readstyle"); */
558  /* fflush(stdout); */
559  n_result = fread(buffer, 1, n_chunksize, infp);
560 
561 /* printf("end readstyle\n"); */
562 /* fflush(stdout); */
563  if (n_result < n_chunksize && !feof(infp)) {
564  /* no more data available */
565  fprintf(errstream, get_status_msg(401));
566  fprintf(errstream, "\n");
567  send_status(n_sockfd, 401, TERM_NO);
568  free(buffer);
569  return 1;
570  }
571  else if (n_result < n_chunksize) {
572  n_style_file_done++;
573  }
574 
575  if (n_result > 0) { /* if chunk is not empty */
576  /* send length information to database server */
577  send_status(n_sockfd, 0, TERM_NO);
578 
579  sprintf(thebytes, "%d", n_result);
580  numbyte = tiwrite(n_sockfd, thebytes, TERM_YES); /* is 10 on the safe side? */
581 /* printf("%s\n", thebytes); */
582 /* printf("%s\n", buffer); */
583 
584  if (numbyte == -1) {
585  fprintf(errstream, "could not write to refdbd. Stop\n");
586  free(buffer);
587  return 2;
588  }
589 
590  /* ------------------------------------------------------------ */
591  /* PHASE 2 */
592  /* wait for acknowledgement of database server */
593  if ((cs_status = read_status(n_sockfd))) {
594  fprintf(errstream, get_status_msg(cs_status));
595  fprintf(errstream, "\n");
596  return 1;
597  }
598 
599  /* ------------------------------------------------------------ */
600  /* PHASE 3 */
601  /* send a dataset */
602  numbyte = iwrite(n_sockfd, buffer, n_result);
603 /* printf("%s\n", buffer); */
604  if (numbyte == -1) {
605  fprintf(errstream, "could not write to refdbd. Stop\n");
606  free(buffer);
607  return 2;
608  }
609 
610  /* ------------------------------------------------------------ */
611  /* PHASE 4 */
612  /* read messages from application server */
613  n_read_done = 0;
614 
615  cs_status = read_status(n_sockfd);
616  if (cs_status == 400) {
617  /* retrieve server-generated error message */
618  do {
619  numbyte = tread(n_sockfd, inbuffer, OUTBUF_LEN);
620  /* printf("phase4 server reply:%s<<\n", inbuffer); */
621  if (numbyte == -1) {
622  /* timeout while reading */
623  fprintf(errstream, get_status_msg(109));
624  return 3;
625  }
626 
627  /* we rely on the fact that the server reply is no more than
628  OUTBUF_LEN in length */
629  if ((num_trailz = get_trailz(inbuffer, numbyte)) >= TERM_LEN) { /* if transmission ends */
630  n_read_done++;
631  }
632  /* write numbyte chars to output, unless this is the last chunk:
633  we do not want to write the terminating \0 */
634  if (!n_broken_pipe) {
635  *ptr_byte_written += fwrite(inbuffer, sizeof(char), numbyte-num_trailz, pagerfp);
636  }
637  /* printf("%s", inbuffer); */
638  } while (!n_read_done);
639 
640  return 4;
641  }
642  /* else: status is 403, chunk added successfully */
643 
644 
645  n_chunk_count++;
646  }
647 /* else { */
648 /* } */
649  } while (!n_style_file_done);
650 
651  free(buffer);
652  return 0;
653 }
654 
655 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
656  send_ris_data(): reads ris data from an input stream and sends the
657  data set-wise to the server
658 
659  int send_ris_data returns 0 if ok, > 0 if there was an error
660  error codes: 1 = data read error
661  2 = write to server error
662  3 = read from server error
663  4 = server error
664  5 = out of memory
665 
666  FILE *infp ptr to a FILE struct for the data input stream
667 
668  FILE *pagerfp ptr to a FILE struct for the output stream for server
669  messages
670 
671  FILE *errstream ptr to a FILE struct for error messages
672 
673  int n_sockfd file descriptor of client/server socket connection
674 
675  char** ptr_ris_set_buffer ptr to an allocated buffer, may be realloc'd
676 
677  size_t* ptr_n_setlength ptr to length of ris_set_buffer
678 
679  int* ptr_n_setcount ptr to set counter
680 
681  char* default_ris ptr to default ris filename
682 
683  int n_cgi if 1, assume CGI data
684 
685  size_t* ptr_byte_written ptr to var that will be incremented by the number
686  of bytes written to a stream
687 
688  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
689 int send_ris_data(FILE *infp, FILE *pagerfp, FILE *errstream, int n_sockfd, char** ptr_ris_set_buffer, size_t* ptr_n_setlength, int* ptr_n_setcount, char* default_ris, int n_cgi, size_t* ptr_byte_written) {
690  int n_result;
691  int n_read_done = 0;
692  int n_ris_file_done = 0;
693  int numbyte;
694  int num_trailz;
695  int cs_status;
696  char thebytes[11] = "";
697  char inbuffer[COMMAND_INBUF_LEN];
698 
699 
700  do {
701  /* ------------------------------------------------------------ */
702  /* PHASE 1 */
703  /* read next dataset and count the bytes */
704  if (!n_cgi) {
705  (*ptr_ris_set_buffer)[0] = '\0';
706  *ptr_n_setlength = TERM_LEN; /* for the terminating \0's */
707  n_result = read_ris_set(infp, default_ris, ptr_ris_set_buffer, ptr_n_setlength, 0);
708 
709  if (n_result == 0) {
711  fprintf(errstream, get_status_msg(401));
712  fprintf(errstream, "\n");
713  send_status(n_sockfd, 401, TERM_NO);
714  return 1;
715  }
716  else if (n_result == 2) {
717  n_ris_file_done++;
718  }
719  }
720  else { /* if cgi, there is only one set to deal with */
721  n_ris_file_done++;
722  }
723 
724  if (*ptr_n_setlength != TERM_LEN) { /* if dataset is not empty */
725  /* send length information to database server */
726  send_status(n_sockfd, 0, TERM_NO);
727 
728  sprintf(thebytes, "%d", *ptr_n_setlength);
729  numbyte = tiwrite(n_sockfd, thebytes, TERM_YES); /* is 10 on the safe side? */
730  /* printf("%s\n", thebytes); */
731 
732  if (numbyte == -1) {
734  fprintf(errstream, "could not write to refdbd. Stop\n");
735  return 2;
736  }
737 
738  /* ------------------------------------------------------------ */
739  /* PHASE 2 */
740  /* wait for acknowledgement of database server */
741  if ((cs_status = read_status(n_sockfd))) {
742  fprintf(errstream, get_status_msg(cs_status));
743  fprintf(errstream, "\n");
744  return 1;
745  }
746 
747  /* ------------------------------------------------------------ */
748  /* PHASE 3 */
749  /* send a dataset */
750  numbyte = iwrite(n_sockfd, *ptr_ris_set_buffer, *ptr_n_setlength);
751  if (numbyte == -1) {
753  fprintf(errstream, "could not write to refdbd. Stop\n");
754  return 2;
755  }
756 
757  /* ------------------------------------------------------------ */
758  /* PHASE 4 */
759  /* read messages from application server */
760  n_read_done = 0;
761 
762  cs_status = read_status(n_sockfd);
763  if (cs_status == 400
764  || cs_status == 407
765  || cs_status == 408
766  || cs_status == 413
767  || cs_status == 414
768  || cs_status == 702) {
769  /* retrieve server-generated error/status message */
770  do {
771  numbyte = tread(n_sockfd, inbuffer, OUTBUF_LEN);
772  if (numbyte == -1) {
774  fprintf(errstream, get_status_msg(109));
775  return 3;
776  }
777 
778  /* we rely on the fact that the server reply is no more than
779  OUTBUF_LEN in length */
780  if ((num_trailz = get_trailz(inbuffer, numbyte)) >= TERM_LEN) { /* if transmission ends */
781  n_read_done++;
782  }
783  /* write numbyte chars to output, unless this is the last chunk:
784  we do not want to write the terminating \0 */
785  if (!n_broken_pipe) {
786  if (!n_cgi) {
787  *ptr_byte_written += fwrite(inbuffer, sizeof(char), numbyte-num_trailz, pagerfp);
788  }
789  }
790 /* printf("%s", inbuffer); */
791  } while (!n_read_done);
792 
793  if (cs_status == 400
794  || cs_status == 702) {
795  return 4;
796  }
797  /* else: status is 408, dataset added successfully */
798  }
799 
800  (*ptr_n_setcount)++;
801  }
802  else {
803  /* we're done sending datasets */
804 /* send_status(n_sockfd, 402, TERM_NO); */
805  }
806  } while (!n_ris_file_done);
807 
808  return 0;
809 }
810 
811 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
812  read_terminated_string(): reads a terminated string, usually a dataset
813 
814  size_t read_terminated_string returns the number of bytes written to
815  pagerfp. In case of an error, *ptr_error
816  is set to 1
817 
818  struct simplelistvals* ptr_slvals ptr to struct with data for dialog
819 
820  FILE *pagerfp ptr to a FILE struct for the output stream for server
821  messages
822 
823  int* ptr_error ptr to error variable
824 
825  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
826 size_t read_terminated_string(struct simplelistvals* ptr_slvals, FILE* pagerfp, int* ptr_error) {
827  int n_read_done = 0;
828  int n_curr_trailing_z = 0;
829  int n_last_trailing_z = 0;
830  size_t byte_written = 0;
831  int numbyte = 0;
832 
833  *ptr_error = 0;
834 
835  do { /* loop until a terminated string is complete */
836 /* printf("looking for a terminated string...\n"); */
837  if (n_curr_trailing_z) {
838  numbyte += tread(ptr_slvals->n_sockfd, ptr_slvals->inbuffer+numbyte, TERM_LEN-n_curr_trailing_z);
839  }
840  else {
841  numbyte = tread(ptr_slvals->n_sockfd, ptr_slvals->inbuffer, OUTBUF_LEN);
842  }
843 
844  if (numbyte == -1) {
845  fprintf(stderr, get_status_msg(109));
846  fprintf(stderr, "\n");
847  *ptr_error = 1;
848  return 0;
849  }
850 
851  n_curr_trailing_z = get_trailz(ptr_slvals->inbuffer, numbyte);
852 /* printf("n_curr_trailing_z went to %d<<n_last_trailing_z went to %d<<numbyte went to %d\n", n_curr_trailing_z, n_last_trailing_z, numbyte); */
853  if (numbyte >= TERM_LEN) {
854  if (n_curr_trailing_z >= TERM_LEN) {
855  /* terminator is complete */
856 /* printf("found complete terminator\n"); */
857  n_last_trailing_z = 0;
858  n_read_done++;
859  /* send back confirmation to the server */
860  send_status(ptr_slvals->n_sockfd, 0, TERM_NO);
861  }
862  else {
863  /* terminator is still incomplete */
864 /* printf("incomplete terminator, trying again\n"); */
865  }
866  }
867  else if (n_curr_trailing_z == numbyte
868  && n_curr_trailing_z + n_last_trailing_z >= TERM_LEN) {
869 /* printf("completed terminator\n"); */
870  n_last_trailing_z = 0;
871  /* terminator is complete including the previous cycle */
872  n_read_done++;
873  /* send back confirmation to the server */
874  send_status(ptr_slvals->n_sockfd, 0, TERM_NO);
875  }
876  else if (n_curr_trailing_z == numbyte) {
877  /* terminator is still incomplete */
878 /* printf("incomplete terminator, trying again\n"); */
879  n_last_trailing_z += n_curr_trailing_z;
880  continue;
881  }
882 
883  /* write numbyte chars to output, unless this is the last chunk: we do not
884  want to write the terminating \0 */
885  if (!n_broken_pipe) {
886  if (n_last_trailing_z) {
887 /* printf("writing n_last_trailing_z\n"); */
888  byte_written += fwrite(cs_term, sizeof(char), n_last_trailing_z, pagerfp);
889  }
890 /* printf("writing numbytes\n"); */
891  byte_written += fwrite(ptr_slvals->inbuffer, sizeof(char), numbyte-n_curr_trailing_z, pagerfp);
892  }
893 /* printf("n_read_done is %d<<n_done is %d<<\n", n_read_done, n_done); */
894 /* printf("inbuffer went to:%s<<\nn_read_done is %d<<\n", ptr_slvals->inbuffer, n_read_done); */
895  fflush(stdout);
896  if (!n_read_done) {
897  n_last_trailing_z = n_curr_trailing_z;
898  }
899  } while (!n_read_done);
900 
901  return byte_written;
902 }
903 
904 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
905  pipehandler(): handler for the SIGPIPE signal. Sets the global
906  variable n_broken_pipe to non-zero. This condition
907  can be used by a function writing to a pipe to abort
908  further write attempts. Any function that uses
909  n_broken_pipe should reset it to zero when it is done
910  dealing with the broken pipe.
911 
912  void pipehandler
913 
914  int sig the received signal
915 
916  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
917 void pipehandler(int sig) {
918  n_broken_pipe = 1;
919 }
920 
921 /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
922  inthandler(): handler for the SIGINT signal. Sets the global
923  variable n_abort_connect to non-zero. This function
924  can be used to make writing to and reading from
925  the application server interruptible. Any function
926  that uses n_abort_connect should reset it to zero
927  when it is done.
928 
929  void inthandler
930 
931  int sig the received signal
932 
933  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
934 void inthandler(int sig) {
935  n_abort_connect = 1;
936  fprintf(stderr, "aborting...\n");
937 }
938