/***************************************************************************** * Authors: Louis Bavoil * Fredrik Hübinette * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/ #include "mozplugger.h" #define THIS (*(data_t **) &(instance->pdata)) #ifndef __GNUC__ #define __inline #endif /***************************************************************************** * Type declarations *****************************************************************************/ typedef struct argument { char *name; char *value; } argument_t; typedef struct data { Display *display; char *displayname; NPWindow windata; int pid; int fd; int repeats; int flags; char *command; char *winname; uint16 mode; char *mimetype; char *href; char *mms; char autostart; int num_arguments; struct argument *args; } data_t; typedef struct mimetype { char type[MAX_TYPE_SIZE]; } mimetype_t; typedef struct command { int flags; char cmd[MAX_CMD_SIZE]; char winname[MAX_WINNAME_SIZE]; } command_t; typedef struct handle { int num_types; int num_cmds; mimetype_t types[MAX_NUM_TYPES_PER_HANDLER]; command_t cmds[MAX_NUM_CMDS_PER_HANDLER]; } handler_t; typedef struct { char *name; int value; } flag_t; /***************************************************************************** * Global variables *****************************************************************************/ static char *config_fname; static char *helper_fname; static char *controller_fname; static int num_handlers; static handler_t handlers[MAX_NUM_HANDLERS]; /***************************************************************************** * Wrapper for fork() which handles some magic needed to prevent netscape * from freaking out. It also prevents interferrance from signals. *****************************************************************************/ static int my_fork(NPP instance) { int pid; sigset_t set,oset; int signum; /* Mask all the signals to avoid being interrupted by a signal */ sigfillset(&set); sigprocmask(SIG_SETMASK, &set, &oset); D(">>>>>>>>Forking<<<<<<<<,\n"); if ((pid = fork()) == -1) { return -1; } if (!pid) { alarm(0); if (!(THIS->flags & H_DAEMON)) setsid(); for (signum=0; signum < NSIG; signum++) signal(signum, SIG_DFL); THIS->display = NULL; #ifdef DEBUG close_debug(); D("Child re-opened ndebug\n"); #endif } else { D("Child running with pid=%d\n", pid); } /* Restore the signal mask */ sigprocmask(SIG_SETMASK, &oset, &set); return pid; } /***************************************************************************** * Wrapper for putenv(). *****************************************************************************/ static void my_putenv(char *buffer, int *offset, const char *var, const char *value) { int l = strlen(var) + strlen(value) + 2; if (!(*offset + l < ENV_BUFFER_SIZE)) { D("Buffer overflow in putenv(%s=%s)\n", var, value); return; } sprintf(buffer+*offset, "%s=%s", var, value); putenv(buffer+*offset); *offset += l; } /***************************************************************************** * Wrapper for execlp() that calls the helper. *****************************************************************************/ static void run(NPP instance, const char *file) { char buffer[ENV_BUFFER_SIZE]; char foo[SMALL_BUFFER_SIZE]; int offset = 0; int i; if ((THIS->flags & H_CONTROLS) && (THIS->mode == NP_FULL)) THIS->flags &= ~(H_CONTROLS | H_SWALLOW | H_FILL); snprintf(buffer, sizeof(buffer), "%d,%d,%d,%lu,%d,%d,%d,%d", THIS->flags, THIS->repeats, THIS->fd, (unsigned long int) THIS->windata.window, (int) THIS->windata.x, (int) THIS->windata.y, (int) THIS->windata.width, (int) THIS->windata.height); D("Executing helper: %s %s %s %s %s %s\n", helper_fname, buffer, file, THIS->displayname, THIS->command, THIS->mimetype); offset = strlen(buffer)+1; snprintf(foo, sizeof(foo), "%lu", (long unsigned)THIS->windata.window); my_putenv(buffer, &offset, "window", foo); snprintf(foo, sizeof(foo), "0x%lx", (long unsigned)THIS->windata.window); my_putenv(buffer, &offset, "hexwindow", foo); snprintf(foo, sizeof(foo), "%ld", (long)THIS->repeats); my_putenv(buffer, &offset, "repeats", foo); snprintf(foo, sizeof(foo), "%ld", (long)THIS->windata.width); my_putenv(buffer, &offset, "width", foo); snprintf(foo, sizeof(foo), "%ld", (long)THIS->windata.height); my_putenv(buffer, &offset, "height", foo); my_putenv(buffer, &offset, "mimetype", THIS->mimetype); my_putenv(buffer, &offset, "file", file); my_putenv(buffer, &offset, "autostart", THIS->autostart ? "1" : "0"); if (THIS->winname) my_putenv(buffer, &offset, "winname", THIS->winname); if (THIS->displayname) my_putenv(buffer, &offset, "DISPLAY", THIS->displayname); if (controller_fname) my_putenv(buffer, &offset, "controller", controller_fname); for (i = 0; i < THIS->num_arguments; i++) if (THIS->args[i].value) my_putenv(buffer, &offset, THIS->args[i].name, THIS->args[i].value); execlp(helper_fname, helper_fname, buffer, THIS->command, NULL); D("EXECLP FAILED!\n"); _exit(EX_UNAVAILABLE); } /***************************************************************************** * Check if 'file' is somewhere to be found in the user PATH. *****************************************************************************/ static int inpath(char *path, char *file) { static struct stat filestat; static char buf[1024]; int i; int count = 1; for (i = strlen(path)-1; i > 0; i--) { if (path[i] == ':') { path[i] = 0; count++; } } for (i = 0; i < count; i++) { snprintf(buf, sizeof(buf), "%s/%s", path, file); D("stat(%s)\n", buf); if (!stat(buf, &filestat)) { D("yes\n"); return 1; } D("no\n"); path += (strlen(path) + 1); } return 0; } /***************************************************************************** * Check if 'file' exists. *****************************************************************************/ static int find(char *file) { static struct stat filestat; static char path[1024]; char *env_path; D("find(%s)\n", file); if (file[0] == '/') return !stat(file, &filestat); /* Get the environment variable PATH */ if (!(env_path = getenv("PATH"))) { D("No PATH !\n"); return 0; } /* Duplicate to avoid corrupting Mozilla's PATH */ strncpy(path, env_path, sizeof(path)); return inpath(path, file); } /***************************************************************************** * Delete a mime handler if no command has been found for it. *****************************************************************************/ static void filter_previous_handler() { handler_t *h; if (num_handlers >= 1) { h = &handlers[num_handlers-1]; if (h->num_cmds == 0) { D("Empty handler: '%s'.\n", h->types[0].type); h->num_types = 0; num_handlers--; } } } /***************************************************************************** * Match a word to a flag of the type swallow(name). *****************************************************************************/ static char *get_winname(char *x, char *flag, command_t *c) { char *end; int len; x += strlen(flag); while (isspace(*x)) x++; if (*x != '(') { fprintf(stderr, "MozPlugger: Warning: Expected '(' after '%s'\n", flag); return NULL; } x++; end = strchr(x,')'); if (end) { len = end - x; if (!(len < sizeof(c->winname))) { fprintf(stderr, "MozPlugger: Error: Window name too long (%s)\n", x); exit(1); } memcpy(c->winname, x, len); c->winname[len] = 0; x = end+1; } return x; } /***************************************************************************** * Match two words. *****************************************************************************/ __inline static int match_word(char *line, char *kw) { return !strncasecmp(line, kw, strlen(kw)) && !isalnum(line[strlen(kw)]); } /***************************************************************************** * Scan a line for all the possible flags. *****************************************************************************/ static int parse_flags(char **x, command_t *commandp) { static flag_t flags[] = { { "repeat", H_REPEATCOUNT }, { "loop", H_LOOP }, { "stream", H_STREAM }, { "ignore_errors", H_IGNORE_ERRORS }, { "exits", H_DAEMON }, { "nokill", H_DAEMON }, { "maxaspect", H_MAXASPECT }, { "fill", H_FILL }, { "noisy", H_NOISY }, { "embed", H_EMBED }, { "noembed", H_NOEMBED }, { "hidden", H_HIDDEN }, { NULL, 0 } }; flag_t *f; for (f = flags; f->name; f++) { if (match_word(*x, f->name)) { *x += strlen(f->name); commandp->flags |= f->value; return 1; } if (match_word(*x, "swallow")) { commandp->flags |= H_SWALLOW; if ((*x = get_winname(*x, "swallow", commandp))) return 1; } if (match_word(*x, "controls")) { commandp->flags |= H_CONTROLS | H_FILL | H_SWALLOW | H_HIDDEN; strcpy(commandp->winname, "mozplugger-controller"); *x += 8; return 1; } } return 0; } /***************************************************************************** * Read the configuration file into memory. *****************************************************************************/ static void read_config(FILE *f) { handler_t *handler = NULL; command_t *cmd = NULL; mimetype_t *type = NULL; char buffer[LARGE_BUFFER_SIZE]; char file[SMALL_BUFFER_SIZE]; int have_commands = 1; D("read_config\n"); while (fgets(buffer, sizeof(buffer), f)) { D("::: %s", buffer); if (buffer[0] == '#' || buffer[0] == '\n' || buffer[0] == '\0') continue; if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = 0; if (!isspace(buffer[0])) { /* Mime type */ if (have_commands) { D("-------------------------------------------\n"); D("New handler\n"); D("-------------------------------------------\n"); filter_previous_handler(); handler = &handlers[num_handlers++]; if (!(num_handlers < MAX_NUM_HANDLERS)) { fprintf(stderr, "MozPlugger: Error: Too many handlers (%d)\n", num_handlers); exit(1); } have_commands = 0; } D("New mime type\n"); type = &handler->types[handler->num_types++]; if (!(handler->num_types < MAX_NUM_TYPES_PER_HANDLER)) { fprintf(stderr, "MozPlugger: Error: Too many types (%d) for handler %d (%s)\n", handler->num_types, num_handlers, handler->types[0].type); exit(1); } if (!(strlen(buffer) < sizeof(type->type))) { fprintf(stderr, "MozPlugger: Error: Mime type too long (%s)\n", buffer); exit(1); } strncpy(type->type, buffer, sizeof(type->type)); } else { /* Command */ char *x = buffer + 1; while (isspace(*x)) x++; if (!*x) { D("Empty command.\n"); have_commands++; continue; } D("New command\n"); have_commands++; cmd = &handler->cmds[handler->num_cmds]; memset(cmd, 0, sizeof(command_t)); D("Parsing %s\n", x); while (*x != ':' && *x) { if (*x == ',' || *x == ' ' || *x == '\t') { x++; } else if (!parse_flags(&x, cmd)) { fprintf(stderr, "MozPlugger: Warning: Unknown directive: %s\n", x); x += strlen(x); } } if (*x == ':') { x++; while (isspace(*x)) x++; if (sscanf(x, "if %"SMALL_BUFFER_SIZE_STR"s", file) != 1 && sscanf(x, "%"SMALL_BUFFER_SIZE_STR"s", file) != 1) continue; if (!find(file)) continue; if (!(strlen(x) < sizeof(cmd->cmd))) { fprintf(stderr, "MozPlugger: Error: Command too long (%s)\n", x); exit(1); } strncpy(cmd->cmd, x, sizeof(cmd->cmd)); } else { D("No column? (%s)\n", x); } handler->num_cmds++; if (!(handler->num_cmds < MAX_NUM_CMDS_PER_HANDLER)) { fprintf(stderr, "MozPlugger: Error: Too many commands (%d) for handler %d (%s)\n", handler->num_cmds, num_handlers, handler->types[0].type); exit(1); } } } filter_previous_handler(); D("Num handlers: %d\n", num_handlers); } /***************************************************************************** * Find the config file or the helper file in function of the function cb. *****************************************************************************/ static int find_helper_file(char *basename, int (*cb)(char *,void *data), void *data) { static char fname[LARGE_BUFFER_SIZE]; char *tmp; D("find_helper_file '%s'\n", basename); if ((tmp = getenv("HOME"))) { snprintf(fname, sizeof(fname), "%s/.netscape/%s", tmp, basename); if (cb(fname,data)) return 1; snprintf(fname, sizeof(fname), "%s/.mozilla/%s", tmp, basename); if (cb(fname,data)) return 1; snprintf(fname, sizeof(fname), "%s/.opera/%s", tmp, basename); if (cb(fname,data)) return 1; } if ((tmp = getenv("MOZILLA_HOME"))) { snprintf(fname, sizeof(fname), "%s/%s", tmp, basename); if (cb(fname, data)) return 1; } if ((tmp = getenv("OPERA_DIR"))) { snprintf(fname, sizeof(fname), "%s/%s", tmp, basename); if (cb(fname, data)) return 1; } snprintf(fname, sizeof(fname), PREFIX "/etc/%s", basename); if (cb(fname, data)) return 1; snprintf(fname, sizeof(fname), "/etc/%s", basename); if (cb(fname, data)) return 1; snprintf(fname, sizeof(fname), "/usr/etc/%s", basename); if (cb(fname, data)) return 1; snprintf(fname, sizeof(fname), "/usr/local/mozilla/%s", basename); if (cb(fname, data)) return 1; snprintf(fname, sizeof(fname), "/usr/local/netscape/%s", basename); if (cb(fname, data)) return 1; if (cb(basename, data)) return 1; return 0; } static int read_config_cb(char *fname, void *data) { int m4out[2]; int pid; int fd; FILE *fp; D("READ_CONFIG(%s)\n", fname); fd = open(fname, O_RDONLY); if (fd < 0) return 0; if (pipe(m4out) < 0) { perror("pipe"); return 0; } if ((pid = fork()) == -1) return 0; if (!pid) { close(m4out[0]); dup2(m4out[1], 1); close(m4out[1]); dup2(fd, 0); close(fd); execlp("m4", "m4", NULL); fprintf(stderr, "MozPlugger: Error: Failed to execute m4.\n"); exit(1); } else { close(m4out[1]); close(fd); fp = fdopen(m4out[0], "r"); if (!fp) return 0; read_config(fp); fclose(fp); waitpid(pid, 0, 0); config_fname = strdup(fname); } return 1; } static int find_plugger_helper_cb(char *fname, void *data) { struct stat buf; if (stat(fname, &buf)) return 0; helper_fname = strdup(fname); return 1; } static int find_plugger_controller_cb(char *fname, void *data) { struct stat buf; if (stat(fname, &buf)) return 0; controller_fname = strdup(fname); return 1; } /***************************************************************************** * Find configuration file and read it into memory. *****************************************************************************/ static void do_read_config(void) { if (num_handlers > 0) return; D("do_read_config\n"); if (!find_helper_file("mozpluggerrc", read_config_cb, 0)) { fprintf(stderr, "MozPlugger: Warning: Unable to find the mozpluggerrc file.\n"); return; } if (!find_helper_file("mozplugger-helper", find_plugger_helper_cb, 0)) { if (find("mozplugger-helper")) { helper_fname = "mozplugger-helper"; } else { fprintf(stderr, "MozPlugger: Warning: Unable to find mozplugger-helper.\n"); return; } } if (!find_helper_file("mozplugger-controller", find_plugger_controller_cb, 0)) { if (find("mozplugger-controller")) { controller_fname = "mozplugger-controller"; } else { fprintf(stderr, "MozPlugger: Warning: Unable to find mozplugger-controller.\n"); return; } } D("do_read_config done\n"); } /***************************************************************************** * Since href's are passed to an app as an argument, just check for ways that * a shell can be tricked into executing a command. *****************************************************************************/ static int safeURL(char* url) { int i = 0; int len = strlen(url); if (url[0] == '/') return 0; for (i = 0; i < len; i++) { if (url[i] == '`' || url[i] == ';') { /* Somebody's trying to do something naughty. */ return 0; } } return 1; } /***************************************************************************** * Go through the commands in the config file and find one that fits our needs. *****************************************************************************/ __inline static int match_command(NPP instance, int streaming, command_t *c) { char embedded = (THIS->mode == NP_EMBED); D("Checking command: %s\n", c->cmd); if (embedded && (c->flags & H_NOEMBED)) { D("Flag mismatch: embed\n"); return 0; } if ((!embedded) && (c->flags & H_EMBED)) { D("Flag mismatch: noembed\n"); return 0; } if ((c->flags & H_LOOP) && (THIS->repeats != MAXINT)) { D("Flag mismatch: loop\n"); return 0; } if ((!!streaming) != (!!(c->flags & H_STREAM))) { D("Flag mismatch: stream\n"); return 0; } D("Match found!\n"); return 1; } __inline static int match_mime_type(NPP instance, mimetype_t *m) { char mimetype[SMALL_BUFFER_SIZE]; sscanf(m->type, "%"SMALL_BUFFER_SIZE_STR"[^:]", mimetype); sscanf(mimetype, "%s", mimetype); D("Checking '%s' ?= '%s'\n", mimetype, THIS->mimetype); if (strcasecmp(mimetype, THIS->mimetype)) { D("Not same.\n"); return 0; } D("Same.\n"); return 1; } __inline static int match_handler(handler_t *h, NPP instance, int streaming) { mimetype_t *m; command_t *c; int mid, cid; D("-------------------------------------------\n"); D("Commands for this handle at (%p):\n", h->cmds); for (mid = 0; mid < h->num_types; mid++) { m = &h->types[mid]; if (match_mime_type(instance, m)) { for (cid = 0; cid < h->num_cmds; cid++) { c = &h->cmds[cid]; if (match_command(instance, streaming, c)) { THIS->flags = c->flags; THIS->command = c->cmd; THIS->winname = c->winname; return 1; } } } } return 0; } static int find_command(NPP instance, int streaming) { int hid; D("find_command...\n"); do_read_config(); for (hid = 0; hid < num_handlers; hid++) { if (match_handler(&handlers[hid], instance, streaming)) { D("Command found.\n"); return 1; } } D("No command found.\n"); return 0; } /***************************************************************************** * Construct a MIME Description string for netscape so that mozilla shall know * when to call us back. *****************************************************************************/ char *NPP_GetMIMEDescription(void) { char *x,*y; handler_t *h; mimetype_t *m; int size_required; int hid, mid; D("GetMIMEDescription\n"); do_read_config(); size_required = 0; for (hid = 0; hid < num_handlers; hid++) { h = &handlers[hid]; for (mid = 0; mid < h->num_types; mid++) { m = &h->types[mid]; size_required += strlen(m->type)+1; } } D("Size required=%d\n", size_required); if (!(x = (char *)malloc(size_required+1))) return 0; D("Malloc did not fail\n"); y = x; for (hid = 0; hid < num_handlers; hid++) { h = &handlers[hid]; for (mid = 0; mid < h->num_types; mid++) { m = &h->types[mid]; memcpy(y,m->type,strlen(m->type)); y+=strlen(m->type); *(y++)=';'; } } if (x != y) y--; *(y++) = 0; D("Getmimedescription done: %s\n", x); return x; } /***************************************************************************** * Let Mozilla know things about mozplugger. *****************************************************************************/ NPError NPP_GetValue(void *instance, NPPVariable variable, void *value) { static char desc_buffer[8192]; NPError err = NPERR_NO_ERROR; D("Getvalue %d\n", variable); switch (variable) { case NPPVpluginNameString: D("GET Plugin name\n"); *((char **)value) = "MozPlugger " VERSION " handles QuickTime Windows Media Player Plugin" ; break; case NPPVpluginDescriptionString: D("GET Plugin description\n"); snprintf(desc_buffer, sizeof(desc_buffer), "MozPlugger version " VERSION ", written by " "Fredrik Hübinette " "<hubbe@hubbe.net> " "and Louis Bavoil " "<bavoil@cs.utah.edu>.
" "For documentation on how to configure mozplugger, " "check the man page. (type man mozplugger)" " " " " " " " " #ifdef DEBUG " " #endif "
Configuration file:%s
Helper binary:%s
Controller binary:%s
Debug file:$HOME/tmp/mozdebug
" "
", config_fname ? config_fname : "Not found!", helper_fname ? helper_fname : "Not found!", controller_fname ? controller_fname : "Not found!"); *((char **)value) = desc_buffer; break; default: err = NPERR_GENERIC_ERROR; } return err; } /***************************************************************************** * Convert a string to an integer. * The string can be true, false, yes or no. *****************************************************************************/ static int my_atoi(char *s, int my_true, int my_false) { switch (s[0]) { case 't': case 'T': case 'y': case 'Y': return my_true; case 'f': case 'F': case 'n': case 'N': return my_false; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return atoi(s); } return -1; } /***************************************************************************** * Initialize another instance of mozplugger. It is important to know * that there might be several instances going at one time. *****************************************************************************/ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) { int e; int src_idx = -1; D("NEW (%s)\n", pluginType); if (!instance) { D("Invalid instance pointer\n"); return NPERR_INVALID_INSTANCE_ERROR; } if (!pluginType) { D("Invalid plugin type\n"); return NPERR_INVALID_INSTANCE_ERROR; } THIS = NPN_MemAlloc(sizeof(data_t)); if (!THIS) return NPERR_OUT_OF_MEMORY_ERROR; memset((void *)THIS, 0, sizeof(data_t)); THIS->windata.window = 0; THIS->display = NULL; THIS->pid = -1; THIS->fd = -1; THIS->repeats = 1; THIS->autostart = 1; THIS->mode = mode; if (!(THIS->mimetype = strdup(pluginType))) return NPERR_OUT_OF_MEMORY_ERROR; THIS->num_arguments = argc; if (!(THIS->args = (argument_t *)NPN_MemAlloc(sizeof(argument_t) * argc))) return NPERR_OUT_OF_MEMORY_ERROR; for (e = 0; e < argc; e++) { if (!strcasecmp("loop", argn[e])) { THIS->repeats = my_atoi(argv[e], MAXINT, 1); } else if (!strcasecmp("autostart", argn[e])) { THIS->autostart = !!my_atoi(argv[e], 1, 0); } /* get the index of the src attribute */ else if (!strcasecmp("src", argn[e])) { src_idx = e; } /* copy the flag to put it into the environement later */ D("VAR_%s=%s\n", argn[e], argv[e]); if (!(THIS->args[e].name = (char *)malloc(strlen(argn[e]) + 5))) return NPERR_OUT_OF_MEMORY_ERROR; sprintf(THIS->args[e].name, "VAR_%s", argn[e]); THIS->args[e].value = argv[e] ? strdup(argv[e]) : NULL; } /* Special case for quicktime. If there's an href or qtsrc attribute, we want that instead of src but we HAVE to have a src first. */ for (e = 0; e < argc; e++) { D("arg %d(%s): %s\n",e,argn[e],argv[e]); if ((!strcasecmp("href", argn[e]) || !strcasecmp("qtsrc", argn[e])) && src_idx > -1 && !THIS->href) { if (!(THIS->href = strdup(argv[e]))) return NPERR_OUT_OF_MEMORY_ERROR; } } if (src_idx > -1) { char *url = argv[src_idx]; if (!strncmp(url, "mms://", 6) || !strncmp(url, "mmst://", 7)) { D("Detected MMS\n"); THIS->mms = strdup(url); } } D("New finished\n"); return NPERR_NO_ERROR; } /***************************************************************************** * Free data, kill processes, it is time for this instance to die. *****************************************************************************/ NPError NPP_Destroy(NPP instance, NPSavedData** save) { int e; D("Destroy\n"); if (!instance) return NPERR_INVALID_INSTANCE_ERROR; if (THIS) { /* Kill the mozplugger-helper process and his sons */ if (THIS->pid > 0) my_kill(-THIS->pid); if (THIS->fd > 0) close(THIS->fd); for (e = 0; e < THIS->num_arguments; e++) { free((char *)THIS->args[e].name); free((char *)THIS->args[e].value); } NPN_MemFree((char *)THIS->args); free(THIS->mimetype); free(THIS->href); free(THIS->mms); NPN_MemFree(THIS); THIS = NULL; } D("Destroy finished\n"); return NPERR_NO_ERROR; } /***************************************************************************** * Check that no child is already running before forking one. *****************************************************************************/ static void new_child(NPP instance, const char* fname) { int pipe[2]; D("NEW_CHILD(%s)\n", fname); if (!instance || !fname) return; if (THIS->pid != -1) return; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe) < 0) { NPN_Status(instance, "MozPlugger: Failed to create a pipe!"); return; } if ((THIS->pid = my_fork(instance)) == -1) return; if (!THIS->pid) { if (!find_command(instance, 1) && !find_command(instance, 0)) _exit(EX_UNAVAILABLE); THIS->fd = pipe[1]; close(pipe[0]); D("CHILD RUNNING run() [2]\n"); run(instance, fname); _exit(EX_UNAVAILABLE); } else { THIS->fd = pipe[0]; close(pipe[1]); } } /***************************************************************************** * Open a new stream. * Each instance can only handle one stream at a time. *****************************************************************************/ NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype) { D("NewStream\n"); if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; if (THIS->pid != -1) return NPERR_INVALID_INSTANCE_ERROR; /* This is a stupid special case and should be coded into * mozpluggerc instead... */ if (!strncasecmp("image/", type, 6) || !strncasecmp("x-image/", type, 6)) THIS->repeats = 1; /* Replace the stream's URL with the URL in THIS->href if it * exists. Since we're going to be replacing 's src with * href, we want to make sure that the URL is not going to try * anything dirty. */ if (THIS->href != NULL && safeURL(THIS->href)) { D("Replacing SRC with HREF... \n"); stream->url = THIS->href; } D("Mime type %s\n", type); D("Url is %s (seekable=%d)\n", stream->url, seekable); /* A command may be removed after mozplugger has been loaded. */ if (!find_command(instance, 1) && !find_command(instance, 0)) { NPN_Status(instance, "MozPlugger: No appropriate application found."); return NPERR_GENERIC_ERROR; } if ((THIS->flags & H_STREAM) && strncasecmp(stream->url, "file:", 5) && strncasecmp(stream->url, "imap:", 5) && strncasecmp(stream->url, "mailbox:", 8)) { *stype = NP_NORMAL; new_child(instance, stream->url); } else { *stype = NP_ASFILEONLY; } return NPERR_NO_ERROR; } /***************************************************************************** * Called after NPP_NewStream if *stype = NP_ASFILEONLY. *****************************************************************************/ void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname) { D("StreamAsFile\n"); new_child(instance, fname); } void resize_window(NPP instance) { XSetWindowAttributes attrib; attrib.override_redirect = True; XChangeWindowAttributes(THIS->display, (Window)THIS->windata.window, CWOverrideRedirect, &attrib); D("Resizing WIN 0x%x to %dx%d!?\n", THIS->windata.window, THIS->windata.width, THIS->windata.height); XResizeWindow(THIS->display, (Window)THIS->windata.window, THIS->windata.width, THIS->windata.height); } /***************************************************************************** * Called when initializing or resizing the window. *****************************************************************************/ NPError NPP_SetWindow(NPP instance, NPWindow* window) { D("SetWindow\n"); if (!instance) return NPERR_INVALID_INSTANCE_ERROR; if (!window) return NPERR_NO_ERROR; if (!window->window) return NPERR_NO_ERROR; if (!window->ws_info) return NPERR_NO_ERROR; THIS->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display; THIS->displayname = XDisplayName(DisplayString(THIS->display)); THIS->windata = *window; if (THIS->mms) { new_child(instance, THIS->mms); free(THIS->mms); THIS->mms = NULL; return NPERR_NO_ERROR; } if (THIS->fd != -1) { D("Writing WIN 0x%x to fd %d\n", window->window, THIS->fd); write(THIS->fd, (char *)window, sizeof(*window)); } resize_window(instance); /* In case Mozilla would call NPP_SetWindow() in a loop. */ usleep(4000); return NPERR_NO_ERROR; } /***************************************************************************** * Empty functions. *****************************************************************************/ NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason) { D("DestroyStream\n"); return NPERR_NO_ERROR; } NPError NPP_Initialize(void) { D("Initialize\n"); do_read_config(); return NPERR_NO_ERROR; } jref NPP_GetJavaClass() { D("GetJavaClass\n"); return NULL; } void NPP_Shutdown(void) { D("Shutdown\n"); } void NPP_Print(NPP instance, NPPrint* printInfo) { D("Print\n"); } int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf) { D("Write %d\n", len); return len; } int32 NPP_WriteReady(NPP instance, NPStream *stream) { D("WriteReady\n"); if (!instance) { D("No instance\n"); return 0; } D("Return MAXINT\n"); return MAXINT; }