1 /**
2  * This file is part of mozplugger a fork of plugger, for list of developers
3  * see the README file.
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, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sysexits.h>
30 #include <signal.h>
31 #include <fcntl.h>
32 #include <sys/stat.h>
33 #include <sys/wait.h>
34 #include <sys/socket.h>
35 #include <errno.h>
36 #include <stdarg.h>
37 #include <time.h>
38 #include <utime.h>
39 
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
42 
43 #ifdef HAVE_GETPWUID
44 #include <pwd.h> /* For alternative way to find HOME dir */
45 #endif
46 
47 #define XP_UNIX
48 #include "npapi.h"
49 #include "npruntime.h"
50 #include "npn_func_tab.h"
51 #include "npp_func_tab.h"
52 #include "npn_funcs.h"
53 #include "npp_funcs.h"
54 #include "np_funcs.h"
55 
56 #include "mozplugger.h"
57 #include "debug.h"
58 #include "npn-get-helpers.h"
59 #include "cmd_flags.h"
60 #include "scriptable_obj.h"
61 #include "pipe_msg.h"
62 
63 #ifndef __GNUC__
64 #define __inline
65 #endif
66 
67 #define AUTO_UPDATE
68 #define CHUNK_SIZE (8192)
69 
70 /**
71  * Element of linked list of commands created when parsing config file
72  */
73 typedef struct command
74 {
75      int flags;
76      const char * cmd;
77      const char * winname;
78      const char * fmatchStr;
79 
80      struct command * pNext;
81 } command_t;
82 
83 
84 /**
85  * Element of fixed size array created when parsing NPP_New call
86  */
87 typedef struct argument
88 {
89      char *name;
90      char *value;
91 } argument_t;
92 
93 /**
94  * Data associated with an instance of an embed object, can be more than
95  * one
96  */
97 typedef struct data
98 {
99      Display * display;
100      Window window;
101      uint32_t width;
102      uint32_t height;
103      pid_t pid;
104      int commsPipeFd;
105      int repeats;
106      command_t * command;     /**< command to execute */
107      unsigned int mode_flags; /**< flags associated with browser calls */
108      char *mimetype;
109      char *href;               /**< If QT this is set to handle special case */
110      char *url;                /**< The URL */
111      char browserCantHandleIt; /**< Is set if browser cant handle protocol */
112      char *urlFragment;
113 
114      int tmpFileFd;     /**< File descriptor of temp file */
115      const char * tmpFileName; /**< Name of the temp file */
116      int tmpFileSize;   /**< Size of temp file so far */
117 
118      char autostart;
119      char autostartNotSeen;
120      int num_arguments;
121      struct argument *args;
122 } data_t;
123 
124 /**
125  * Element of linked list of mimetypes created when parsing config file
126  */
127 typedef struct mimetype
128 {
129      const char * type;
130 
131      struct mimetype * pNext;
132 } mimetype_t;
133 
134 /**
135  * Element of linked list of handlers created when parsing config file
136  */
137 typedef struct handle
138 {
139      mimetype_t * types;
140      command_t * cmds;
141 
142      struct handle * pNext;
143 } handler_t;
144 
145 /**
146  * Global variables
147  */
148 
149 static char errMsg[512] = {0};
150 static handler_t * g_handlers = 0;
151 
152 static const char * g_pluginName = "MozPlugger dummy Plugin";
153 static const char * g_version = VERSION;
154 static const char * g_linker = NULL;
155 static const char * g_controller = NULL;
156 static const char * g_helper = NULL;
157 
158 static char staticPool[MAX_STATIC_MEMORY_POOL];
159 static int staticPoolIdx = 0;
160 
161 /**
162  * Wrapper for putenv(). Instead of writing to the envirnoment, the envirnoment
163  * variables are written to a buffer.
164  *
165  * @param[in,out] buffer The buffer where the environment variables are written
166  * @param[in] bufLen The length of the buffer
167  * @param[in] offset The current position in the buffer
168  * @param[in] var The name of the environment variable
169  * @param[in] value The value of the environment variable
170  *
171  * @return The new offset
172  */
my_putenv(char * buffer,int bufLen,int offset,const char * var,const char * value)173 static int my_putenv(char *buffer, int bufLen, int offset, const char *var,
174                                                  const char *value)
175 {
176      if(value)
177      {
178           const int len = strlen(var) + strlen(value) + 2;
179           if (offset + len >= bufLen)
180           {
181                D("Buffer overflow in putenv(%s=%s) offset=%i, bufLen=%i\n",
182                                                    var, value, offset, bufLen);
183           }
184           else
185           {
186                snprintf(&buffer[offset], len, "%s=%s", var, value);
187                putenv(&buffer[offset]);
188                offset += len;
189           }
190      }
191      else
192      {
193           D("putenv did nothing, no value for %s\n", var);
194      }
195      return offset;
196 }
197 
198 /**
199  * putenv with a unsigned value
200  *
201  * @param[in,out] buffer The buffer where the environment variables are written
202  * @param[in] bufLen The length of the buffer
203  * @param[in] offset The current position in the buffer
204  * @param[in] var The name of the environment variable
205  * @param[in] value The value of the environment variable
206  *
207  * @return The new offset
208  */
my_putenv_unsigned(char * buffer,int bufLen,int offset,const char * var,unsigned long value)209 static int my_putenv_unsigned(char *buffer, int bufLen, int offset,
210                                           const char *var, unsigned long value)
211 {
212      char temp[50];
213      snprintf(temp, sizeof(temp), "%lu", value);
214      return my_putenv(buffer, bufLen, offset, var, temp);
215 }
216 
217 /**
218  * putenv with a hex value
219  *
220  * @param[in,out] buffer The buffer where the environment variables are written
221  * @param[in] bufLen The length of the buffer
222  * @param[in] offset The current position in the buffer
223  * @param[in] var The name of the environment variable
224  * @param[in] value The value of the environment variable
225  *
226  * @return The new offset
227  */
my_putenv_hex(char * buffer,int bufLen,int offset,const char * var,unsigned long value)228 static int my_putenv_hex(char *buffer, int bufLen, int offset,
229                                           const char *var, unsigned long value)
230 {
231      char temp[50];
232      snprintf(temp, sizeof(temp), "0x%lx", value);
233      return my_putenv(buffer, bufLen, offset, var, temp);
234 }
235 
236 /**
237  * putenv with a string
238  *
239  * @param[in,out] buffer The buffer where the environment variables are written
240  * @param[in] bufLen The length of the buffer
241  * @param[in] offset The current position in the buffer
242  * @param[in] var The name of the environment variable
243  * @param[in] value The value of the environment variable
244  *
245  * @return The new offset
246  */
my_putenv_signed(char * buffer,int bufLen,int offset,const char * var,long value)247 static int my_putenv_signed(char *buffer, int bufLen, int offset,
248                                                    const char *var, long value)
249 {
250      char temp[50];
251      snprintf(temp, sizeof(temp), "%ld", value);
252      return my_putenv(buffer, bufLen, offset, var, temp);
253 }
254 
255 /**
256  * Report the error
257  *
258  * @param[in] fmt The format string
259  */
reportError(NPP instance,const char * fmt,...)260 static void reportError(NPP instance, const char * fmt, ...)
261 {
262      va_list ap;
263      va_start(ap, fmt);
264 
265      vsnprintf(errMsg, sizeof(errMsg), fmt, ap);
266      va_end(ap);
267 
268      if(instance)
269      {
270           NPN_Status(instance, errMsg);
271      }
272      fprintf(stderr, "%s\n",errMsg);
273      D("%s\n", errMsg);
274 }
275 
clearError(void)276 static void clearError(void)
277 {
278      errMsg[0] = 0;
279 }
280 
haveError(void)281 static bool haveError(void)
282 {
283      return errMsg[0] != 0;
284 }
285 
286 /**
287  * Allocate some memory from the static pool. We use a static pool for
288  * the database because Mozilla can unload the plugin after use and this
289  * would lead to memory leaks if we use the heap.
290  *
291  * @param[in] size The size of the memory to allocate
292  *
293  * @return Pointer to the memory allocated or NULL
294  */
allocStaticMem(int size)295 static void * allocStaticMem(int size)
296 {
297      void * retVal = NULL;
298      const int newIdx = staticPoolIdx + size;
299 
300      if(newIdx > MAX_STATIC_MEMORY_POOL)
301      {
302           reportError(NULL, "MozPlugger: config file is too big - delete some handlers/commands or mimetypes");
303      }
304      else
305      {
306           retVal = &staticPool[staticPoolIdx];
307           staticPoolIdx = newIdx;
308      }
309      return retVal;
310 }
311 
312 /**
313  * Make a dynamic string static by copying to static memory.
314  * Given a pointer to a string in temporary memory, return the same string
315  * but this time stored in permanent (i.e. static) memory. Will only be deleted
316  * when the plugin is unloaded by Mozilla.
317  *
318  * @param[in] str Pointer to the string
319  * @param[in] len The length of the string
320  *
321  * @return Pointer to the copied string
322  */
makeStrStatic(const char * str,int len)323 static const char * makeStrStatic(const char * str, int len)
324 {
325      /* plus one for string terminator */
326      char * const buf = allocStaticMem(len + 1);
327 
328      if(buf)
329      {
330           strncpy(buf, str, len);
331           buf[len] = '\0';
332      }
333      return buf;
334 }
335 
336 /**
337  * Search backwards from end of string buffer until first non-white space
338  * and then terminate string after that point to perform a trim.
339  *
340  * @param[in,out] buf The string to be trimmed.
341  */
trim_trailing_spaces(char * buf)342 static void trim_trailing_spaces(char * buf)
343 {
344      char * end = &buf[strlen(buf)-1];
345      for( ;end >= buf; end--)
346      {
347           if((*end != '\r') && (*end != '\n') && (*end != '\t') && (*end != ' '))
348           {
349                end[1] = '\0';
350                return;
351           }
352      }
353 }
354 
355 /**
356  * Trim the line buffer and if the line is empty or contains just a comment
357  * return false
358  *
359  * @param[in] buffer The line read
360  *
361  * @return true if not a blank line
362  */
chkCfgLine(char * buffer)363 static bool chkCfgLine(char * buffer)
364 {
365      if(buffer[0] != '#')
366      {
367           trim_trailing_spaces(buffer);
368           return true;
369      }
370      return false;
371 }
372 
is_base_mozplugger(const char * magic)373 static bool is_base_mozplugger(const char * magic)
374 {
375      return (magic[0] == '-');
376 }
377 
378 /**
379  * Get the home directory
380  *
381  * @return a pointer to const string that contains home directory
382  */
get_home_dir(void)383 static const char * get_home_dir(void)
384 {
385      const char * home = getenv("HOME");
386 #ifdef HAVE_GETPWUID
387      if(home == NULL)
388      {
389           struct passwd * pw = getpwuid(getuid());
390           home = pw->pw_dir;
391      }
392 #endif
393      return home;
394 }
395 
396 /**
397  * Get the prefix to the path to the config files based on the magic
398  *
399  * @param[in] magic references for this particular plugin type
400  * @param[out] buf The buffer to put the prefix
401  * @param[in] bufLen The length of the buffer
402  *
403  * @return the sizeof the resulting string
404  */
get_cfg_path_prefix(const char * magic,char * buf,int bufLen)405 static int get_cfg_path_prefix(const char * magic, char * buf, int bufLen)
406 {
407      const char * fmt;
408      int prefixLen = 1;
409      const char * home;
410 
411      if(is_base_mozplugger(magic))
412      {
413           magic = "0";
414      }
415      else
416      {
417           prefixLen = strchr(magic, ':') - magic;
418      }
419 
420      /* Locations are ...
421       * $MOZPLUGGER_HOME/.cache/
422       * $XDG_CACHE_HOME/mozplugger/
423       * $HOME/.cache/mozplugger/
424       */
425 
426      if( (home = getenv("MOZPLUGGER_HOME")) != NULL)
427      {
428           fmt = "%s/.cache/%.*s";
429      }
430      else if( (home = getenv("XDG_CACHE_HOME")) != NULL)
431      {
432           fmt = "%s/mozplugger/%.*s";
433      }
434      else if( (home = get_home_dir()) != NULL)
435      {
436           fmt = "%s/.cache/mozplugger/%.*s";
437      }
438      else
439      {
440           reportError(NULL, "Mozplugger cannot determine HOME directory\n");
441           *buf = '\0';
442           return 0;
443      }
444      return snprintf(buf, bufLen, fmt, home, prefixLen, magic);
445 }
446 
447 /**
448  * Get the paths to the mozplugger helpers.
449  *
450  * @param[in] magic references for this particular plugin type
451  *
452  * @return None
453  */
get_helper_paths(const char * magic)454 static void get_helper_paths(const char * magic)
455 {
456      char fname[200];
457      FILE * fp;
458      int n;
459 
460      if(g_controller || g_linker || g_helper)
461          return;
462 
463      n = get_cfg_path_prefix(magic, fname, sizeof(fname));
464      strncat(fname, ".helpers", sizeof(fname) - n);
465 
466      if((fp = fopen(fname, "rb")) != NULL)
467      {
468           char buffer[512];
469           while(fgets(buffer, sizeof(buffer), fp))
470           {
471                if(chkCfgLine(buffer))
472                {
473                     char * sep = strchr(buffer, '\t');
474                     int pathLen = strlen(&sep[1]);
475                     *sep = '\0';
476                     if(strcmp(buffer, "linker") == 0)
477                     {
478                          g_linker = makeStrStatic(&sep[1], pathLen);
479                     }
480                     else if(strcmp(buffer, "controller") == 0)
481                     {
482                          g_controller = makeStrStatic(&sep[1], pathLen);
483                     }
484                     else if(strcmp(buffer, "version") == 0)
485                     {
486                          g_version = makeStrStatic(&sep[1], pathLen);
487                     }
488                     else if(strcmp(buffer, "name") == 0)
489                     {
490                          g_pluginName = makeStrStatic(&sep[1], pathLen);
491                     }
492                     else if(strcmp(buffer, "helper") == 0)
493                     {
494                          g_helper = makeStrStatic(&sep[1], pathLen);
495                     }
496                }
497           }
498           fclose(fp);
499      }
500 }
501 
502 /**
503  * Get the path to the configuration file.
504  *
505  * @param[in] magic references for this particular plugin type
506  *
507  * @return The full path to the configuration file
508  */
get_cmds_cfg_path(const char * magic)509 static char * get_cmds_cfg_path(const char * magic)
510 {
511      char fname[200];
512 
513      int n = get_cfg_path_prefix(magic, fname, sizeof(fname));
514      strncat(fname, ".cmds", sizeof(fname) - n);
515 
516      return strdup(fname);
517 }
518 
519 /**
520  * Get the path to the mimetypes file.
521  *
522  * @param[in] magic references for this particular plugin type
523  *
524  * @return The full path to the configuration file
525  */
get_mimetypes_cfg_path(const char * magic)526 static char * get_mimetypes_cfg_path(const char * magic)
527 {
528      char fname[200];
529 
530      int n = get_cfg_path_prefix(magic, fname, sizeof(fname));
531      strncat(fname, ".mimetypes", sizeof(fname) - n);
532 
533      return strdup(fname);
534 }
535 
536 
537 /**
538  * Wrapper for execlp() that calls the helper.
539  *
540  * WARNING: This function runs in the daughter process so one must assume the
541  * daughter uses a copy (including) heap memory of the parent's memory space
542  * i.e. any write to memory here does not affect the parent memory space.
543  * Since Linux uses copy-on-write, best leave memory read-only and once execlp
544  * is called, all daughter memory is wiped anyway (except the stack).
545  *
546  * @param[in] THIS Pointer to the data associated with this instance of the
547  *                     plugin
548  * @param[in] file The url of the embedded object
549  * @param[in] pipeFd The file descriptor of the pipe to the helper application
550  */
run(data_t * const THIS,const char * file,int pipeFd)551 static void run(data_t * const THIS, const char *file, int pipeFd)
552 {
553      char buffer[ENV_BUFFER_SIZE];
554      int offset = 0;
555      int i;
556      unsigned int flags = THIS->command->flags;
557      int autostart = THIS->autostart;
558      const char * launcher = NULL;
559      const char * nextHelper = NULL;
560 
561      /* If there is no window to draw the controls in then
562       * dont use controls -> mozdev bug #18837 */
563      if((THIS->window == 0) &&  ((flags & (H_CONTROLS | H_LINKS)) != 0) )
564      {
565           D("Cannot use controls or link button as no window to draw"
566                                                               " controls in\n");
567 	  flags &= ~(H_CONTROLS | H_LINKS);
568      }
569 
570      /* If no autostart seen and using controls dont autostart by default */
571      if ((flags & (H_CONTROLS | H_LINKS)) && (THIS->autostartNotSeen))
572      {
573           autostart = 0;
574      }
575 
576      snprintf(buffer, sizeof(buffer), "%d,%d,%d,%lu,%d,%d",
577 	      flags,
578 	      THIS->repeats,
579 	      pipeFd,
580 	      (unsigned long int) THIS->window,
581 	      (int) THIS->width,
582 	      (int) THIS->height);
583 
584      offset = strlen(buffer)+1;
585 
586      offset = my_putenv_unsigned(buffer, sizeof(buffer), offset,
587                                                         "window", THIS->window);
588 
589      offset = my_putenv_hex(buffer, sizeof(buffer), offset,
590                                                      "hexwindow", THIS->window);
591 
592      offset = my_putenv_signed(buffer, sizeof(buffer), offset,
593                                                       "repeats", THIS->repeats);
594 
595      offset = my_putenv_unsigned(buffer, sizeof(buffer), offset,
596                                                           "width", THIS->width);
597 
598      offset = my_putenv_unsigned(buffer, sizeof(buffer), offset,
599                                                         "height", THIS->height);
600 
601      offset = my_putenv(buffer, sizeof(buffer), offset,
602                                                     "mimetype", THIS->mimetype);
603 
604      offset = my_putenv(buffer, sizeof(buffer), offset, "file", file);
605 
606      offset = my_putenv(buffer, sizeof(buffer), offset,
607                                                  "fragment", THIS->urlFragment);
608 
609      offset = my_putenv(buffer, sizeof(buffer), offset,
610                                             "autostart", autostart ? "1" : "0");
611 
612      offset = my_putenv(buffer, sizeof(buffer), offset,
613                                              "winname", THIS->command->winname);
614 
615      if(THIS->display)
616      {
617           char * displayname = XDisplayName(DisplayString(THIS->display));
618           offset = my_putenv(buffer, sizeof(buffer), offset, "DISPLAY", displayname);
619      }
620 
621      for (i = 0; i < THIS->num_arguments; i++)
622      {
623 	  offset = my_putenv(buffer, sizeof(buffer), offset,
624                                        THIS->args[i].name, THIS->args[i].value);
625      }
626 
627      if(flags & H_CONTROLS)
628      {
629           launcher = g_controller;
630      }
631      else if(flags & H_LINKS)
632      {
633           launcher = g_linker;
634      }
635      else if(!autostart && !(flags & H_AUTOSTART) && (THIS->window != 0))
636      {
637           /* Application doesn't do autostart and autostart is false and
638            * we have a window to draw in */
639 	  nextHelper = g_helper;
640           launcher = g_linker;
641      }
642      else
643      {
644           launcher = g_helper;
645      }
646 
647      if(launcher == 0)
648      {
649           D("No launcher defined");
650           _exit(EX_UNAVAILABLE); /* Child exit, that's OK */
651      }
652 
653      D("Executing helper: %s %s %s %s %s\n",
654        launcher,
655        buffer,
656        file,
657        THIS->command->cmd,
658        THIS->mimetype);
659 
660      execlp(launcher, launcher, buffer, THIS->command->cmd, nextHelper, NULL);
661 
662      D("EXECLP FAILED! errno=%i\n", errno);
663 
664      _exit(EX_UNAVAILABLE); /* Child exit, that's OK */
665 
666 }
667 
NP_strdup2(const char * str,int len)668 static char * NP_strdup2(const char * str, int len)
669 {
670      char * dupStr = NPN_MemAlloc(len + 1);
671      if(dupStr != NULL)
672      {
673           strncpy(dupStr, str, len);
674           dupStr[len] = '\0';
675      }
676      else
677      {
678           D("NPN_MemAlloc failed, size=%i\n", len+1);
679      }
680      return dupStr;
681 }
682 
683 
684 /**
685  * String dup function that uses NPN_MemAlloc as opposed to malloc
686  *
687  * WARNING, this function will not work if directly or indirectly called from
688  * NPP_GetMimeDescription.
689  *
690  * @param[in] str The string to duplicate
691  *
692  * @return Pointer to the duplicate.
693  */
NP_strdup(const char * str)694 static char * NP_strdup(const char * str)
695 {
696      return NP_strdup2(str, strlen(str));
697 }
698 
699 
700 /**
701  * Test if the line buffer contains a mimetype
702  *
703  * @param[in] buffer The line buffer
704  *
705  * @return true if contains a mimetype
706  */
isCfgMimeType(char * buffer)707 static bool isCfgMimeType(char * buffer)
708 {
709     return !isspace(buffer[0]);
710 }
711 
712 /**
713  * Parse the mimetypec in the cfg file
714  *
715  * @param[in] buffer The line read from config file
716  *
717  * @return a mimetype_t structure if valid mimetype.
718  */
parseCfgMimeType(char * buffer)719 static mimetype_t * parseCfgMimeType(char * buffer)
720 {
721      mimetype_t * type = (mimetype_t *) allocStaticMem(sizeof(mimetype_t));
722      if(type == 0)
723      {
724           D("Failed to alloc memory for mimetype\n");
725           return NULL;
726      }
727      memset(type, 0, sizeof(mimetype_t));
728 
729      D("New mime type\n");
730 
731      /* Cant use NPN_MemAlloc in NPP_GetMimeDescription, use
732       * makeStrStatic as opposed to strdup otherwise we get a
733       * memory leak */
734      type->type = makeStrStatic(buffer, strlen(buffer));
735 
736      return (type->type == 0) ? NULL : type;
737 }
738 
739 /**
740  * Parse the command found in the cfg file
741  *
742  * @param[in] buffer The line read from config file
743  *
744  * @return a command structure if command found.
745  */
parseCfgCmdLine(char * buffer)746 static command_t * parseCfgCmdLine(char * buffer)
747 {
748      char * x = &buffer[1];
749      char * sep;
750 
751      command_t * cmd = (command_t *) allocStaticMem(sizeof(command_t));
752      if(cmd == NULL)
753      {
754            D("Failed to alloc memory for command\n");
755            return NULL;
756      }
757      memset(cmd, 0, sizeof(command_t));
758 
759      D("-- reading cmd line %s\n", x);
760 
761      sep = strchr(x, '\t');
762      cmd->flags = strtol(x, NULL, 16);
763      x = &sep[1];
764      sep = strchr(x, '\t');
765      if(sep > x)
766      {
767           cmd->winname = makeStrStatic(x, sep - x);
768      }
769      x = &sep[1];
770      sep = strchr(x, '\t');
771      if( sep > x)
772      {
773           cmd->fmatchStr = makeStrStatic(x, sep - x);
774      }
775      x = &sep[1];
776      cmd->cmd = makeStrStatic(x, strlen(x));
777      return cmd;
778 }
779 
780 /**
781  * Read the configuration file into memory.
782  *
783  * @param[in] f The FILE pointer
784  */
read_config(FILE * f)785 static void read_config(FILE * f)
786 {
787      int num_handlers = 0;
788 
789      handler_t * prev_handler = NULL;
790      handler_t * handler = NULL;
791 
792      command_t * prev_cmd = NULL;
793      mimetype_t * prev_type = NULL;
794 
795      char lineBuf[512];
796      int lineNum;
797 
798      D("read_config\n");
799 
800      lineNum = 0;
801      while (fgets(lineBuf, sizeof(lineBuf), f))
802      {
803           lineNum++;
804           if(!chkCfgLine(lineBuf))
805           {
806                continue;
807           }
808 
809 	  D("%5i::|%s|\n", lineNum, lineBuf);
810 
811           if(isCfgMimeType(lineBuf))
812 	  {
813 	       /* Mime type */
814                mimetype_t * type = NULL;
815 
816 	       if (!handler || handler->cmds)
817 	       {
818 		    D("------------ Starting new handler ---------\n");
819 
820 		    handler = (handler_t *) allocStaticMem(sizeof(handler_t));
821                     if(handler == 0)
822                     {
823                          return;
824                     }
825                     memset(handler, 0, sizeof(handler_t));
826 
827                     prev_type = NULL;
828                     prev_cmd = NULL;
829 
830                     if(prev_handler)
831                     {
832                          /* Add to end of linked list of handlers */
833                          prev_handler->pNext = handler;
834                     }
835                     else
836                     {
837                          /* Add at header of link list of handlers */
838                          g_handlers = handler;
839                     }
840                     /* Remember the current end of linked list */
841                     prev_handler = handler;
842 
843                     num_handlers++;
844 	       }
845 
846                type = parseCfgMimeType(lineBuf);
847                if(!type)
848                {
849                     return; /* run out of memory! */
850                }
851                if(prev_type)
852                {
853                     /* Add to end of linked list of handlers */
854                     prev_type->pNext = type;
855                }
856                else
857                {
858                     /* Add at header of link list of handlers */
859                     handler->types = type;
860                }
861                /* Remember the current end of linked list */
862                prev_type = type;
863 	  }
864 	  else
865 	  {
866                command_t * cmd = parseCfgCmdLine(lineBuf);
867                if(!cmd)
868                {
869                     return; /* run out of memory! */
870                }
871                if(!handler)
872                {
873                     D("Command before mimetype!\n");
874                     return;
875                }
876 
877                if(prev_cmd)
878                {
879                     /* Add to end of linked list of handlers */
880                     prev_cmd->pNext = cmd;
881                }
882                else
883                {
884                     /* Add at header of link list of handlers */
885                     handler->cmds = cmd;
886                }
887                /* Remember the current end of linked list */
888                prev_cmd = cmd;
889           }
890      }
891      D("Num handlers: %d\n", num_handlers);
892 }
893 
894 /**
895  * Find configuration file, helper and controller executables. Call the
896  * appropriate xxx_cb function to handle the action (e.g. for configuration
897  * file, the parsering and reading into memory).
898  *
899  * @param[in] magic references for this particular plugin type
900  *
901  * @return false if failed, true otherwise
902  */
do_read_config(const char * magic)903 static bool do_read_config(const char * magic)
904 {
905      bool retVal = true;
906      char * config_fname;
907      if (g_handlers)
908      {
909           return retVal;
910      }
911 
912      D("do_read_config(%s)\n", magic);
913 
914      config_fname = get_cmds_cfg_path(magic);
915      get_helper_paths(magic);
916 
917      if(config_fname)
918      {
919           FILE * fd = fopen(config_fname, "rb");
920           if(fd)
921           {
922                read_config(fd);
923                fclose(fd);
924                D("do_read_config done\n");
925           }
926           else
927           {
928                D("Failed to read config %s\n", config_fname);
929                retVal = false;
930           }
931           free(config_fname);
932      }
933      else
934      {
935           if(!haveError())
936           {
937               reportError(NULL, "Mozplugger error - failed to locate %s", config_fname);
938           }
939 	  retVal = false;
940      }
941 
942      return retVal;
943 }
944 
945 /**
946  * Check URL is safe. Since href's are passed to an app as an argument, just
947  * check for ways that a shell can be tricked into executing a command.
948  *
949  * @param[in] name The name to check
950  * @param[in] isURL Is the name a URL or filename?
951  *
952  * @return true if OK, false if not
953  */
safeName(const char * name,int isURL)954 static bool safeName(const char* name, int isURL)
955 {
956      int i = 0;
957      const int len = strlen(name);
958 
959      if ((name[0] == '/') && (isURL))
960      {
961           D("safeName() - reject URL '%s' as starts with '/'\n", name);
962 	  return false;
963      }
964 
965      for (i = 0; i < len; i++)
966      {
967 	  if (name[i] == '`' || name[i] == ';')
968 	  {
969                D("safeName() - reject '%s' as contains either ';' or '`'\n", name);
970 	       /* Somebody's trying to do something naughty. */
971 	       return false;
972 	  }
973      }
974      return true;
975 }
976 
977 /**
978  * Extract the file name from the HTTP Headers (if present). This is passed
979  * via the fragment environment variable to the helper application. Copy
980  * a suitable filename for the URL to be used for the cached temporay file
981  * name.
982  *
983  * @param[in] THIS Pointer to the instance data
984  * @param[in] headers The HTTP headers to parse
985  * @param[out] fileName The file Name extracted from the headers
986  * @param[in] maxFileNameLen The max length of fileName
987  *
988  * @return None
989  */
parseHeaders(data_t * const THIS,const char * headers,char * fileName)990 static char * parseHeaders(data_t * const THIS, const char * headers, char * fileName)
991 {
992      const char * p = headers;
993 
994      if (!headers)
995      {
996           return fileName;
997      }
998 
999      while((p = strstr(p, "Content-Disposition:")) != NULL)
1000      {
1001           size_t len = strcspn(p, "\n\r");
1002 	  const char * start = strstr(p, "filename=\"");
1003 
1004 	  if (len == 0)
1005           {
1006 	       break;
1007           }
1008 
1009           if((start ==0) || (start - p > len))
1010           {
1011 	       p += len;
1012 	       continue;
1013 	  }
1014  	  start += strlen("filename=\"");
1015 	  len = len - (start - p) - 1;
1016 
1017 	  if(len > 0)
1018           {
1019                 if(fileName)
1020                 {
1021                      NPN_MemFree(fileName);
1022                 }
1023                 fileName = NP_strdup2(start, len);
1024 	  }
1025 	  p += len;
1026      }
1027      return fileName;
1028 }
1029 
1030 /**
1031  * Extract the 'fragment' from the end of the URL if present. This is passed
1032  * via the fragment environment variable to the helper application. Copy
1033  * a suitable filename for the URL to be used for the cached temporay file
1034  * name.
1035  *
1036  * @param[in] THIS Pointer to the instance data
1037  * @param[out] fileName The file Name extracted from the URL
1038  * @param[in] maxFileNameLen The max length of fileName
1039  *
1040  * @return Pointer to allocated memory with fileName
1041  */
parseURL(data_t * const THIS,int extract_filename)1042 static char * parseURL(data_t * const THIS, int extract_filename)
1043 {
1044      const char * frag = strchr(THIS->url, '#');
1045 
1046      if(frag)
1047      {
1048           if(THIS->urlFragment)
1049           {
1050               D("parseURL - replacing previous fragment\n");
1051               NPN_MemFree(THIS->urlFragment);
1052           }
1053 
1054           D("parseURL - fragment '%s' found at end of URL\n", &frag[1]);
1055           THIS->urlFragment = NP_strdup(&frag[1]);
1056      }
1057 
1058      if(extract_filename)
1059      {
1060           const char * end = strrchr(THIS->url, '?');
1061           const char * start;
1062           int len;
1063 
1064           /* Find end or url (but dont include variable params or fragment */
1065           if(!end)
1066           {
1067                end = frag ? frag : &THIS->url[strlen(THIS->url)];
1068           }
1069           /* Work backwards to the first forward slash */
1070           start = &end[-1];
1071           while( (start > THIS->url) && (*start != '/'))
1072           {
1073                start--;
1074           }
1075           if(*start == '/')
1076           {
1077                start++;
1078           }
1079           len = end-start;
1080           return NP_strdup2(start, len);
1081      }
1082      return NULL;
1083 }
1084 
1085 /**
1086  * See if the URL matches out match criteria.
1087  *
1088  * @param[in] matchStr The string to match
1089  * @param[in] url The url
1090  *
1091  * @return 1(true) if matched, zero otherwise
1092  */
1093 __inline
match_url(const char * matchStr,const char * url)1094 static int match_url(const char * matchStr, const char * url)
1095 {
1096      int matchStrLen;
1097      const char * end;
1098 
1099      switch (matchStr[0])
1100      {
1101      case '*':
1102           /* Does the URL start with the match String */
1103           matchStr++; /* Step over the asterisk */
1104 	  return (strncasecmp(matchStr, url, strlen(matchStr)) == 0);
1105 
1106      case '%':
1107           /* Does the URL end with the match String */
1108           matchStr++; /* Step over the percent sign */
1109 
1110           /* Need to find the end of the url, before any
1111            * extra params i.e'?=xxx' or '#yyy' */
1112           if( (end = strchr(url, '?')) == NULL)
1113           {
1114                if( (end = strchr(url, '#')) == NULL)
1115                {
1116                     end = &url[strlen(url)];
1117                }
1118           }
1119           matchStrLen = strlen(matchStr);
1120           if(end - matchStrLen < url)
1121           {
1122                return 0;
1123           }
1124 	  return (strncasecmp(matchStr, end-matchStrLen, matchStrLen) == 0);
1125 
1126      default:
1127           /* Is the match string anywhere in the URL */
1128 	  return (strstr(url, matchStr) != NULL);
1129      }
1130 }
1131 
1132 /**
1133  * Go through the commands in the config file and find one that fits our needs.
1134  *
1135  * @param[in] THIS Pointer to the data associated with this instance of the
1136  *                       plugin
1137  * @param[in] streamOnly If true select entry sith stream set only
1138  * @param[in] c Pointer to command structure to match against
1139  *
1140  * @return 1(true) if match, else zero otherwise
1141  */
1142 __inline
match_command(const data_t * THIS,int streamOnly,const command_t * c)1143 static int match_command(const data_t * THIS, int streamOnly, const command_t *c)
1144 {
1145 #define MODE_MASK (H_NOEMBED | H_EMBED)
1146 
1147      D("Checking command: %s\n", c->cmd);
1148 
1149      /* If command is specific to a particular mode... */
1150      if (c->flags & MODE_MASK)
1151      {
1152           /* Check it matches the current mode... */
1153           if ( (THIS->mode_flags & MODE_MASK) != (c->flags & MODE_MASK) )
1154           {
1155 	       D("Flag mismatch: mode different %x != %x\n",
1156                      THIS->mode_flags & MODE_MASK,  c->flags & MODE_MASK);
1157 	       return 0;
1158           }
1159      }
1160      if((THIS->mode_flags & H_LINKS) != 0)   /* Requires the links helper? */
1161      {
1162           if((c->flags & MODE_MASK) == 0)    /* But command is not */
1163           {
1164 	       D("Flag mismatch: cmd doesnt do links\n");
1165 	       return 0;
1166           }
1167      }
1168 
1169      if ((c->flags & H_LOOP) && (THIS->repeats != INF_LOOPS))
1170      {
1171 	  D("Flag mismatch: loop\n");
1172 	  return 0;
1173      }
1174      if (streamOnly && !(c->flags & H_STREAM))
1175      {
1176 	  D("Flag mismatch: stream only required\n");
1177 	  return 0;
1178      }
1179 
1180      if(c->fmatchStr)
1181      {
1182           if(!match_url(c->fmatchStr, THIS->url))
1183           {
1184                D("fmatch mismatch: url '%s' doesnt have '%s'\n",
1185                                               THIS->url, c->fmatchStr);
1186                return 0;
1187           }
1188      }
1189      D("Match found!\n");
1190      return 1;
1191 }
1192 
1193 /**
1194  * See if mimetype matches.
1195  *
1196  * @param[in] reqMimeType pointer to required mimetype
1197  * @param[in] m Mimetype to match against
1198  *
1199  * @return 1(true) if match, else zero otherwise
1200  */
1201 __inline
match_mime_type(const char * reqMimeType,mimetype_t * m)1202 static int match_mime_type(const char * reqMimeType, mimetype_t * m)
1203 {
1204      int retVal;
1205      if ((strcasecmp(m->type, reqMimeType) != 0) && (strcmp(m->type, "*") != 0))
1206      {
1207           retVal = 0;
1208      }
1209      else
1210      {
1211           retVal = 1;
1212      }
1213      D("Checking '%s' ?= '%s', %s\n", m->type, reqMimeType,
1214                                             retVal == 1 ? "same" : "different");
1215      return retVal;
1216 }
1217 
1218 /**
1219  * See if handler matches, if so check a command is available and return that
1220  * command.
1221  *
1222  * @param[in] h Pointer to handler to match against
1223  * @param[in] THIS Pointer to data associated with this instance of plugin
1224  * @param[in] streamOnly If True select only entry with stream flag
1225  *
1226  * @return Pointer to command struct if match or NULL
1227  */
1228 __inline
match_handler(const handler_t * h,const data_t * THIS,int streamOnly)1229 static command_t * match_handler(const handler_t * h, const data_t * THIS, int streamOnly)
1230 {
1231      mimetype_t *m;
1232 
1233      D("-------------------------------------------\n");
1234      D("Commands for this handle at (%p):\n", h->cmds);
1235 
1236      for(m = h->types; m; m = m->pNext)
1237      {
1238 	  if (match_mime_type(THIS->mimetype, m))
1239 	  {
1240                command_t * c;
1241                for(c = h->cmds; c; c = c->pNext)
1242 	       {
1243 		    if (match_command(THIS, streamOnly, c))
1244 		    {
1245 			 return c;
1246 		    }
1247 	       }
1248 	  }
1249      }
1250      return NULL;
1251 }
1252 
1253 /**
1254  * Find the appropriate command
1255  *
1256  * @param[in] THIS Pointer to plugin instance data
1257  * @param[in] streamOnly If true select only the command with stream flag
1258  *
1259  * @return Pointer to command struct if match, else NULL otherwise
1260  */
find_command(const data_t * THIS,int streamOnly)1261 static command_t * find_command(const data_t * THIS, int streamOnly)
1262 {
1263      handler_t * h;
1264 
1265      D("find_command...\n");
1266 
1267      for(h = g_handlers; h; h = h->pNext)
1268      {
1269           command_t * command = match_handler(h, THIS, streamOnly);
1270           if(command)
1271 	  {
1272 	       D("Command found.\n");
1273 	       return command;
1274 	  }
1275      }
1276 
1277      D("No command found.\n");
1278      return NULL;
1279 }
1280 
1281 /**
1282  * Get the plugin version string
1283  *
1284  * @param[in] magic references for this particular plugin type
1285  *
1286  * @return Pointer to the version string
1287  */
NP2_GetPluginVersion(const char * magic)1288 const char * NP2_GetPluginVersion(const char * magic)
1289 {
1290      D("NP_GetPluginVersion(%s)\n", magic);
1291      if(!is_base_mozplugger(magic))
1292      {
1293           get_helper_paths(magic);
1294      }
1295      D("NP_GetPluginVersion returning '%s'\n", g_version);
1296      return g_version;
1297 }
1298 
1299 /**
1300  * Rebuild the cached versions of configuration
1301  *
1302  * @return true if success.
1303  */
mozplugger_update(bool * pDoesntExist)1304 static bool mozplugger_update(bool * pDoesntExist)
1305 {
1306      bool success = true;
1307      pid_t pid;
1308 
1309      D("Called mozplugger_update\n");
1310      pid = fork();
1311      if(pid == -1)
1312      {
1313           fprintf(stderr, "Failed to fork\n");
1314 	  exit(EXIT_FAILURE);
1315      }
1316      else if(pid == 0)
1317      {
1318 	  execlp("mozplugger-update", "mozplugger-update", NULL);
1319           if( errno == EEXIST)
1320           {
1321                exit(1000);
1322           }
1323           exit(EXIT_FAILURE);
1324      }
1325      else
1326      {
1327          int status;
1328          D("Waiting for mozplugger-update\n");
1329          waitpid(pid, &status, 0);          /* If Application completed is a bad way, then lets give up now */
1330          if(!WIFEXITED(status))
1331          {
1332                D("mozplugger-update dumped core or something...\n");
1333                success = false;
1334          }
1335          else
1336          {
1337                status = WEXITSTATUS(status);
1338                if(status != EXIT_SUCCESS)
1339                {
1340                     D("mozplugger-update exited with status: %d\n", status);
1341                     success = false;
1342                     if(status == 1000)
1343                     {
1344                          *pDoesntExist = true;
1345                     }
1346                }
1347          }
1348      }
1349      D("mozplugger-update done\n");
1350      if(success)
1351      {
1352 //         NPN_ReloadPlugins(false);
1353      }
1354      return success;
1355 }
1356 
1357 /**
1358  * Check is the local plugin directories exist for various browsers
1359  * If they do then its likely that the user uses those browsers
1360  * so check mozplugger0.so exists in that directory
1361  *
1362  * @return false if we need to run update
1363  */
chkValidLocalPluginDirs()1364 static bool chkValidLocalPluginDirs()
1365 {
1366      static const char * browsers[] =
1367      {
1368           "%s/.mozilla/plugins",
1369           "%s/.netscape/plugins",
1370           "%s/.opera/plugins"
1371      };
1372 
1373      const char * home = get_home_dir();
1374      int i;
1375 
1376      if(home == NULL)
1377      {
1378            reportError(NULL, "Mozplugger cannot determine HOME directory");
1379            return false;
1380      }
1381 
1382      for(i = 0; i < sizeof(browsers)/sizeof(const char *); i++)
1383      {
1384           struct stat details;
1385           char fname[256];
1386           int n = snprintf(fname, sizeof(fname), browsers[i], home);
1387 
1388           if( (mkdir(fname, S_IRWXU) != 0) && (errno != EEXIST))
1389           {
1390                continue;
1391           }
1392 
1393           strncat(fname, "/mozplugger0.so", sizeof(fname) - n);
1394           if(stat(fname, &details) != 0)
1395           {
1396                return false;
1397           }
1398      }
1399      return true;
1400 }
1401 
1402 /**
1403  * Check the last time we updated the cache
1404  *
1405  * return -1 too soon, +1 about time to update
1406  */
chkTimeToUpdate(bool * update,bool * dont_update)1407 static time_t chkTimeToUpdate(bool * update, bool * dont_update)
1408 {
1409      struct stat details;
1410      char ts_fname[256];
1411      time_t ts_ftime = 0;
1412 
1413      get_cfg_path_prefix(".last_update:", ts_fname, sizeof(ts_fname));
1414      if(stat(ts_fname, &details) == 0)
1415      {
1416           time_t now = time(NULL);
1417           ts_ftime = details.st_mtime;
1418 
1419           if(ts_ftime > now)
1420           {
1421                D("Strange .last_update written in the future? %lu s\n", ts_ftime - now);
1422           }
1423           else
1424           {
1425                time_t diff = now - ts_ftime;
1426                if(diff < 10)
1427                {
1428                     D("Dont update, too soon %lu s\n", diff);
1429                     *dont_update = true;
1430                }
1431 #ifdef AUTO_UPDATE
1432                else if(diff > 7*24*60*60)
1433                {
1434                     D("Auto update %lu s\n", diff);
1435                     *update = true;
1436                }
1437           }
1438 #endif
1439      }
1440      return ts_ftime;
1441 }
1442 
1443 /**
1444  * Parse buf for text containing the VERSION of the config file. Check the
1445  * version matches
1446  *
1447  * @param[in] buf The string read from the description file
1448  *
1449  * @return false if not matches
1450  */
chk_version_matches(char * buf)1451 static bool chk_version_matches(char * buf)
1452 {
1453      D("Processed config version = '%s'\n", &buf[1]);
1454      trim_trailing_spaces(buf);
1455      if(strcmp(&buf[1],  VERSION) != 0)
1456      {
1457           D("Processed config format mismatch should be" VERSION "\n");
1458           return false;
1459      }
1460      return true;
1461 }
1462 
1463 /**
1464  * Parse buf for text containing the name of the config file. Check the
1465  * date and time of that file against the time of the cached file.
1466  *
1467  * @param[in] buf The string read from the description file
1468  *
1469  * @return false if description file written before timestamp
1470  */
chk_cached_is_newer(char * buf,time_t cached_ftime)1471 static bool chk_cached_is_newer(char * buf, time_t cached_ftime)
1472 {
1473      char * q = strstr(buf, "autogenerated from ");
1474      if(q)
1475      {
1476           struct stat details;
1477           q += 19;                  /* Skip text part */
1478           trim_trailing_spaces(q);
1479 
1480           if( (stat(q, &details) == 0) && (details.st_mtime <= cached_ftime))
1481           {
1482                return true;
1483           }
1484           else
1485           {
1486                D("mozpluggerrc = %s %u - %u\n", q, (unsigned) details.st_mtime, (unsigned) cached_ftime);
1487           }
1488     }
1489     return false;
1490 }
1491 
read_desc(const char * fname,time_t ts_ftime,bool * update,bool is_base)1492 static char * read_desc(const char * fname, time_t ts_ftime, bool *update, bool is_base)
1493 {
1494      char * desc = NULL;
1495      FILE * fp = fopen(fname, "rb");
1496 
1497      D("Reading '%s'\n", fname);
1498      if(fp != NULL)
1499      {
1500           char linebuf[256];
1501 
1502           if( fgets(linebuf, sizeof(linebuf), fp)
1503                   && chk_version_matches(linebuf)
1504                       && fgets(linebuf, sizeof(linebuf), fp)
1505                           && chk_cached_is_newer(linebuf, ts_ftime))
1506           {
1507                 while( fgets(linebuf, sizeof(linebuf), fp) && (linebuf[0] == '#'))
1508                      ;
1509 
1510                 if(!is_base)
1511                 {
1512                      struct stat details;
1513 
1514                      fstat(fileno(fp), &details);
1515                      desc = malloc(details.st_size+1);
1516                      if(desc)
1517                      {
1518                           D("Size '%u'\n", (unsigned) details.st_size);
1519 
1520                          strcpy(desc, linebuf);
1521                          fgets(&desc[strlen(linebuf)], details.st_size, fp);
1522                     }
1523                }
1524           }
1525           else
1526           {
1527                *update = true;
1528           }
1529           fclose(fp);
1530      }
1531      else
1532      {
1533           D("Failed to read description\n");
1534 #ifdef AUTO_UPDATE
1535           *update = true;
1536 #endif
1537      }
1538      return desc;
1539 }
1540 
1541 /**
1542  * Construct a MIME Description string for netscape so that mozilla shall know
1543  * when to call us back.
1544  *
1545  * @param[in] magic references for this particular plugin type
1546  *
1547  * @return Pointer to string containing mime decription for this plugin
1548  */
NP2_GetMIMEDescription(const char * magic)1549 const char * NP2_GetMIMEDescription(const char * magic)
1550 {
1551      char * fname;
1552      char * desc;
1553      bool update = false;
1554      bool dont_update = false;
1555      bool doesnt_exist = false;
1556      time_t ts_ftime;
1557 
1558      D("NP_GetMIMEDescription(%s)\n", magic);
1559 
1560      if(!chkValidLocalPluginDirs())
1561      {
1562           D("Local plugin dirs not valid");
1563           update = true;
1564      }
1565 
1566      /* Check the last time we updated the cache */
1567      ts_ftime = chkTimeToUpdate( &update, &dont_update);
1568 
1569      if(update && !dont_update)
1570      {
1571           mozplugger_update(&doesnt_exist);
1572           ts_ftime = time(NULL);
1573           dont_update = true;
1574           update = false;
1575      }
1576 
1577      fname = get_mimetypes_cfg_path(magic);
1578      desc = read_desc(fname, ts_ftime, &update, is_base_mozplugger(magic));
1579 
1580      if(update && !dont_update)
1581      {
1582           mozplugger_update(&doesnt_exist);
1583           ts_ftime = time(NULL);
1584           update = false;
1585 
1586           free(desc);
1587           desc = read_desc(fname, ts_ftime, &update, is_base_mozplugger(magic));
1588 
1589      }
1590      free(fname);
1591 
1592      if(!desc && update && !doesnt_exist && !haveError())
1593      {
1594           reportError(NULL, "Please close browser and run mozplugger-update");
1595      }
1596 
1597      if(haveError())
1598      {
1599           desc = realloc(desc, 512);
1600           snprintf(desc, 511, "dummy/dummy:*.dummy:%s", errMsg);
1601      }
1602      D("Getmimedescription done: %.100s ...\n", desc);
1603      return (const char *)desc;
1604 }
1605 
1606 /**
1607  * Is the plugin playing
1608  *
1609  * @return True if got property
1610  */
is_playing(NPP instance)1611 bool is_playing(NPP instance)
1612 {
1613      data_t * THIS = instance->pdata;
1614      if (THIS)
1615      {
1616           if((THIS->commsPipeFd >= 0) || (THIS->pid > -1))
1617           {
1618                int status;
1619                if(waitpid(THIS->pid, &status, WNOHANG) == 0)
1620                {
1621                     /* If no status available from child then child
1622                                   * must still be running!? */
1623                     return true;
1624                }
1625           }
1626      }
1627      return false;
1628 }
1629 
1630 /**
1631  * Get the name of the plugin
1632  *
1633  * @param[in] magic references for this particular plugin type
1634  */
getPluginName(const char * magic)1635 static const char * getPluginName(const char * magic)
1636 {
1637      if(!is_base_mozplugger(magic))
1638      {
1639           get_helper_paths(magic);
1640      }
1641      return g_pluginName;
1642 }
1643 
1644 /**
1645  * Get plugin Description
1646  *
1647  * @param[in] magic references for this particular plugin type
1648  *
1649  * @return Returns the Description of the plugin
1650  */
getPluginDescription(const char * magic)1651 static const char * getPluginDescription(const char * magic)
1652 {
1653      static char desc_buffer[8192];
1654      const char * dbgPath = get_debug_path();
1655      char * config_fname = get_cmds_cfg_path(magic);
1656      struct stat details;
1657 
1658      if(is_base_mozplugger(magic) || (!config_fname) || (stat(config_fname, &details) != 0))
1659      {
1660           snprintf(desc_buffer, sizeof(desc_buffer),
1661 		   "MozPlugger version " VERSION
1662                    " Refresh required, please close browser and run mozplugger-update, "
1663 		   "for documentation on mozplugger see the man page."
1664                   );
1665      }
1666      else
1667      {
1668           const char * home = get_home_dir();
1669           char * pCfg = NULL;
1670           struct stat details;
1671           int i;
1672 
1673           details.st_mtime = 0;
1674           stat(config_fname, &details);
1675 
1676           /* removed cmds and replace with '*' */
1677           i = strlen(config_fname)-4;
1678           config_fname[i++] = '*';
1679           config_fname[i] = '\0';
1680 
1681           /* Hide the user's name!? */
1682           i = strlen(home);
1683           if(strncmp(home, config_fname, i) == 0)
1684           {
1685                pCfg = &config_fname[i-1];
1686                *pCfg = '~';
1687           }
1688           else
1689           {
1690                pCfg = config_fname;
1691           }
1692 
1693           snprintf(desc_buffer, sizeof(desc_buffer),
1694 		   "MozPlugger version "
1695 		   VERSION
1696 #ifdef GCOV
1697                    "(gcov)"
1698 #endif
1699 		   ", for documentation on mozplugger see the man page. "
1700 		   "<table>"
1701 		   "<tr><td>Cached config files:</td><td>%s</td><td>%s</td></tr>"
1702                    "%s%s%s"
1703 		   " </table>"
1704 		   "<br clear=all>",
1705                    pCfg, asctime(localtime(&details.st_mtime)),
1706                    dbgPath ? "<tr><td>Debug file:</td><td>" : "",
1707                    dbgPath ? dbgPath : "",
1708                    dbgPath ? "/" DEBUG_FILENAME "</td><td></td></tr>" : ""
1709                   );
1710      }
1711      free(config_fname);
1712      return (const char *)desc_buffer;
1713 }
1714 
1715 /**
1716  * Get plugin needs Xembed
1717  *
1718  * @return Returns True if Xembed required
1719  */
getPluginNeedsXembed(NPP instance,NPError * pErr)1720 static NPBool getPluginNeedsXembed(NPP instance, NPError *pErr)
1721 {
1722      NPBool retVal = 0;
1723 
1724      if (instance == NULL)
1725      {
1726           *pErr = NPERR_GENERIC_ERROR;
1727      }
1728      else
1729      {
1730           data_t * this = instance->pdata;
1731           if((this == NULL) || (this->command == NULL))
1732           {
1733                *pErr = NPERR_GENERIC_ERROR;
1734           }
1735 
1736           else if( ((this->command->flags & H_NEEDS_XEMBED) != 0)
1737                                               && does_browser_support_xembed())
1738           {
1739                D("Plugin needs XEmbed\n");
1740                retVal = 1;
1741           }
1742           else
1743           {
1744                D("Plugin does not need XEmbed\n");
1745           }
1746      }
1747      return retVal;
1748 }
1749 
1750 /**
1751  * Let Mozilla know things about mozplugger. This one is called without an
1752  * instance pointer when loading the plugin.
1753  *
1754  * @param[in] magic references for this particular plugin type
1755  * @param[in] variable Name of variable to get (enum)
1756  * @param[out] value The value got
1757  *
1758  * @return Returns error code if problem
1759  */
NP2_GetValue(const char * magic,NPPVariable variable,void * value)1760 NPError NP2_GetValue(const char * magic, NPPVariable variable, void *value)
1761 {
1762      NPError err = NPERR_NO_ERROR;
1763 
1764      D("NP_GetValue(%.20s, %s)\n", magic, NPPVariableToString(variable));
1765 
1766      switch (variable)
1767      {
1768      case NPPVpluginNameString:
1769 	  *((const char **)value) = getPluginName(magic);
1770 	  break;
1771 
1772      case NPPVpluginDescriptionString:
1773 	  *((const char **)value) = getPluginDescription(magic);
1774 	  break;
1775 
1776      default:
1777 	  D("NP_GetValue('%s' - %d) not implemented\n",
1778                                       NPPVariableToString(variable), variable);
1779 	  err = NPERR_GENERIC_ERROR;
1780           break;
1781      }
1782      return err;
1783 }
1784 
1785 /**
1786  * Let Mozilla know things about this instance.
1787  *
1788  * @param[in] instance Pointer to plugin instance data
1789  * @param[in] variable Name of variable to get (enum)
1790  * @param[out] value The value got
1791  *
1792  * @return Returns error code if problem
1793  */
NPP_GetValue(NPP instance,NPPVariable variable,void * value)1794 NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
1795 {
1796      NPError err = NPERR_NO_ERROR;
1797 
1798      D("NPP_GetValue(%s)\n", NPPVariableToString(variable));
1799 
1800      switch (variable)
1801      {
1802      case NPPVpluginDescriptionString:
1803 	  *((const char **)value) = getPluginDescription("");
1804 	  break;
1805 
1806      case NPPVpluginNeedsXEmbed:
1807 #ifdef ALWAYS_NEEDS_XEMBED
1808           /* For Chromium always return 1 */
1809           *((NPBool *)value) = 1;
1810 #else
1811           *((NPBool *)value) = getPluginNeedsXembed(instance, &err);
1812 #endif
1813           break;
1814 
1815      case NPPVpluginScriptableNPObject :
1816           *((NPObject **)value) = getPluginScritableObject(instance, &err);
1817           break;
1818 
1819      default :
1820 	  D("NPP_GetValue('%s' - %d) not implemented\n",
1821                                       NPPVariableToString(variable), variable);
1822 	  err = NPERR_GENERIC_ERROR;
1823           break;
1824      }
1825      return err;
1826 }
1827 
1828 /**
1829  * Let Mozilla set things on mozplugger.
1830  *
1831  * @param[in] instance Pointer to plugin instance data
1832  * @param[in] variable Name of variable to get (enum)
1833  * @param[in] value The value to set
1834  *
1835  * @return Returns error code if problem
1836  */
NPP_SetValue(NPP instance,NPNVariable variable,void * value)1837 NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
1838 {
1839      NPError err = NPERR_NO_ERROR;
1840 
1841      switch (variable)
1842      {
1843      default:
1844           D("NPP_SetValue( %d)  not implemented\n", variable);
1845 	  err = NPERR_GENERIC_ERROR;
1846           break;
1847      }
1848      return err;
1849 }
1850 
1851 
1852 /**
1853  * Convert a string to an integer.
1854  * The string can be true, false, yes or no.
1855  *
1856  * @param[in] s String to convert
1857  * @param[in] my_true The value associated with true
1858  * @param[in] my_false The value associated with false
1859  *
1860  * @return The value
1861  */
my_atoi(const char * s,int my_true,int my_false)1862 static int my_atoi(const char *s, int my_true, int my_false)
1863 {
1864      switch (s[0])
1865      {
1866      case 't': case 'T': case 'y': case 'Y':
1867 	  return my_true;
1868      case 'f': case 'F': case 'n': case 'N':
1869 	  return my_false;
1870      case '0': case '1': case '2': case '3': case '4':
1871      case '5': case '6': case '7': case '8': case '9':
1872 	  return atoi(s);
1873      }
1874      return -1;
1875 }
1876 
1877 /**
1878  * Initialize another instance of mozplugger. It is important to know
1879  * that there might be several instances going at one time.
1880  *
1881  * @param[in] pluginType Type of embedded object (mime type)
1882  * @param[in] instance Pointer to plugin instance data
1883  * @param[in] mode Embedded or not
1884  * @param[in] argc The number of associated tag attributes
1885  * @param[in] argn Array of attribute names
1886  * @param[in] argv Array of attribute values#
1887  * @param[in] saved Pointer to any previously saved data
1888  *
1889  * @return Returns error code if problem
1890  */
NPP_New(NPMIMEType pluginType,NPP instance,uint16_t mode,int16_t argc,char * argn[],char * argv[],NPSavedData * saved)1891 NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode,
1892 		int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
1893 {
1894      int e;
1895 
1896      int src_idx = -1;
1897      int href_idx = -1;
1898      int data_idx = -1;
1899      int alt_idx = -1;
1900      int autostart_idx = -1;
1901      int autohref_idx = -1;
1902      int target_idx = -1;
1903      data_t * THIS;
1904 
1905      char *url = NULL;
1906 
1907      D("NPP_New(%s) - instance=%p\n", pluginType, instance);
1908 
1909      if (!instance)
1910      {
1911 	  return NPERR_INVALID_INSTANCE_ERROR;
1912      }
1913 
1914      if (!pluginType)
1915      {
1916 	  return NPERR_INVALID_INSTANCE_ERROR;
1917      }
1918 
1919      THIS = NPN_MemAlloc(sizeof(data_t));
1920      if (THIS == NULL)
1921      {
1922           return NPERR_OUT_OF_MEMORY_ERROR;
1923      }
1924      instance->pdata = THIS;
1925 
1926      memset((void *)THIS, 0, sizeof(data_t));
1927 
1928      /* Only initialise the non-zero fields */
1929      THIS->pid = -1;
1930      THIS->commsPipeFd = -1;
1931      THIS->repeats = 1;
1932      THIS->autostart = 1;
1933      THIS->autostartNotSeen = 1;
1934      THIS->tmpFileFd = -1;
1935 
1936      if(mode == NP_EMBED)
1937      {
1938          THIS->mode_flags = H_EMBED;
1939      }
1940      else
1941      {
1942          THIS->mode_flags = H_NOEMBED;
1943      }
1944 
1945      if (!(THIS->mimetype = NP_strdup(pluginType)))
1946      {
1947 	  return NPERR_OUT_OF_MEMORY_ERROR;
1948      }
1949 
1950      THIS->num_arguments = argc;
1951      if(argc == 0)
1952      {
1953         return NPERR_NO_ERROR;
1954      }
1955 
1956      if (!(THIS->args = (argument_t *)NPN_MemAlloc(
1957                                           (uint32_t)(sizeof(argument_t) * argc))))
1958      {
1959 	  return NPERR_OUT_OF_MEMORY_ERROR;
1960      }
1961 
1962      for (e = 0; e < argc; e++)
1963      {
1964 	  if (strcasecmp("loop", argn[e]) == 0)
1965 	  {
1966 	       THIS->repeats = my_atoi(argv[e], INF_LOOPS, 1);
1967 	  }
1968           /* realplayer also uses numloop tag */
1969           /* windows media player uses playcount */
1970           else if((strcasecmp("numloop", argn[e]) == 0) ||
1971                   (strcasecmp("playcount", argn[e]) == 0))
1972           {
1973 	       THIS->repeats = atoi(argv[e]);
1974           }
1975 	  else if((strcasecmp("autostart", argn[e]) == 0) ||
1976 	          (strcasecmp("autoplay", argn[e]) == 0))
1977 	  {
1978                autostart_idx = e;
1979 	  }
1980 	  /* get the index of the src attribute if this is a 'embed' tag */
1981 	  else if (strcasecmp("src", argn[e]) == 0)
1982 	  {
1983 	       src_idx = e;
1984 	  }
1985 	  /* get the index of the data attribute if this is a 'object' tag */
1986           else if (strcasecmp("data", argn[e]) == 0)
1987           {
1988                data_idx = e;
1989           }
1990           /* Special case for quicktime. If there's an href or qtsrc attribute,
1991            * remember it for now */
1992           else if((strcasecmp("href", argn[e]) == 0) ||
1993 	            (strcasecmp("qtsrc", argn[e]) == 0))
1994           {
1995                if(href_idx == -1)
1996                {
1997                     href_idx = e;
1998                }
1999           }
2000           else if((strcasecmp("filename", argn[e]) == 0) ||
2001 	            (strcasecmp("url", argn[e]) == 0) ||
2002 	            (strcasecmp("location", argn[e]) == 0))
2003           {
2004                if(alt_idx == -1)
2005                {
2006                     alt_idx = e;
2007                }
2008           }
2009           /* Special case for quicktime. If there's an autohref or target
2010            * attributes remember them for now */
2011           else if (strcasecmp("target", argn[e]) == 0)
2012           {
2013                target_idx = e;
2014           }
2015 	  else if(strcasecmp("autohref", argn[e]) == 0)
2016 	  {
2017                autohref_idx = e;
2018 	  }
2019 
2020 	  /* copy the flag to put it into the environment later */
2021 	  D("VAR_%s=%s\n", argn[e], argv[e]);
2022           {
2023                const int len = strlen(argn[e]) + 5;
2024 
2025     	       if (!(THIS->args[e].name = (char *)NPN_MemAlloc(len)))
2026                {
2027 	            return NPERR_OUT_OF_MEMORY_ERROR;
2028                }
2029 	       snprintf(THIS->args[e].name, len, "VAR_%s", argn[e]);
2030  	       THIS->args[e].value = argv[e] ? NP_strdup(argv[e]) : NULL;
2031           }
2032      }
2033 
2034      if (src_idx >= 0)
2035      {
2036           url = THIS->args[src_idx].value;
2037           /* Special case for quicktime. If there's an href or qtsrc
2038            * attribute, we want that instead of src but we HAVE to
2039            * have a src first. */
2040           if (href_idx >= 0)
2041           {
2042 	       D("Special case QT detected\n");
2043 	       THIS->href = THIS->args[href_idx].value;
2044 
2045                autostart_idx = autohref_idx;
2046 
2047                if(target_idx >= 0)
2048                {
2049                    /* One of those clickable Quicktime linking objects! */
2050                    THIS->mode_flags &= ~(H_EMBED | H_NOEMBED);
2051                    THIS->mode_flags |= H_LINKS;
2052                }
2053           }
2054      }
2055      else if (data_idx >= 0)
2056      {
2057           D("Looks like an object tag with data attribute\n");
2058           url = THIS->args[data_idx].value;
2059      }
2060      else if (alt_idx >= 0)
2061      {
2062           D("Fall-back use alternative tags\n");
2063           url = THIS->args[alt_idx].value;
2064      }
2065 
2066      /* Do the autostart check here, AFTER we have processed the QT special
2067       * case which can change the autostart attribute */
2068      if(autostart_idx > 0)
2069      {
2070 	  THIS->autostart = !!my_atoi(argv[autostart_idx], 1, 0);
2071 	  THIS->autostartNotSeen = 0;
2072      }
2073 
2074      if (url)
2075      {
2076           THIS->url = url;
2077 
2078           /* Mozilla does not support the following protocols directly and
2079            * so it never calls NPP_NewStream for these protocols */
2080 	  if(   (strncmp(url, "mms://", 6) == 0)
2081              || (strncmp(url, "mmsu://", 7) == 0)    /* MMS over UDP */
2082              || (strncmp(url, "mmst://", 7) == 0)    /* MMS over TCP */
2083              || (strncmp(url, "rtsp://", 7) == 0)
2084              || (strncmp(url, "rtspu://", 8) == 0)   /* RTSP over UDP */
2085              || (strncmp(url, "rtspt://", 8) == 0))  /* RTSP over TCP */
2086 	  {
2087 	       D("Detected MMS -> url=%s\n", url);
2088 
2089                THIS->browserCantHandleIt = true;
2090                THIS->command = find_command(THIS,1); /* Needs to be done early! so xembed
2091                                                          flag is correctly set*/
2092 
2093 
2094                /* The next call from browser will be NPP_SetWindow() &
2095                 * NPP_NewStream will never be called */
2096 	  }
2097           else
2098           {
2099                THIS->command = find_command(THIS,0); /* Needs to be done early so xembed
2100                                                        flag is correctly set*/
2101 
2102                /* For protocols that Mozilla does support, sometimes
2103                 * the browser will call NPP_NewStream straight away, some
2104                 * times it wont (depends on the nature of the tag). So that
2105                 * it works in all cases call NPP_GetURL, this may result
2106                 * in NPP_NewStream() being called twice (i.e. if this is an
2107                 * embed tag with src attribute or object tag with data
2108                 * attribute) */
2109                if (mode == NP_EMBED)
2110                {
2111                     const NPError retVal = NPN_GetURL(instance, url, 0);
2112                     if(retVal != NPERR_NO_ERROR)
2113                     {
2114                          D("NPN_GetURL(%s) failed with %i\n", url, retVal);
2115 
2116 	                 fprintf(stderr, "MozPlugger: Warning: Couldn't get"
2117                                  "%s\n", url);
2118                          return NPERR_GENERIC_ERROR;
2119                     }
2120                }
2121           }
2122      }
2123 
2124      D("New finished\n");
2125 
2126      return NPERR_NO_ERROR;
2127 }
2128 
2129 /**
2130  * Send the SHUTDOWN_MSG to the child process
2131  *
2132  * @param[in] pipeFd The pipe fd
2133  * @param[in] pip The process ID
2134  *
2135  */
sendShutdownMsg(int pipeFd,pid_t pid)2136 void sendShutdownMsg(int pipeFd, pid_t pid)
2137 {
2138      if(pipeFd >= 0)
2139      {
2140           PipeMsg_t msg;
2141           ssize_t ret;
2142 
2143           msg.msgType = SHUTDOWN_MSG;
2144 
2145           D("Writing SHUTDOWN_MSG to fd %d\n", pipeFd);
2146           ret = write(pipeFd, (char *) &msg, sizeof(msg));
2147           if(ret == sizeof(msg))
2148           {
2149                if(pid >= 0)
2150                {
2151                     int i;
2152                     for(i = 0; i < 5; i++)
2153                     {
2154                          int status;
2155                          if(waitpid(pid, &status, WNOHANG) != 0)
2156                          {
2157                               pid = 0;
2158                               break;
2159                          }
2160                          usleep(100000);
2161                      }
2162                }
2163           }
2164           else
2165           {
2166                D("Writing to comms pipe failed\n");
2167           }
2168           close(pipeFd); /* this will cause a broken pipe in the helper! */
2169      }
2170 
2171      /* By this point the child should be dead, but just in case...*/
2172      if(pid > 0)
2173      {
2174           int status;
2175           if(kill(pid, SIGTERM) == 0)
2176           {
2177                usleep(100000);
2178                kill(pid, SIGKILL);
2179           }
2180           waitpid(pid, &status, 0);
2181      }
2182 }
2183 
2184 
2185 /**
2186  * Free data, kill processes, it is time for this instance to die.
2187  *
2188  * @param[in] instance Pointer to the plugin instance data
2189  * @param[out] save Pointer to any data to be saved (none in this case)
2190  *
2191  * @return Returns error code if a problem
2192  */
NPP_Destroy(NPP instance,NPSavedData ** save)2193 NPError NPP_Destroy(NPP instance, NPSavedData** save)
2194 {
2195      data_t * THIS;
2196 
2197      D("NPP_Destroy(%p)\n", instance);
2198 
2199      if (!instance)
2200      {
2201 	  return NPERR_INVALID_INSTANCE_ERROR;
2202      }
2203 
2204      THIS = instance->pdata;
2205      if (THIS)
2206      {
2207           sendShutdownMsg(THIS->commsPipeFd, THIS->pid);
2208           if(THIS->tmpFileFd >= 0)
2209           {
2210                close(THIS->tmpFileFd);
2211           }
2212           if(THIS->tmpFileName != 0)
2213           {
2214                char * p;
2215                D("Deleting temp file '%s'\n", THIS->tmpFileName);
2216 
2217                chmod(THIS->tmpFileName, 0600);
2218                unlink(THIS->tmpFileName);
2219                p = strrchr(THIS->tmpFileName, '/');
2220                if(p)
2221                {
2222                     *p = '\0';
2223                     D("Deleting temp dir '%s'\n", THIS->tmpFileName);
2224                     rmdir(THIS->tmpFileName);
2225                }
2226                NPN_MemFree((char *)THIS->tmpFileName);
2227           }
2228           if(THIS->args)
2229           {
2230                int e;
2231 	       for (e = 0; e < THIS->num_arguments; e++)
2232 	       {
2233 	            NPN_MemFree((char *)THIS->args[e].name);
2234 	            NPN_MemFree((char *)THIS->args[e].value);
2235 	       }
2236 	       NPN_MemFree((char *)THIS->args);
2237           }
2238 
2239           if(THIS->mimetype)
2240           {
2241 	       NPN_MemFree(THIS->mimetype);
2242           }
2243 
2244           if(THIS->urlFragment)
2245           {
2246                NPN_MemFree(THIS->urlFragment);
2247           }
2248 
2249 	  NPN_MemFree(instance->pdata);
2250 	  instance->pdata = NULL;
2251      }
2252 
2253      D("Destroy finished\n");
2254 
2255      return NPERR_NO_ERROR;
2256 }
2257 
2258 /**
2259  * Check that no child is already running before forking one.
2260  *
2261  * @param[in] instance Pointer to the plugin instance data
2262  * @param[in] fname The filename of the embedded object
2263  * @param[in] isURL Is the filename a URL?
2264  *
2265  * @return Nothing
2266  */
new_child(NPP instance,const char * fname,int isURL)2267 static void new_child(NPP instance, const char* fname, int isURL)
2268 {
2269      int commsPipe[2];
2270      data_t * THIS;
2271      sigset_t set;
2272      sigset_t oset;
2273 
2274      D("NEW_CHILD(%s)\n", fname ? fname : "NULL");
2275 
2276      if(fname == NULL)
2277      {
2278           return;
2279      }
2280 
2281      THIS = instance->pdata;
2282 
2283      if (THIS->pid != -1)
2284      {
2285           D("Child already running\n");
2286 	  return;
2287      }
2288 
2289      /* Guard against spawning helper if no command! */
2290      if(THIS->command == 0)
2291      {
2292           D("Child has no command\n");
2293           return;
2294      }
2295 
2296      if(!safeName(fname, isURL)
2297              || (THIS->urlFragment && !safeName(THIS->urlFragment, 0)))
2298      {
2299 	  reportError(instance, "MozPlugger: Detected unsafe URL aborting!");
2300 	  return;
2301      }
2302 
2303      if (socketpair(AF_UNIX, SOCK_STREAM, 0, commsPipe) < 0)
2304      {
2305 	  reportError(instance, "MozPlugger: Failed to create a pipe!");
2306 	  return;
2307      }
2308 
2309      /* Mask all the signals to avoid being interrupted by a signal */
2310      sigfillset(&set);
2311      sigprocmask(SIG_SETMASK, &set, &oset);
2312 
2313      D(">>>>>>>>Forking<<<<<<<<\n");
2314 
2315      THIS->pid = fork();
2316      if(THIS->pid == 0)
2317      {
2318           int signum;
2319           int i;
2320           int maxFds;
2321           const int commsFd = commsPipe[1];
2322 
2323 	  alarm(0);
2324 
2325 	  for (signum=0; signum < NSIG; signum++)
2326           {
2327 	       signal(signum, SIG_DFL);
2328           }
2329 
2330 	  close_debug();
2331 
2332   /* Close all those File descriptors inherited from the
2333    * parent, except the pipes and stdin, stdout, stderr */
2334 
2335           maxFds = sysconf(_SC_OPEN_MAX);
2336           for(i = 3; i < maxFds; i++)
2337           {
2338               if(i != commsFd)
2339               {
2340                    close(i);
2341               }
2342           }
2343           D("Closed up to %i Fds, except %i\n", maxFds, commsFd);
2344 
2345           /* Restore the signal mask */
2346           sigprocmask(SIG_SETMASK, &oset, &set);
2347 
2348 	  run(THIS, fname, commsFd);
2349 
2350 	  _exit(EX_UNAVAILABLE); /* Child exit, that's OK */
2351      }
2352 
2353      /* Restore the signal mask */
2354      sigprocmask(SIG_SETMASK, &oset, &set);
2355 
2356      if(THIS->pid == -1)
2357      {
2358 	  reportError(instance, "MozPlugger: Failed to fork helper!");
2359      }
2360 
2361      D("Child running with pid=%d\n", THIS->pid);
2362 
2363      THIS->commsPipeFd = commsPipe[0];
2364      close(commsPipe[1]);
2365 }
2366 
2367 /**
2368  * Whilst creating a pdf watch out for characters that may
2369  * cause issues...
2370  *
2371  * @param[in,out] string the string to be escaped
2372  */
escapeBadChars(char * string)2373 static void escapeBadChars(char * string)
2374 {
2375      for(;*string; string++)
2376      {
2377           char ch = *string;
2378           if((ch == ';') || (ch == '`') || (ch == '&') ||
2379                                       (ch == ' ') || (ch == '\t'))
2380           {
2381                *string = '_';
2382           }
2383      }
2384 }
2385 
2386 /**
2387  * Guess a temporary file name
2388  *
2389  * Creates a temporary file name based on the fileName provided. Checks that
2390  * the filename created does not include any dangereous or awkward characters.
2391  *
2392  * @param[in] fileName Pointer to url string
2393  *
2394  * @return file descriptor
2395  */
guessTmpFile(const char * fileName,int soFar,char * tmpFilePath,int maxTmpFilePathLen)2396 static int guessTmpFile(const char * fileName, int soFar,
2397                                      char * tmpFilePath, int maxTmpFilePathLen)
2398 {
2399      int i = 0;
2400      int fd = -1;
2401      int spaceLeft = maxTmpFilePathLen - soFar - 1;
2402      const int maxNameLen = pathconf(tmpFilePath, _PC_NAME_MAX);
2403      const int fileNameLen = strlen(fileName);
2404 
2405      if(spaceLeft > maxNameLen)
2406      {
2407          spaceLeft = maxNameLen;
2408      }
2409      tmpFilePath[soFar++] = '/';
2410 
2411      while(1)
2412      {
2413           if(i < 100)
2414 	  {
2415                int n = 0;
2416                int pos = 0;
2417                if(i > 0)
2418                {
2419 	            n = snprintf(&tmpFilePath[soFar], spaceLeft, "%03i-", i);
2420                }
2421 	       if(fileNameLen > (spaceLeft-n))
2422                {
2423                     pos = fileNameLen - (spaceLeft-n);
2424                }
2425 	       strcpy(&tmpFilePath[soFar+n], &fileName[pos]);
2426           }
2427 	  else
2428 	  {
2429                strncpy(&tmpFilePath[soFar], "XXXXXX", spaceLeft);
2430                fd = mkstemp(tmpFilePath);
2431 	       break;
2432 	  }
2433 
2434           escapeBadChars(&tmpFilePath[soFar]);
2435 
2436 	  fd = open(tmpFilePath, O_CREAT | O_EXCL | O_WRONLY,
2437 			  S_IRUSR | S_IWUSR);
2438 	  if(fd >= 0)
2439 	  {
2440 	       break;
2441 	  }
2442           i++;
2443      }
2444 
2445      return fd;
2446 }
2447 
2448 /**
2449  * From the url create a temporary file to hold a copy of th URL contents.
2450  *
2451  * @param[in] fileName Pointer to url string
2452  * @param[out] tmpFileName Pointer to place tmp file name string
2453  * @param[in] maxTmpFileLen
2454  *
2455  * @return -1 on error or file descriptor
2456  */
createTmpFile(char ** pFileName)2457 static int createTmpFile(char ** pFileName)
2458 {
2459      char tmpFilePath[512];
2460      int fd = -1;
2461      const char * root;
2462      const pid_t pid = getpid();
2463 
2464      D("Creating temp file for '%s'\n", *pFileName);
2465 
2466      root = getenv("MOZPLUGGER_TMP");
2467      if(root)
2468      {
2469           int soFar;
2470 
2471           strncpy(tmpFilePath, root, sizeof(tmpFilePath)-1);
2472           soFar = strlen(tmpFilePath);
2473 
2474 	  soFar += snprintf(&tmpFilePath[soFar], sizeof(tmpFilePath)-soFar,
2475                                                                 "/tmp-%i", pid);
2476           if( (mkdir(tmpFilePath, S_IRWXU) == 0) || (errno == EEXIST))
2477           {
2478                D("Creating temp file in '%s'\n", tmpFilePath);
2479 
2480 	       fd = guessTmpFile(*pFileName, soFar, tmpFilePath, sizeof(tmpFilePath)-1);
2481           }
2482      }
2483 
2484      if(fd < 0)
2485      {
2486           root = getenv("TMPDIR");
2487           if(!root)
2488           {
2489                root = "/tmp";
2490           }
2491 
2492           snprintf(tmpFilePath, sizeof(tmpFilePath), "%s/mozplugger-%i",
2493                                                                      root, pid);
2494           if((mkdir(tmpFilePath, S_IRWXU) == 0) || (errno == EEXIST))
2495           {
2496                int soFar = strlen(tmpFilePath);
2497 
2498                D("Creating temp file in '%s'\n", tmpFilePath);
2499 
2500 	       fd = guessTmpFile(*pFileName, soFar, tmpFilePath, sizeof(tmpFilePath)-1);
2501           }
2502      }
2503      NPN_MemFree(*pFileName);
2504 
2505      if(fd >= 0)
2506      {
2507           D("Opened temporary file '%s'\n", tmpFilePath);
2508           *pFileName = NP_strdup(tmpFilePath);
2509      }
2510      else
2511      {
2512           *pFileName = NULL;
2513      }
2514      return fd;
2515 }
2516 
2517 /**
2518  * Open a new stream.
2519  * Each instance can only handle one stream at a time.
2520  *
2521  * @param[in] instance Pointer to the plugin instance data
2522  * @param[in] type The mime type
2523  * @param[in] stream Pointer to the stream data structure
2524  * @param[in] seekable Flag to say if stream is seekable
2525  * @param[out] stype How the plugin will handle the stream
2526  *
2527  * @return Returns error code if a problem
2528  */
NPP_NewStream(NPP instance,NPMIMEType type,NPStream * stream,NPBool seekable,uint16_t * stype)2529 NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream,
2530 		      NPBool seekable, uint16_t *stype)
2531 {
2532      char * fileName = NULL;
2533      char * savedMimetype = NULL;
2534      data_t * THIS;
2535      char refind_command = 0;
2536 
2537      D("NPP_NewStream(%p)\n", instance);
2538 
2539      if (instance == NULL)
2540      {
2541 	  return NPERR_INVALID_INSTANCE_ERROR;
2542      }
2543 
2544      THIS = instance->pdata;
2545 
2546      /* Looks like browser can handle this stream so we can clear the flag */
2547      THIS->browserCantHandleIt = 0;
2548 
2549      if((THIS->pid != -1) || (THIS->tmpFileFd >= 0))
2550      {
2551           D("NewStream() exiting process already running\n");
2552 	  return NPERR_GENERIC_ERROR;
2553      }
2554 
2555      /*  Replace the stream's URL with the URL in THIS->href if it
2556       *  exists. */
2557      if(THIS->href != NULL)
2558      {
2559 	  D("Replacing SRC with HREF... \n");
2560 
2561           if((THIS->url == 0) || (strcmp(THIS->href, THIS->url) != 0))
2562           {
2563                /* URL has changed */
2564                D("URL has changed to %s\n", THIS->href);
2565                THIS->url = THIS->href;
2566                refind_command = 1;
2567           }
2568      }
2569      else if((THIS->url == 0) || (strcmp(stream->url, THIS->url) != 0))
2570      {
2571           /* URL has changed */
2572           D("URL has changed to %s\n", stream->url);
2573           THIS->url = (char *) stream->url;
2574           refind_command = 1;
2575      }
2576 
2577      D("Url is %s (seekable=%d)\n", THIS->url, seekable);
2578 
2579      /* Ocassionally the MIME type here is different to that passed to the
2580       * NEW function - this is because of either badly configure web server
2581       * who's HTTP response content-type does not match the mimetype in the
2582       * preceding embebbed, object or link tag. Or badly constructed embedded
2583       * tag or ambiguity in the file extension to mime type mapping. Lets
2584       * first assume the HTTP response was correct and if not fall back to
2585       * the original tag in the mime type. */
2586      if(strcmp(type, THIS->mimetype) != 0)
2587      {
2588           D("Mismatching mimetype reported, originally was \'%s\' now '\%s' "
2589                           "for url %s\n", THIS->mimetype, type, THIS->url);
2590           savedMimetype = THIS->mimetype;
2591           THIS->mimetype = NP_strdup(type);
2592 
2593           if(!(THIS->command = find_command(THIS, 0)))
2594           {
2595                NPN_MemFree(THIS->mimetype);
2596                THIS->mimetype = savedMimetype;
2597                THIS->command = find_command(THIS, 0);
2598           }
2599           else
2600           {
2601                NPN_MemFree(savedMimetype);
2602           }
2603      }
2604      else if(refind_command)
2605      {
2606           THIS->command = find_command(THIS, 0);
2607           D("Mime type %s\n", type);
2608      }
2609 
2610      if(THIS->command == 0)
2611      {
2612 	  reportError(instance, "MozPlugger: No appropriate application found.");
2613 	  return NPERR_GENERIC_ERROR;
2614      }
2615 
2616      /* Extract from the URL the various additional information */
2617      fileName = parseURL(THIS, 1);
2618      D("fileName (pre-header parse) = %s\n", fileName);
2619 
2620      /* Extract the fileName from HTTP headers, overide URL fileName */
2621      fileName = parseHeaders(THIS, stream->headers, fileName);
2622      D("fileName = %s\n", fileName);
2623 
2624      if( (THIS->command->flags & H_STREAM) == 0)
2625      {
2626           THIS->tmpFileFd = createTmpFile(&fileName);
2627 
2628           if(THIS->tmpFileFd < 0)
2629           {
2630 	       reportError(instance, "MozPlugger: Failed to create tmp file");
2631 	       return NPERR_GENERIC_ERROR;
2632           }
2633           else
2634           {
2635                /* Make file read only by us only */
2636                fchmod(THIS->tmpFileFd, 0400);
2637                THIS->tmpFileName = fileName;
2638                THIS->tmpFileSize = 0;
2639           }
2640      }
2641      else
2642      {
2643           NPN_MemFree(fileName);
2644           new_child(instance, THIS->url, 1);
2645      }
2646 
2647      *stype = NP_NORMAL;
2648      return NPERR_NO_ERROR;
2649 }
2650 
2651 /**
2652  * Called after NPP_NewStream if *stype = NP_ASFILEONLY.
2653  *
2654  * @param[in] instance Pointer to plugin instance data
2655  * @param[in] stream Pointer to the stream data structure
2656  * @param[in] fname Name of the file to stream
2657  *
2658  * @return none
2659  */
NPP_StreamAsFile(NPP instance,NPStream * stream,const char * fname)2660 void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
2661 {
2662      D("NPP_StreamAsFile(%p, %p, %s)\n", instance, stream, fname);
2663 
2664      if (instance != NULL)
2665      {
2666           new_child(instance, fname, 0);
2667      }
2668 }
2669 
2670 /**
2671  * The browser should have resized the window for us, but this function was
2672  * added because of a bug in Mozilla 1.7 (see Mozdev bug #7734) and
2673  * https://bugzilla.mozilla.org/show_bug.cgi?id=201158
2674  *
2675  * Bug was fixed in Mozilla CVS repositary in version 1.115 of
2676  * ns4xPluginInstance.cpp (13 Nov 2003), at the time version was 0.13.
2677  * version 0.14 happened on 14th July 2004
2678  *
2679  * @param[in] dpy The display pointer
2680  * @param[in] win The window ID
2681  * @param[in] width The width of the window
2682  * @param[in] height The height of the window
2683  *
2684  * @return none
2685  */
resize_window(Display * dpy,Window win,unsigned width,unsigned height)2686 static void resize_window(Display * dpy, Window win, unsigned width, unsigned height)
2687 {
2688      if(does_browser_have_resize_bug() && ((unsigned)win != 0))
2689      {
2690           XSetWindowAttributes attrib;
2691 
2692           attrib.override_redirect = True;
2693           XChangeWindowAttributes(dpy, win, (unsigned long) CWOverrideRedirect, &attrib);
2694 
2695           D("Bug #7734 work around - resizing WIN 0x%x to %ux%u!?\n",
2696                 (unsigned) win, width, height);
2697 
2698           XResizeWindow(dpy, win, width, height);
2699      }
2700 }
2701 
2702 /**
2703  * Send the WINDOW_MSG to the child process
2704  *
2705  * @param[in] THIS The instance
2706  * @param[in] Window The window ID
2707  * @param[in] width The new window width
2708  * @param[in] height The new window height
2709  *
2710  */
sendWindowMsg(data_t * THIS)2711 void sendWindowMsg(data_t * THIS)
2712 {
2713      if(THIS->commsPipeFd >= 0)
2714      {
2715           PipeMsg_t msg;
2716           ssize_t ret;
2717 
2718           msg.msgType = WINDOW_MSG;
2719           msg.window_msg.window = THIS->window;
2720           msg.window_msg.width = THIS->width;
2721           msg.window_msg.height = THIS->height;
2722 
2723           D("Sending WIN MSG to helper (win=0x%x - %u x %u)\n",
2724                                   (unsigned) THIS->window, THIS->width, THIS->height);
2725 
2726           ret = write(THIS->commsPipeFd, (char *) &msg, sizeof(msg));
2727           if(ret < sizeof(msg))
2728           {
2729                D("Writing to comms pipe failed\n");
2730                close(THIS->commsPipeFd);
2731                THIS->commsPipeFd = -1;
2732           }
2733     }
2734 }
2735 
2736 
2737 /**
2738  * The browser calls NPP_SetWindow after creating the instance to allow drawing
2739  * to begin. Subsequent calls to NPP_SetWindow indicate changes in size or
2740  * position. If the window handle is set to null, the window is destroyed. In
2741  * this case, the plug-in must not perform any additional graphics operations
2742  * on the window and should free any associated resources.
2743  *
2744  * @param[in] instance Pointer to plugin instance data
2745  * @param[in] window Pointer to NPWindow data structure
2746  *
2747  * @return Returns error code if problem
2748  */
NPP_SetWindow(NPP instance,NPWindow * window)2749 NPError NPP_SetWindow(NPP instance, NPWindow* window)
2750 {
2751      data_t * THIS;
2752      D("NPP_SetWindow(%p)\n", instance);
2753 
2754      if(!instance)
2755      {
2756           D("NPP_SetWindow, ERROR NULL instance\n");
2757 	  return NPERR_INVALID_INSTANCE_ERROR;
2758      }
2759 
2760      if(!window)
2761      {
2762           D("NPP_SetWindow, WARN NULL window\n");
2763 	  return NPERR_NO_ERROR;
2764      }
2765 
2766      THIS = instance->pdata;
2767 
2768      if(!window->ws_info)
2769      {
2770           D("NPP_SetWindow, WARN NULL display\n");
2771 	  return NPERR_NO_ERROR;
2772      }
2773 
2774      if(!window->window)
2775      {
2776           D("NPP_SetWindow, WARN zero window ID\n");
2777      }
2778 
2779      THIS->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;
2780 
2781      THIS->window = (Window) window->window;
2782      THIS->width = window->width;
2783      THIS->height = window->height;
2784 
2785      if ((THIS->url) && (THIS->browserCantHandleIt))
2786      {
2787           if(THIS->command == 0)
2788           {
2789                /* Can only use streaming commands, as Mozilla cannot handle
2790                 * these types (mms) of urls */
2791                if (!(THIS->command = find_command(THIS, 1)))
2792                {
2793                     if(haveError())
2794                     {
2795                          NPN_Status(instance, errMsg);
2796                          clearError();
2797                     }
2798                     else
2799                     {
2800 	                 reportError(instance, "MozPlugger: No appropriate application found.");
2801                     }
2802  	            return NPERR_GENERIC_ERROR;
2803                }
2804           }
2805 
2806           /* Extract from the URL the various additional information */
2807           (void) parseURL(THIS, 0);
2808 
2809 	  new_child(instance, THIS->url, 1);
2810           THIS->url = NULL; /* Stops new_child from being called again */
2811 	  return NPERR_NO_ERROR;
2812      }
2813 
2814      sendWindowMsg(THIS);
2815 
2816      resize_window(THIS->display, THIS->window, THIS->width, THIS->height);
2817 
2818      /* In case Mozilla would call NPP_SetWindow() in a loop. */
2819      usleep(4000);
2820 
2821 //     get_browser_toolkit(instance);
2822 //     does_browser_support_key_handling(instance);
2823 
2824      return NPERR_NO_ERROR;
2825 }
2826 
2827 /**
2828  * Called from browser when there is an event to be passed to the plugin. Only applicabe for
2829  * windowless plugins
2830  *
2831  * @param[in] instance The instance pointer
2832  * @param[in] event The event
2833  *
2834  * @return ??
2835  */
NPP_HandleEvent(NPP instance,void * event)2836 int16_t NPP_HandleEvent(NPP instance, void* event)
2837 {
2838      D("NPP_HandleEvent(%p)\n", instance);
2839      return 0;
2840 }
2841 
2842 /**
2843  * Send progress message to helper
2844  */
sendProgressMsg(data_t * THIS)2845 static void sendProgressMsg(data_t * THIS)
2846 {
2847      if(THIS->commsPipeFd >= 0)
2848      {
2849           int ret;
2850           PipeMsg_t msg;
2851 
2852           msg.msgType = PROGRESS_MSG;
2853           msg.progress_msg.done = (THIS->tmpFileFd < 0);
2854           msg.progress_msg.bytes = THIS->tmpFileSize;
2855 
2856           ret = write(THIS->commsPipeFd, (char *) &msg, sizeof(msg));
2857           if(ret < sizeof(msg))
2858           {
2859                D("Writing to comms pipe failed\n");
2860                close(THIS->commsPipeFd);
2861                THIS->commsPipeFd = -1;
2862           }
2863      }
2864 }
2865 
2866 /**
2867  * Called from the Browser when the streaming has been completed by the Browser
2868  * (the reason code indicates whether this was due to a User action, Network
2869  * issue or that streaming has been done.
2870  *
2871  * @param[in] instance Pointer to plugin instance data
2872  * @param[in] stream Pointer to the stream data structure
2873  * @param[in] reason Reason for stream being destroyed
2874  *
2875  * @return Returns error code if a problem
2876  */
NPP_DestroyStream(NPP instance,NPStream * stream,NPError reason)2877 NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
2878 {
2879      data_t * THIS;
2880      D("NPP_DestroyStream(%p, %p, %i)\n", instance, stream, reason);
2881 
2882      if (!instance)
2883      {
2884           return NPERR_INVALID_INSTANCE_ERROR;
2885      }
2886 
2887      THIS = instance->pdata;
2888 
2889      if(THIS->tmpFileFd >= 0)
2890      {
2891           close(THIS->tmpFileFd);
2892           THIS->tmpFileFd = -1;
2893 
2894           if( THIS->tmpFileName != NULL)
2895           {
2896                D("Closing Temporary file \'%s\'\n", THIS->tmpFileName);
2897                if(THIS->commsPipeFd < 0)   /* is no helper? */
2898                {
2899                     new_child(instance, THIS->tmpFileName, 0);
2900                }
2901           }
2902 
2903           sendProgressMsg(THIS);
2904      }
2905      return NPERR_NO_ERROR;
2906 }
2907 
2908 /**
2909  * The browser calls this function only once; when the plug-in is loaded,
2910  * before the first instance is created. NPP_Initialize tells the plug-in that
2911  * the browser has loaded it.
2912  *
2913  * @param[in] magic references for this particular plugin type
2914  * @param[in] nsTable The table of NPN functions
2915  * @param[out] pluginFuncs On return contains the NPP functions
2916  *
2917  * @return Returns error code if a problem
2918  */
NP2_Initialize(const char * magic,const NPNetscapeFuncs * nsTable,NPPluginFuncs * pluginFuncs)2919 NPError NP2_Initialize(const char * magic,
2920                   const NPNetscapeFuncs * nsTable, NPPluginFuncs * pluginFuncs)
2921 {
2922      NPError err;
2923      D("NP_Initialize(%.20s)\n", magic);
2924 
2925      if( (err = NPN_InitFuncTable(nsTable)) == NPERR_NO_ERROR)
2926      {
2927           if( (err = NPP_InitFuncTable(pluginFuncs)) == NPERR_NO_ERROR)
2928           {
2929                 get_api_version();
2930 
2931                 if(!do_read_config(magic))
2932                 {
2933                      err = NPERR_GENERIC_ERROR;
2934                 }
2935                 else
2936                 {
2937                      const int free = MAX_STATIC_MEMORY_POOL - staticPoolIdx;
2938                      D("Static Pool used=%i, free=%i\n", staticPoolIdx, free);
2939                 }
2940           }
2941      }
2942      return err;
2943 }
2944 
2945 /**
2946  * The browser calls this function just before it unloads the plugin from
2947  * memory. So this function should do any tidy up - in this case nothing is
2948  * required.
2949  *
2950  * @param[in] magic references for this particular plugin type
2951  *
2952  * @return none
2953  */
NP2_Shutdown(const char * magic)2954 NPError NP2_Shutdown(const char * magic)
2955 {
2956      D("NP_Shutdown(%.20s)\n", magic);
2957      return NPERR_NO_ERROR;
2958 }
2959 
2960 /**
2961  * Called when user as requested to print the webpage that contains a visible
2962  * plug-in. For mozplugger this is ignored.
2963  *
2964  * @param[in] instance Pointer to the plugin instance data
2965  * @param[in] printInfo Pointer to the print info data structure
2966  *
2967  * @return none
2968  */
NPP_Print(NPP instance,NPPrint * printInfo)2969 void NPP_Print(NPP instance, NPPrint* printInfo)
2970 {
2971      D("NPP_Print(%p)\n", instance);
2972 }
2973 
2974 /**
2975  * Called when the Browser wishes to deliver a block of data from a stream to
2976  * the plugin. Since streaming is handled directly by the application specificed
2977  * in the configuration file, mozplugger has no need for this data. Here it
2978  * just pretends the data has been taken by returning 'len' to indicate all
2979  * bytes consumed. Actaully this function should never be called by the
2980  * Browser.
2981  *
2982  * @param[in] instance Pointer to the plugin instance data
2983  * @param[in] stream Pointer to the stream data structure
2984  * @param[in] offset Where the data starts in 'buf'
2985  * @param[in] len The amount of data
2986  * @param[in] buf The data to be delivered
2987  *
2988  * @return Always returns value of passed in 'len'
2989  */
NPP_Write(NPP instance,NPStream * stream,int32_t offset,int32_t len,void * buf)2990 int32_t NPP_Write(NPP instance, NPStream *stream, int32_t offset, int32_t len,
2991 		  void * buf)
2992 {
2993      D("NPP_Write(%p, %p, %d, %d)\n", instance, stream, offset, (int) len);
2994      if(instance)
2995      {
2996           data_t * const THIS = instance->pdata;
2997 
2998           if(THIS->tmpFileFd >= 0)   /* is tmp file open? */
2999           {
3000                if(offset != THIS->tmpFileSize)
3001                {
3002                    D("Strange, there's a gap?\n");
3003                }
3004                len = write(THIS->tmpFileFd, buf, len);
3005                THIS->tmpFileSize += len;
3006                D("Temporary file size now=%i\n", THIS->tmpFileSize);
3007           }
3008 
3009           sendProgressMsg(THIS);
3010      }
3011      return len;
3012 }
3013 
3014 /**
3015  * Browser calls this function before calling NPP_Write to see how much data
3016  * the plugin is ready to accept.
3017  *
3018  * @param[in] instance Pointer to the plugin instance data
3019  * @param[in] stream Pointer to the stream data structure
3020  *
3021  * @return CHUNK_SIZE or zero
3022  */
NPP_WriteReady(NPP instance,NPStream * stream)3023 int32_t NPP_WriteReady(NPP instance, NPStream *stream)
3024 {
3025      int32_t size = 0;
3026 
3027      D("NPP_WriteReady(%p, %p)\n", instance, stream);
3028      if (instance != 0)
3029      {
3030           data_t * const THIS = instance->pdata;
3031 
3032           if(THIS->tmpFileFd >= 0)  /* is tmp file is open? */
3033           {
3034                size = CHUNK_SIZE;
3035           }
3036           else
3037           {
3038                D("Nothing to do - Application will handle stream\n");
3039 	       /* Tell the browser that it can finish with the stream
3040    	          (actually we just wanted the name of the stream!)
3041 	          And not the stream data. */
3042                NPN_DestroyStream(instance, stream, NPRES_DONE);
3043           }
3044      }
3045      return size;
3046 }
3047 
3048 /**
3049  * Browser calls this function to notify when a GET or POST has completed
3050  * Currently not used by mozplugger
3051  *
3052  * @param[in] instance Pointer to the plugin instance data
3053  * @param[in] url The URL that was GET or POSTed
3054  * @param[in] reason The reason for the notify event
3055  * @param[in] notifyData Data that was passed in the original call to Get or Post URL
3056  *
3057  * @return none
3058  */
NPP_URLNotify(NPP instance,const char * url,NPReason reason,void * notifyData)3059 void NPP_URLNotify(NPP instance, const char * url, NPReason reason, void * notifyData)
3060 {
3061      D("NPP_URLNotify(%p, %s, %i)\n", instance, url, reason);
3062 }
3063 
3064 /**
3065  * Called by the browser when the browser intends to focus an instance.
3066  * Instance argument indicates the instance getting focus.
3067  * Direction argument indicates the direction in which focus advanced to the instance.
3068  * Return value indicates whether or not the plugin accepts focus.
3069  * Currently not used by mozplugger
3070  *
3071  * @param[in] instance Pointer to the plugin instance data
3072  * @param[in] direction The advancement direction
3073  *
3074  * @return True or False
3075  */
NPP_GotFocus(NPP instance,NPFocusDirection direction)3076 NPBool NPP_GotFocus(NPP instance, NPFocusDirection direction)
3077 {
3078      D("NPP_GotFocus(%p, %i)\n", instance, direction);
3079      return false;
3080 }
3081 
3082 /**
3083  * Called by the browser when the browser intends to take focus.
3084  * Instance argument indicates the instances losing focus.
3085  * There is no return value, plugins will lose focus when this is called.
3086  * Currently not used by mozplugger
3087  *
3088  * @param[in] instance Pointer to the plugin instance data
3089  *
3090  * @return True or False
3091  */
NPP_LostFocus(NPP instance)3092 void NPP_LostFocus(NPP instance)
3093 {
3094      D("NPP_LostFocus(%p)\n", instance);
3095 }
3096 
3097 /**
3098  * Currently not used by mozplugger
3099  *
3100  * @param[in] instance Pointer to the plugin instance data
3101  * @param[in] url The URL that was GET or POSTed
3102  * @param[in] status ??
3103  * @param[in] notifyData Data that was passed in the original call to Get or Post URL
3104  *
3105  * @return None
3106  */
NPP_URLRedirectNotify(NPP instance,const char * url,int32_t status,void * noifyData)3107 void NPP_URLRedirectNotify(NPP instance, const char * url, int32_t status, void * noifyData)
3108 {
3109      D("NPP_URLRedirectNotify(%p, %s, %i)\n", instance, url, status);
3110 }
3111 
3112 /**
3113  * Clear site data held by plugin (should this clear tmp files?)
3114  * Currently not used by mozplugger
3115  *
3116  * @param[in] site The site name
3117  * @param[in] flags
3118  * @param[in] maxAge
3119  *
3120  * @return Error status
3121  */
NPP_ClearSiteData(const char * site,uint64_t flags,uint64_t maxAge)3122 NPError NPP_ClearSiteData(const char * site, uint64_t flags, uint64_t maxAge)
3123 {
3124      D("NPP_ClearSiteData(%s)\n", site);
3125      return NPERR_NO_ERROR;
3126 }
3127 
3128 /**
3129  * Get list of sites plugin has data for (should this be list of tmp files?)
3130  * Currently not used by mozplugger
3131  *
3132  * @return List of sites plugin has data for.
3133  */
NPP_GetSitesWithData(void)3134 char ** NPP_GetSitesWithData(void)
3135 {
3136      D("NPP_GetSitesWithData()\n");
3137      return 0;
3138 }
3139