~ubuntu-branches/ubuntu/warty/swish-e/warty

« back to all changes in this revision

Viewing changes to src/extprog.c

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Drolez
  • Date: 2004-03-11 08:41:07 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040311084107-7vp0mu82blq1qjvo
Tags: 2.4.1-3
Oops ! A comment was not removed to disable interactive compilation.
Closes: Bug#237332

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
** Copyright (C) 1995, 1996, 1997, 1998 Hewlett-Packard Company
 
3
** Originally by Kevin Hughes, kev@kevcom.com, 3/11/94
 
4
**
 
5
** This program and library is free software; you can redistribute it and/or
 
6
** modify it under the terms of the GNU (Library) General Public License
 
7
** as published by the Free Software Foundation; either version 2
 
8
** of the License, or 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 (Library) General Public License for more details.
 
14
**
 
15
** You should have received a copy of the GNU (Library) General Public License
 
16
**  long 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
** Mar 27, 2001 - created moseley
 
21
**
 
22
*/
 
23
 
 
24
#include "acconfig.h"
 
25
 
 
26
#ifdef HAVE_UNISTD_H
 
27
#include <unistd.h>
 
28
#endif
 
29
 
 
30
#include "swish.h"
 
31
#include "mem.h"
 
32
#include "swstring.h"
 
33
#include "index.h"
 
34
#include "file.h"
 
35
#include "error.h"
 
36
#include "parse_conffile.h"
 
37
#include "bash.h" /* for locating a program */
 
38
 
 
39
static char *find_command_in_path(const char *name, const char *path_list, int *path_index);
 
40
static char *get_env_path_with_libexecdir( void );
 
41
 
 
42
 
 
43
struct MOD_Prog
 
44
{
 
45
    /* prog system specific configuration parameters */
 
46
    struct swline *progparameterslist;
 
47
};
 
48
 
 
49
 
 
50
/* 
 
51
  -- init structures for this module
 
52
*/
 
53
 
 
54
void initModule_Prog (SWISH  *sw)
 
55
{
 
56
    struct MOD_Prog *self;
 
57
 
 
58
    self = (struct MOD_Prog *) emalloc(sizeof(struct MOD_Prog));
 
59
    sw->Prog = self;
 
60
 
 
61
    /* initialize buffers used by indexstring */
 
62
    self->progparameterslist = (struct swline *) NULL;
 
63
 
 
64
    return;
 
65
}
 
66
 
 
67
void freeModule_Prog (SWISH *sw)
 
68
{
 
69
    struct MOD_Prog *self = sw->Prog;
 
70
 
 
71
 
 
72
    if ( self->progparameterslist )
 
73
        efree( self->progparameterslist );
 
74
 
 
75
    efree ( self );
 
76
    sw->Prog = NULL;
 
77
 
 
78
    return;
 
79
}
 
80
 
 
81
int configModule_Prog (SWISH *sw, StringList *sl)
 
82
 
 
83
{
 
84
    struct MOD_Prog *self = sw->Prog;
 
85
    char *w0    = sl->word[0];
 
86
 
 
87
    if (strcasecmp(w0, "SwishProgParameters") == 0)
 
88
    {
 
89
        if (sl->n > 1)
 
90
        {
 
91
            grabCmdOptions(sl, 1, &self->progparameterslist);
 
92
        }
 
93
        else
 
94
            progerr("%s: requires at least one value", w0);
 
95
    }
 
96
 
 
97
    else 
 
98
    {
 
99
        return 0;                   /* not a module directive */
 
100
    }
 
101
 
 
102
    return 1;
 
103
}
 
104
 
 
105
 
 
106
 
 
107
static FILE   *open_external_program(SWISH * sw, char *prog)
 
108
{
 
109
    char   *cmd;
 
110
    char   *full_path;
 
111
    FILE   *fp;
 
112
    size_t  total_len;
 
113
    struct swline *progparameterslist = sw->Prog->progparameterslist;
 
114
    int    path_index = 0;  /* index into $PATH */
 
115
    char  *env_path = get_env_path_with_libexecdir();
 
116
        
 
117
    if ( ! strcmp( prog, "stdin") )
 
118
        return stdin;
 
119
 
 
120
    normalize_path( prog );  /* flip backslashes to forward slashes */
 
121
 
 
122
    full_path = find_command_in_path( (const char *)prog, env_path, &path_index );
 
123
    if ( !full_path )
 
124
        progerr("Failed to find program '%s' in PATH: %s ", prog, env_path );
 
125
 
 
126
    efree( env_path );
 
127
 
 
128
    if ( sw->verbose )
 
129
        printf("External Program found: %s\n", full_path );
 
130
 
 
131
 
 
132
 
 
133
    /* get total length of configuration parameters */
 
134
    total_len = 0;
 
135
    while (progparameterslist)
 
136
    {
 
137
        total_len += strlen(progparameterslist->line) + 1; /* separate by spaces */
 
138
        progparameterslist = progparameterslist->next;
 
139
    }
 
140
 
 
141
    cmd = emalloc(total_len + strlen( full_path ) + 1);
 
142
    strcpy(cmd, full_path);
 
143
    efree( full_path );
 
144
 
 
145
 
 
146
#ifdef _WIN32
 
147
 
 
148
    make_windows_path( cmd );
 
149
 
 
150
#endif
 
151
 
 
152
 
 
153
    progparameterslist = sw->Prog->progparameterslist;
 
154
    while (progparameterslist)
 
155
    {
 
156
        strcat(cmd, " ");
 
157
        strcat(cmd, progparameterslist->line);
 
158
        progparameterslist = progparameterslist->next;
 
159
    }
 
160
 
 
161
    fp = popen(cmd, F_READ_TEXT);
 
162
 
 
163
    if (!fp)
 
164
        progerrno("Failed to spawn external program '%s': ", cmd);
 
165
 
 
166
    efree(cmd);
 
167
    return fp;
 
168
}
 
169
 
 
170
/* To make filters work with prog, need to write the file out to a temp file */
 
171
/* It will be faster to do the filtering from within the "prog" program */
 
172
/* This may not be safe if running as a threaded app, and I'm not clear on how portable this is */
 
173
/* This also uses read_stream to read in the file -- so the entire file is read into memory instead of chunked to the temp file */
 
174
 
 
175
/* Notice that the data is read out in TEXT mode -- this is because it's read from the */
 
176
/* external program in TEXT mode.  Binary files will be modified while in memory */
 
177
/* (under Windows) but writing back in TEXT mode should restore the file to its */
 
178
/* original binary format for use by the filter.  Really, don't use FileFilter with -S prog */
 
179
 
 
180
static void    save_to_temp_file(SWISH *sw, FileProp *fprop)
 
181
{
 
182
    FILE   *out;
 
183
    char   *rd_buffer = NULL;   /* complete file read into buffer */
 
184
    size_t  bytes;
 
185
    struct FilterList *filter_save = fprop->hasfilter;
 
186
    
 
187
 
 
188
    /* slirp entire file into memory -- yuck */
 
189
    fprop->hasfilter = NULL;  /* force reading fprop->fsize bytes */
 
190
    rd_buffer = read_stream(sw, fprop, 0);
 
191
 
 
192
    fprop->hasfilter = filter_save;
 
193
 
 
194
    /* Save content to a temporary file */
 
195
    efree( fprop->work_path );
 
196
    out = create_tempfile(sw, F_WRITE_TEXT, "fltr", &fprop->work_path, 0 );
 
197
 
 
198
    bytes = fwrite( rd_buffer, 1, fprop->fsize, out );
 
199
 
 
200
    if ( bytes != (size_t)fprop->fsize )
 
201
        progerrno("Failed to write temporary filter file '%s': ", fprop->work_path);
 
202
 
 
203
 
 
204
    /* hide the fact that it's an external program */
 
205
    fprop->fp = (FILE *) NULL;
 
206
 
 
207
 
 
208
//***JMRUIZ    efree(rd_buffer);
 
209
    fclose( out );
 
210
   
 
211
}
 
212
 
 
213
 
 
214
 
 
215
static void    extprog_indexpath(SWISH * sw, char *prog)
 
216
{
 
217
    FileProp *fprop;
 
218
    FILE   *fp;
 
219
    char   *ln;
 
220
    char   *real_path;
 
221
    long    fsize;
 
222
    time_t  mtime;
 
223
    int     index_no_content;
 
224
    long    truncate_doc_size;
 
225
    int     docType = 0;
 
226
 
 
227
    mtime = 0;
 
228
    fsize = -1;
 
229
    index_no_content = 0;
 
230
    real_path = NULL;
 
231
 
 
232
    fp = open_external_program(sw, prog);
 
233
 
 
234
    ln = emalloc(MAXSTRLEN + 1);
 
235
 
 
236
    truncate_doc_size = sw->truncateDocSize;
 
237
    sw->truncateDocSize = 0;    /* can't truncate -- prog should make sure doc is not too large */
 
238
    // $$$ This is no longer true with libxml push parser
 
239
 
 
240
    // $$$ next time, break out the header parsing in its own function, please
 
241
 
 
242
    /* loop on headers */
 
243
    while (fgets(ln, MAXSTRLEN, fp) != NULL)
 
244
    {
 
245
        char    *end;
 
246
        char    *line;
 
247
        int     has_filter = 0;
 
248
        
 
249
        line = str_skip_ws(ln); /* skip leading white space */
 
250
        end = strrchr(line, '\n'); /* replace \n with null -- better to remove trailing white space */
 
251
 
 
252
        /* trim white space */
 
253
        if (end)
 
254
        {
 
255
            while ( end > line && isspace( (int)*(end-1) ) )
 
256
                end--;
 
257
 
 
258
            *end = '\0';
 
259
        }
 
260
 
 
261
        if (strlen(line) == 0) /* blank line indicates body */
 
262
        {
 
263
            if (!real_path)
 
264
                progerr("External program failed to return required headers Path-Name:");
 
265
 
 
266
            if ( fsize == -1)
 
267
                progerr("External program failed to return required headers Content-Length: when processing file '%s'", real_path);
 
268
 
 
269
            if ( fsize == 0 && sw->verbose >= 2)
 
270
                progwarn("External program returned zero Content-Length when processing file'%s'", real_path);
 
271
 
 
272
            
 
273
 
 
274
            /* Create the FileProp entry to describe this "file" */
 
275
 
 
276
            /* This is not great -- really should make creating a fprop more generic */
 
277
            /* this was done because file.c assumed that the "file" was on disk */
 
278
            /* which has changed over time due to filters, http, and prog */
 
279
            
 
280
            fprop = init_file_properties();  
 
281
            fprop->real_path = real_path;
 
282
            fprop->work_path = estrdup( real_path );
 
283
            fprop->orig_path = estrdup( real_path );
 
284
 
 
285
            /* Set the doc type from the header */
 
286
            if ( docType ) 
 
287
            {
 
288
                fprop->doctype   = docType;
 
289
                docType = 0;
 
290
            } 
 
291
 
 
292
 
 
293
            /* set real_path, doctype, index_no_content, filter, stordesc */
 
294
            init_file_prop_settings(sw, fprop);
 
295
 
 
296
            fprop->fp = fp; /* stream to read from */
 
297
            fprop->fsize = fsize; /* how much to read */
 
298
            fprop->source_size = fsize;  /* original size of input document - should be an extra header! */
 
299
            fprop->mtime = mtime;
 
300
 
 
301
            /* header can force index_no_content */
 
302
            if (index_no_content)
 
303
                fprop->index_no_content++;
 
304
 
 
305
 
 
306
            /*  the quick hack to make filters work is for FilterOpen
 
307
             *  to see that fprop->fp is set, read it into a buffer
 
308
             *  write it to a temporary file, then call the filter
 
309
             *  program as noramlly is done.  But much smarter to
 
310
             *  simply filter in the prog, after all.  Faster, too.
 
311
             */
 
312
 
 
313
            if (fprop->hasfilter)
 
314
            {
 
315
                save_to_temp_file( sw , fprop );
 
316
                has_filter++; /* save locally, in case it gets reset somewhere else */
 
317
            }
 
318
 
 
319
            if (sw->verbose >= 3)
 
320
                printf("%s", real_path);
 
321
            else if (sw->verbose >= 2)
 
322
                printf("Processing %s...\n", real_path);
 
323
 
 
324
 
 
325
            do_index_file(sw, fprop);
 
326
 
 
327
            if ( has_filter && remove( fprop->work_path ) )
 
328
                progwarnno("Error removing temporary file '%s': ", fprop->work_path);
 
329
 
 
330
            free_file_properties(fprop);
 
331
            // efree(real_path); free_file_properties will free the paths
 
332
            real_path = NULL;
 
333
            mtime = 0;
 
334
            fsize = 0;
 
335
            index_no_content = 0;
 
336
            
 
337
        }
 
338
 
 
339
 
 
340
        else /* we are reading headers */
 
341
        {
 
342
            if (strncasecmp(line, "Content-Length", 14) == 0)
 
343
            {
 
344
                char *x = strchr(line, ':');
 
345
                if (!x)
 
346
                    progerr("Failed to parse Content-Length header '%s'", line);
 
347
                fsize = strtol(++x, NULL, 10);
 
348
                continue;
 
349
            }
 
350
 
 
351
            if (strncasecmp(line, "Last-Mtime", 10) == 0)
 
352
            {
 
353
                char *x = strchr(line, ':');
 
354
                if (!x)
 
355
                    progerr("Failed to parse Last-Mtime header '%s'", line);
 
356
                mtime = strtol(++x, NULL, 10);
 
357
                continue;
 
358
            }
 
359
 
 
360
            if (strncasecmp(line, "No-Contents:", 12) == 0)
 
361
            {
 
362
                index_no_content++;
 
363
                continue;
 
364
            }
 
365
 
 
366
 
 
367
            if (strncasecmp(line, "Path-Name", 9) == 0)
 
368
            {
 
369
                char *x = strchr(line, ':');
 
370
                if (!x)
 
371
                    progerr("Failed to parse Path-Name header '%s'", line);
 
372
 
 
373
                x = str_skip_ws(++x);
 
374
                if (!*x)
 
375
                    progerr("Failed to find path name in Path-Name header '%s'", line);
 
376
 
 
377
                real_path = emalloc(strlen(x) + 1);
 
378
                strcpy(real_path, x);
 
379
                continue;
 
380
            }
 
381
 
 
382
            if (strncasecmp(line, "Document-Type", 13) == 0)
 
383
            {
 
384
                char *x = strchr(line, ':');
 
385
                if (!x)
 
386
                    progerr("Failed to parse Document-Type '%s'", line);
 
387
 
 
388
                x = str_skip_ws(++x);
 
389
                if (!*x)
 
390
                    progerr("Failed to documnet type in Document-Type header '%s'", line);
 
391
 
 
392
                if ( !(docType = strtoDocType( x )) )
 
393
                    progerr("documnet type '%s' not a valid Swish-e document type in Document-Type header '%s'", x, line);
 
394
 
 
395
                continue;
 
396
            }
 
397
 
 
398
            progwarn("Unknown header line: '%s' from program %s", line, prog);
 
399
 
 
400
        }
 
401
    }
 
402
 
 
403
    efree(ln);
 
404
 
 
405
    /* restore the setting */
 
406
    sw->truncateDocSize = truncate_doc_size;
 
407
 
 
408
    if ( fp != stdin )
 
409
        if ( pclose(fp) == -1 )
 
410
            progwarnno("Failed to properly close external program: ");
 
411
    
 
412
}
 
413
 
 
414
 
 
415
 
 
416
 
 
417
 
 
418
/* Don't use old method of config checking */
 
419
static int     extprog_parseconfline(SWISH * sw, StringList *l)
 
420
{
 
421
    return 0;
 
422
}
 
423
 
 
424
 
 
425
 
 
426
struct _indexing_data_source_def ExternalProgramDataSource = {
 
427
    "External-Program",
 
428
    "prog",
 
429
    extprog_indexpath,
 
430
    extprog_parseconfline
 
431
};
 
432
 
 
433
 
 
434
/* From GNU Which */
 
435
static char *find_command_in_path(const char *name, const char *path_list, int *path_index)
 
436
{
 
437
  char *found = NULL, *full_path;
 
438
  int status, name_len;
 
439
  int absolute_path_given = 0;
 
440
  char *abs_path = NULL;
 
441
  name_len = strlen(name);
 
442
 
 
443
  if (!absolute_program(name))
 
444
    absolute_path_given = 0;
 
445
  else
 
446
  {
 
447
    char *p;
 
448
    absolute_path_given = 1;
 
449
 
 
450
    if (abs_path)
 
451
      xfree(abs_path);
 
452
 
 
453
    if (*name != '.' && *name != '/' && *name != '~')
 
454
    {
 
455
      abs_path = (char *)xmalloc(3 + name_len);
 
456
      strcpy(abs_path, "./");
 
457
      strcat(abs_path, name);
 
458
    }
 
459
    else
 
460
    {
 
461
      abs_path = (char *)xmalloc(1 + name_len);
 
462
      strcpy(abs_path, name);
 
463
    }
 
464
 
 
465
    path_list = abs_path;
 
466
    p = strrchr(abs_path, '/');
 
467
    *p++ = 0;
 
468
    name = p;
 
469
  }
 
470
 
 
471
  while (path_list && path_list[*path_index])
 
472
  {
 
473
    char *path;
 
474
 
 
475
    if (absolute_path_given)
 
476
    {
 
477
      path = savestring(path_list);
 
478
      *path_index = strlen(path);
 
479
    }
 
480
    else
 
481
      path = get_next_path_element(path_list, path_index);
 
482
 
 
483
    if (!path)
 
484
      break;
 
485
 
 
486
#ifdef SKIPTHIS
 
487
    if (*path == '~')
 
488
    {
 
489
      char *t = tilde_expand(path);
 
490
      xfree(path);
 
491
      path = t;
 
492
 
 
493
      if (skip_tilde)
 
494
      {
 
495
        xfree(path);
 
496
        continue;
 
497
      }
 
498
    }
 
499
 
 
500
    if (skip_dot && *path != '/')
 
501
    {
 
502
      xfree(path);
 
503
      continue;
 
504
    }
 
505
 
 
506
    found_path_starts_with_dot = (*path == '.');
 
507
#endif
 
508
 
 
509
    full_path = make_full_pathname(path, name, name_len);
 
510
    xfree(path);
 
511
 
 
512
    status = file_status(full_path);
 
513
 
 
514
    /* This is different from "where" because it stops at the first found file */
 
515
    /* but where (and shells) continue to find first executable program in path */
 
516
    if (status & FS_EXISTS) 
 
517
    {
 
518
      if (status & FS_EXECABLE)
 
519
      {
 
520
        found = full_path;
 
521
        break;
 
522
      }
 
523
      else
 
524
          progwarn("Found '%s' in PATH but is not executable", full_path);
 
525
    }
 
526
    xfree(full_path);
 
527
  }
 
528
 
 
529
  return (found);
 
530
}
 
531
 
 
532
 
 
533
static char *get_env_path_with_libexecdir( void )
 
534
{
 
535
    char *pathbuf;
 
536
    char *path = getenv("PATH");
 
537
    char *execdir = get_libexec();  /* Should free */
 
538
 
 
539
    if ( !path )
 
540
        return execdir;
 
541
 
 
542
    pathbuf = (char *)emalloc( strlen( path ) + strlen( execdir ) + strlen( PATH_SEPARATOR ) + 1 );
 
543
 
 
544
    sprintf(pathbuf, "%s%s%s", path, PATH_SEPARATOR, execdir );
 
545
    return pathbuf;
 
546
}
 
547