snownews/filters.c

188 lines
5.3 KiB
C

// This file is part of Snownews - A lightweight console RSS newsreader
//
// Copyright (c) 2003-2004 Oliver Feiler <kiza@kcore.de>
//
// Snownews is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 3
// as published by the Free Software Foundation.
//
// Snownews is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Snownews. If not, see http://www.gnu.org/licenses/.
#include "filters.h"
#include "uiutil.h"
#include "conv.h"
//----------------------------------------------------------------------
static int pipe_command_buf (const char* command, char** argv, const void* inbuf, size_t inbuf_size, char** outbuf, unsigned* outbuf_size);
//----------------------------------------------------------------------
// Load output of local script. Must be valid RSS.
int FilterExecURL (struct feed* cur_ptr)
{
char* command = strdup (cur_ptr->feedurl);
char* freeme = command;
strsep (&command, ":");
char buf[BUFSIZ];
snprintf (buf, sizeof (buf), _("Loading \"%s\""), command);
UIStatus (buf, 0, 0);
FILE* scriptoutput = popen (command, "r");
free (freeme);
if (!scriptoutput)
return -1;
cur_ptr->content_length = 0;
cur_ptr->xmltext = realloc (cur_ptr->xmltext, cur_ptr->content_length + 1);
cur_ptr->xmltext[cur_ptr->content_length] = '\0';
while (!feof (scriptoutput) && fgets (buf, sizeof (buf), scriptoutput)) {
size_t br = strlen (buf);
cur_ptr->xmltext = realloc (cur_ptr->xmltext, cur_ptr->content_length + br + 1);
memcpy (&cur_ptr->xmltext[cur_ptr->content_length], buf, br + 1);
cur_ptr->content_length += br;
}
pclose (scriptoutput);
// Set title and link structure to something.
// To the feedurl in this case so the program shows something
// as placeholder instead of crash.
if (cur_ptr->title == NULL)
cur_ptr->title = strdup (cur_ptr->feedurl);
if (cur_ptr->link == NULL)
cur_ptr->link = strdup (cur_ptr->feedurl);
return 0;
}
int FilterPipeNG (struct feed* cur_ptr)
{
if (cur_ptr->perfeedfilter == NULL)
return -1;
char* data = malloc (cur_ptr->content_length + 1);
memcpy (data, cur_ptr->xmltext, cur_ptr->content_length);
data[cur_ptr->content_length] = 0;
free (cur_ptr->xmltext);
cur_ptr->xmltext = NULL;
cur_ptr->content_length = 0;
char* filter = strdup (cur_ptr->perfeedfilter);
char* command = strsep (&filter, " ");
char** options = malloc (sizeof (char*));
size_t nopts = 0;
options[nopts++] = command;
for (;;) {
options = realloc (options, sizeof (char*) * (nopts + 1));
if (!(options[nopts++] = strsep (&filter, " ")))
break;
}
int rc = pipe_command_buf (command, options,
data, cur_ptr->content_length,
&cur_ptr->xmltext, &cur_ptr->content_length);
free (data);
free (command);
free (options); // options[i] contains only pointers!
return rc;
}
static int pipe_command_buf (const char* command, char** argv, const void* inbuf, size_t inbuf_size, char** outbuf, unsigned* outbuf_size)
{
enum { READ_END, WRITE_END, N_ENDS };
int input_pipe[N_ENDS], output_pipe[N_ENDS];
if (0 != pipe (input_pipe)) {
perror ("Couldn't create input pipe");
return -1;
}
if (0 != pipe (output_pipe)) {
close (input_pipe[READ_END]);
close (input_pipe[WRITE_END]);
perror ("Couldn't create output pipe");
return -1;
}
int result = fork();
if (result < 0) {
close (input_pipe[READ_END]);
close (input_pipe[WRITE_END]);
close (output_pipe[READ_END]);
close (output_pipe[WRITE_END]);
perror ("fork");
return -1;
} else if (result == 0) {
close (output_pipe[WRITE_END]);
close (input_pipe[READ_END]);
if (0 > dup2 (output_pipe[READ_END], STDIN_FILENO)) {
perror ("dup2 error on output_pipe");
exit (EXIT_FAILURE);
}
close (output_pipe[READ_END]);
if (0 > dup2 (input_pipe[WRITE_END], STDOUT_FILENO)) {
perror ("dup2 error on input_pipe");
exit (EXIT_FAILURE);
}
close (input_pipe[WRITE_END]);
if (0 > execvp (command, argv)) {
char tmp[PATH_MAX];
snprintf (tmp, sizeof (tmp), "Exec of \"%s\" failed", command);
perror (tmp);
}
exit (EXIT_FAILURE);
} else {
close (output_pipe[READ_END]);
close (input_pipe[WRITE_END]);
write (output_pipe[WRITE_END], inbuf, inbuf_size);
close (output_pipe[WRITE_END]);
char* buf = NULL, *buf_cur = NULL;
int buf_size = 0, bytes_read = 0;
do {
buf_size += BUFSIZ;
buf = realloc (buf, buf_size + 1);
buf_cur = buf + buf_size - BUFSIZ;
result = read (input_pipe[READ_END], buf_cur, BUFSIZ);
if (result > 0) {
bytes_read += result;
if (result < BUFSIZ) {
buf_size -= (BUFSIZ - result);
buf = realloc (buf, buf_size + 1);
break;
}
} else if (result < 0) {
free (buf);
buf = NULL;
return -1;
}
} while (result > 0);
close (input_pipe[READ_END]);
if (bytes_read == 0) {
free (buf);
return -1;
} else {
buf[buf_size] = '\0';
*outbuf = buf;
*outbuf_size = buf_size;
}
}
return 0;
}