FreeWRL/FreeX3D  3.0.0
pluginUtils.c
1 /*
2 
3  FreeWRL support library.
4  Plugin interaction.
5 
6 */
7 
8 
9 /****************************************************************************
10  This file is part of the FreeWRL/FreeX3D Distribution.
11 
12  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13 
14  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Lesser Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
27 
28 #include <config.h>
29 #include <system.h>
30 #include <display.h>
31 #include <internal.h>
32 #include "../threads.h"
33 
34 #include <libFreeWRL.h>
35 #include <list.h>
36 #include <io_files.h>
37 #include <signal.h>
38 
39 #include "../vrml_parser/Structs.h"
40 #include "../main/headers.h"
41 #include "../main/MainLoop.h" /* for fwl_replaceWorldNeededRes() */
42 #include "../input/EAIHeaders.h" /* for implicit declarations */
43 
44 #include "../x3d_parser/Bindable.h"
45 #include "../opengl/OpenGL_Utils.h"
46 #include "../scenegraph/RenderFuncs.h"
47 #include "../main/ProdCon.h"
48 #include "pluginUtils.h"
49 #include "PluginSocket.h"
50 
51 #define UNUSED(v) ((void) v)
52 
53 static int checkIfX3DVRMLFile(char *fn);
54 // OLDCODE static int checkIfHTMLFile(char *fn);
55 
56 /* get all system commands, and pass them through here. What we do
57  * is take parameters and execl them, in specific formats, to stop
58  * people (or, to try to stop) from typing malicious code. */
59 
60 /* keep a list of children; if one hangs, fwl_doQuit will hang, also. */
61 #ifndef _MSC_VER
62 #define MAXPROCESSLIST 128
63 pid_t childProcess[MAXPROCESSLIST];
64 int lastchildProcess = 0;
65 int childProcessListInit = FALSE;
66 #else
67 #include <process.h>
68 #endif
69 
70 typedef struct ppluginUtils{
71  /* we keep polling here, if we are loading a url...*/
72  int waitingForURLtoLoad;// = FALSE;
73  resource_item_t *plugin_res;// = NULL; /* If this res is valid, then we can replace root_res with it */
74 }* pppluginUtils;
75 void *pluginUtils_constructor(){
76  void *v = MALLOCV(sizeof(struct ppluginUtils));
77  memset(v,0,sizeof(struct ppluginUtils));
78  return v;
79 }
80 void pluginUtils_init(struct tpluginUtils *t){
81  //public
82  //private
83  t->prv = pluginUtils_constructor();
84  {
85  pppluginUtils p = (pppluginUtils)t->prv;
86  /* we keep polling here, if we are loading a url...*/
87  p->waitingForURLtoLoad = FALSE;
88  p->plugin_res = NULL; /* If this res is valid, then we can replace root_res with it */
89  }
90 }
91 
92 
93 
94 void killErrantChildren(void) {
95 #ifndef _MSC_VER
96  int count;
97 
98  for (count = 0; count < MAXPROCESSLIST; count++) {
99  if (childProcess[count] != 0) {
100  /* printf ("trying to kill %d\n",childProcess[count]); */
101  /* http://www.opengroup.org/onlinepubs/000095399/functions/kill.html */
102  kill (childProcess[count],SIGINT);
103  }
104  }
105 #endif
106 }
107 
108 /* implement Anchor/Browser actions */
109 
110 void goToViewpoint(char *vp) {
111  struct X3D_Node *localNode;
112  /* unused int tableIndex; */
113  int flen;
114  struct tProdCon *t = &gglobal()->ProdCon;
115 
116  /* see if we can get a node that matches this DEF name */
117  localNode = EAI_GetViewpoint(vp);
118 
119  /* did we find a match with known Viewpoints?*/
120  if (localNode != NULL) {
121  for (flen=0; flen<vectorSize(t->viewpointNodes);flen++) {
122  if (localNode == vector_get(struct X3D_Node *,t->viewpointNodes,flen)) {
123  struct X3D_Viewpoint *vp;
124  /* unbind current, and bind this one */
125  vp = (struct X3D_Viewpoint*)vector_get(struct X3D_Node *,t->viewpointNodes,t->currboundvpno);
126  send_bind_to((struct X3D_Node*)vp,0);
127  t->currboundvpno=flen;
128  vp = (struct X3D_Viewpoint *)vector_get(struct X3D_Node *,t->viewpointNodes,t->currboundvpno);
129  send_bind_to((struct X3D_Node*)vp,1);
130  return;
131  }
132  }
133  }
134  /* printf ("goToViewpoint - failed to match local Viewpoint\n"); */
135 }
136 
137 #if !defined(_MSC_VER) && !defined(ANDROIDNDK)
138 void startNewHTMLWindow(char *url) {
139  const char *browser;
140 #define LINELEN 4000
141 #define ERRLINELEN 4200
142  char sysline[LINELEN];
143  int sysReturnCode;
144  char syslineFailed[ERRLINELEN];
145  int testlen;
146 
147  browser = NULL;
148 
149 // OLD_IPHONE_AQUA #ifdef AQUA
150 // OLD_IPHONE_AQUA if (RUNNINGASPLUGIN) {
151 // OLD_IPHONE_AQUA /* printf ("Anchor, running as a plugin - load non-vrml file\n"); */
152 // OLD_IPHONE_AQUA requestNewWindowfromPlugin(_fw_browser_plugin, _fw_instance, url);
153 // OLD_IPHONE_AQUA } else {
154 // OLD_IPHONE_AQUA #endif
155 
156  browser = freewrl_get_browser_program();
157  if (!browser) {
158  ConsoleMessage ("Error: no Internet browser found.");
159  return;
160  }
161 
162  /* bounds check here */
163  testlen = 0;
164  if (browser) testlen = (int) strlen(browser);
165 
166  testlen += (int) strlen(url) + 10;
167  if (testlen > LINELEN) {
168  ConsoleMessage ("Anchor: combination of browser name and file name too long.");
169  } else {
170 
171  if (browser) strcpy (sysline, browser);
172  else strcpy (sysline, browser);
173  strcat (sysline, " ");
174  strcat (sysline, url);
175  strcat (sysline, " &");
176  freewrlSystem (sysline);
177  }
178 
179 
180  if (browser) sprintf(sysline, "%s %s &", browser, url);
181  else sprintf(sysline, "open %s &", url);
182  sysReturnCode = system (sysline);
183  if (sysReturnCode < 0) {
184  sprintf(syslineFailed ,"ERR %s %d system call failed, returned %d. Was: %s\n",__FILE__,__LINE__,sysReturnCode,sysline);
185  ConsoleMessage (syslineFailed);
186  }
187 // OLD_IPHONE_AQUA #ifdef AQUA
188 // OLD_IPHONE_AQUA
189 // OLD_IPHONE_AQUA }
190 // OLD_IPHONE_AQUA #endif
191 }
192 #endif
193 
194 
196 //static int waitingForURLtoLoad = FALSE;
197 //static resource_item_t *plugin_res = NULL; /* If this res is valid, then we can replace root_res with it */
198 
199 static int urlLoadingStatus() {
200  pppluginUtils p = (pppluginUtils)gglobal()->pluginUtils.prv;
201 
202  /* printf ("urlLoadingStatus %s\n",resourceStatusToString(plugin_res->status)); */
203  /* printf ("and we have %d children in root.\n",X3D_GROUP(rootNode)->children.n); */
204 
205  switch (p->plugin_res->status) {
206  case ress_downloaded:
207  case ress_parsed:
208  EAI_Anchor_Response(TRUE);
209  p->waitingForURLtoLoad = FALSE;
210  break;
211  case ress_failed:
212  ConsoleMessage ("Failed to load URL\n");
213  EAI_Anchor_Response(FALSE);
214  p->waitingForURLtoLoad = FALSE;
215  break;
216  default: {}
217  }
218 
219  return p->waitingForURLtoLoad;
220 }
221 
222 /* returns FALSE if we are DONE the action, whether or not it was successful;
223  TRUE if we want to hit this next time through the event loop */
224 
225 int doBrowserAction()
226 {
227  int i;
228  struct Multi_String Anchor_url;
229  char *description;
230  resource_item_t * parentPath;
231  pppluginUtils p;
232  ttglobal tg = gglobal();
233  p = (pppluginUtils)tg->pluginUtils.prv;
234 
235 
236  /* are we in the process of polling for a new X3D URL to load? */
237  if (p->waitingForURLtoLoad) return urlLoadingStatus();
238 
239  UNUSED(description); // compiler warning mitigation
240 
241  if (AnchorsAnchor() != NULL) {
242 
243  Anchor_url = AnchorsAnchor()->url;
244  description = AnchorsAnchor()->description->strptr;
245 
246  TRACE_MSG("doBrowserAction: description: %s\n", description);
247 
248  /* are we going to load up a new VRML/X3D world, or are we going to just go and load up a new web page ? */
249  if (Anchor_url.n <= 0) {
250  /* printf ("have Anchor, empty URL\n"); */
251  setAnchorsAnchor( NULL );
252  return FALSE; /* done the action, the url is just not good */
253  }
254 
255  /* June 2016 goal: make frontend handle .html anchors, so it can be done in a platform-specific way
256  x we can't handle mixed anchors (see next comment)
257  * so we still need to determine media_type here:
258  scene, external (ie html - for frontend to do external anchor), or viewpoint.
259 
260  [future: allow mixed anchors: Anchor url [ "missing.wrl" "bad.exe" "funny.html" "#viewpoint" ]
261  and have resource.c iterate over SF till one loads.
262  Problem for future: it takes us several steps to unload current scene, and those steps conflict
263  with any attempt to load a new scene at the same time. So in a resource.c/ProdCon.c driven
264  mixed anchor, if we suddenly find a scene succeeds download, we can't properly unload
265  current scene, due to all the perl arrays and implicit 'bindings' ie one global route array,
266  one global node array, one global texture array, navigation last drag locations in scene rather than mouse coords,
267  and the resource and parsing queues that will think current scene parts are for the new scene.
268  Ideally all those implicit bindings would be hot-swappable, resources would know their scene, so when
269  the are dequeued if their scene is gone they'll be disposed -
270  so a new scene can be parsed while old one running, and swapped in ProdCon after parse, or on next frame.]
271  */
272 
273 
274  /* first test case - url is ONLY a viewpoint change */
275  if (Anchor_url.p[0]->strptr[0] == '#') {
276  setAnchorsAnchor( NULL );
277  fwl_gotoViewpoint(&(Anchor_url.p[0]->strptr[1]));
278  return TRUE;
279  }
280  /* We have a url, lets go and get the first one of them */
281  parentPath = (resource_item_t *)AnchorsAnchor()->_parentResource;
282  p->plugin_res = resource_create_multi0(&AnchorsAnchor()->url);
283 #define DO_THIS_BLOC 1
284 #ifdef DO_THIS_BLOC //EXPERIMENT_FAILED
285  {
286  /*Goal: avoid blocking UI thread
287  Method: schedule a scene change whereby the file part gets sent to the resource worker thread
288  while the UI thread keeps looping
289  - first, make sure it's a scene file (not .html, .img which are handled in the html browser in new window)
290  */
291  BOOL isScene; //, isHTML;
292 
293  // June 2016 change: avoid mixed anchors, must be uniform ie all SF are scene, or all SF are html
294  // for it to be scene, all need to be scene (could split out non-scene to get scene-only MF / non-mixed anchor)
295  isScene = TRUE; //was FALSE
296  for (i = 0; i < Anchor_url.n; i++)
297  isScene = isScene && checkIfX3DVRMLFile(Anchor_url.p[i]->strptr); // was ||
298  if (isScene){
299  resource_identify(parentPath, p->plugin_res);
300  fwl_replaceWorldNeededRes(p->plugin_res);
301  return FALSE;
302  }
303  // June 2016: if not scene or viewpoint, it might be html, plain images, audio
304  // send to frontend for platform-specific anchoring to web browser
305  p->plugin_res->actions = resa_download; //just to get it to the frontend
306  p->plugin_res->media_type = resm_external;
307  p->plugin_res->type = rest_multi;
308  resource_identify(parentPath, p->plugin_res);
309  resitem_enqueue(ml_new(p->plugin_res));
310  }
311 #else //EXPERIMENT
312 
313 #ifdef TEXVERBOSE
314  PRINTF("url: ");
315  Multi_String_print(&AnchorsAnchor()->url);
316  PRINTF("parent resource: \n");
317  resource_dump(parentPath);
318  PRINTF("file resource: \n");
319  resource_dump(p->plugin_res);
320 #endif
321  {
322  s_list_t *head_of_list;
323 
324  /* hold on to the top of the list so we can delete it later */
325  head_of_list = p->plugin_res->m_request;
326 
327  /* go through the urls until we have a success, or total failure */
328  do {
329  /* Setup parent */
330  resource_identify(parentPath, p->plugin_res);
331 
332  /* Setup media type */
333  p->plugin_res->media_type = resm_image; /* quick hack */
334 
335  if (resource_fetch(p->plugin_res)) {
336  /* printf ("really loading anchor from %s\n", plugin_res->actual_file); */
337 
338  /* we have the file; res->actual_file is the file on the local system;
339  plugin_res->parsed_request is the file that might be remote */
340 
341  if (checkIfX3DVRMLFile(p->plugin_res->actual_file)) {
342  resource_item_t *resToLoad;
343 
344  /* out with the old... */
345  kill_oldWorld(TRUE,TRUE,__FILE__,__LINE__);
346 
347  /* tell the new world which viewpoint to go to */
348  //fwl_gotoViewpoint (p->plugin_res->afterPoundCharacters);
349  resToLoad = resource_create_single(p->plugin_res->actual_file);
350  resToLoad->afterPoundCharacters = p->plugin_res->afterPoundCharacters;
351  /* in with the new... */
352  send_resource_to_parser(resToLoad);
353  p->waitingForURLtoLoad = TRUE;
354  return TRUE; /* keep the browser ticking along here */
355  } else {
356 #ifdef _MSC_VER
357  resource_item_t *resToLoad;
358  //we don't want to launch a new IE browser or IE tab,
359  //just load a new scene in freewrl
360  //analogous to what happens when we have file://...AnchorA.x3d
361  //the following is the only way I know to do that right now, same as
362  //below several lines:
363  kill_oldWorld(TRUE,TRUE,__FILE__,__LINE__);
364 
365  /* we want to clean out the old world AND load a new one in */
366 
367  resToLoad = resource_create_single(p->plugin_res->parsed_request);
368  resToLoad->afterPoundCharacters = p->plugin_res->afterPoundCharacters;
369 
370  send_resource_to_parser(resToLoad);
371 
372  p->waitingForURLtoLoad = TRUE;
373  return TRUE; /* keep the browser ticking along here */
374 #else
375  p->plugin_res->complete = TRUE;
376  startNewHTMLWindow(p->plugin_res->parsed_request);
377 #endif
378  }
379  } else {
380  /* we had a problem with that URL, set this so we can try the next */
381  p->plugin_res->type=rest_multi;
382  }
383  } while ((p->plugin_res->status != ress_downloaded) && (p->plugin_res->m_request != NULL));
384 
385  /* destroy the m_request, if it exists */
386  if (head_of_list != NULL) {
387  ml_delete_all(head_of_list);
388  }
389 
390  /* were we successful?? */
391  if (p->plugin_res->status != ress_loaded) {
392  ERROR_MSG("Could not load new world: %s\n", p->plugin_res->actual_file);
393  return FALSE;
394  }
395  }
396 #endif //EXPERIMENT
397 
398 /*********************************************************/
399 
400 
401  } else {
402  /* printf ("\nwe have a single replacement here\n"); */
403  }
404  return FALSE; /* we are done the action */
405 }
406 
407 /*
408  * Check to see if the file name is a geometry file.
409  * return TRUE if it looks like it is, false otherwise
410  *
411  * This should be kept in line with the plugin register code in
412  * Plugin/netscape/source/npfreewrl.c
413  */
414 
415 static int checkIfX3DVRMLFile(char *fn) {
416  if ((strstr(fn,".wrl") > 0) ||
417  (strstr(fn,".WRL") > 0) ||
418  (strstr(fn,".x3d") > 0) ||
419  (strstr(fn,".x3z") > 0) ||
420  (strstr(fn,".x3dv") > 0) ||
421  (strstr(fn,".x3db") > 0) ||
422  (strstr(fn,".X3DV") > 0) ||
423  (strstr(fn,".X3DB") > 0) ||
424  (strstr(fn,".X3D") > 0)) {
425  return TRUE;
426  }
427  return FALSE;
428 }
429 // OLDCODE static int checkIfHTMLFile(char *fn) {
430 // OLDCODE if ((strstr(fn,".html") > 0) ||
431 // OLDCODE (strstr(fn,".HTML") > 0)
432 // OLDCODE ) {
433 // OLDCODE return TRUE;
434 // OLDCODE }
435 // OLDCODE return FALSE;
436 // OLDCODE }
437 
438 
439 void new_root();
440 /* we are an Anchor, and we are not running in a browser, and we are
441  * trying to do an external VRML or X3D world.
442  */
443 /* void Anchor_ReplaceWorld (char *name) */
444 bool Anchor_ReplaceWorld(const char *name)
445 {
446  gglobal()->Mainloop.replaceWorldRequest = STRDUP(name);
447  //resource_item_t *AR_res;
448 
450 
451  //AR_res = resource_create_single(name);
453  //new_root();
454  //send_resource_to_parser(AR_res);
455  //resource_wait(AR_res);
456 
457  //if (AR_res->status != ress_loaded) {
458  // /* FIXME: destroy this new node tree */
459  // return FALSE;
460  //}
461  return TRUE;
462 }
463 
464 /* send in a 0 to 15, return a char representation */
465 char tohex (int mychar) {
466  if (mychar <10) return (mychar + '0');
467  else return (mychar - 10 + 'A');
468 }
469 
470 /* should this character be encoded? */
471 int URLmustEncode(int ch) {
472  if (
473  (ch == 0x20)
474  || (ch == 0x22)
475  || (ch == 0x3c)
476  || (ch == 0x3e)
477  || (ch == 0x23)
478  || (ch == 0x25)
479  || (ch == 0x7b)
480  || (ch == 0x7d)
481  || (ch == 0x7c)
482  || (ch == 0x5c)
483  || (ch == 0x5e)
484  || (ch == 0x7e)
485  || (ch == 0x5b)
486  || (ch == 0x5d)
487  || (ch == 0x60)) return TRUE;
488  return FALSE;
489 }
490 
491 
492 /***************/
493 /* static FILE * tty = NULL; */
494 
495 /* prints to a log file if we are running as a plugin */
496 void URLprint (const char *m, const char *p) {
497 #undef URLPRINTDEBUG
498 #ifdef URLPRINTDEBUG
499  if (tty == NULL) {
500  tty = fopen("/home/luigi/logURLencod", "w");
501  if (tty == NULL)
502  abort();
503  fprintf (tty, "\nplugin restarted\n");
504  }
505 
506  fprintf (tty,"%f URLprint: ",TickTime());
507  fprintf(tty, m,p);
508  fflush(tty);
509 #endif
510 }
511 
512 /* loop about waiting for the Browser to send us some stuff. */
513 /* Change a string to encode spaces for getting URLS. */
514 void URLencod (char *dest, const char *src, int maxlen) {
515  int mylen;
516  int sctr;
517  int destctr;
518  int curchar;
519 
520 #ifdef URLPRINTDEBUG
521  char *orig;
522 
523  orig = dest;
524 
525  /* get the length of the source and bounds check */
526  URLprint ("going to start URLencod %s\n","on a string");
527  URLprint ("start, src is %s\n",src);
528  /* URLprint ("maxlen is %d\n",maxlen); */
529 #endif
530 
531  destctr = 0; /* ensure we dont go over dest length */
532  mylen = (int) strlen(src);
533  if (mylen == 0) {
534  dest[0]= '\0';
535  return;
536  }
537 
538  /* encode the string */
539  for (sctr = 0; sctr < mylen; sctr ++) {
540  curchar = (int) *src; src++;
541  /* should we encode this one? */
542 
543  if (URLmustEncode(curchar)) {
544  *dest = '%'; dest ++;
545  *dest = tohex ((curchar >> 4) & 0x0f); dest++;
546  *dest = tohex (curchar & 0x0f); dest++;
547  destctr +=3;
548  } else {
549  *dest = (char) curchar; destctr++; dest++;
550  }
551 
552 
553 
554  /* bounds check */
555  if (destctr > (maxlen - 5)) {
556  *dest = '\0';
557  return;
558  }
559  }
560  *dest = '\0'; /* null terminate this one */
561 #ifdef URLPRINTDEBUG
562  URLprint ("encoded string is %s\n",orig);
563 #endif
564 
565 }
566 
567 /* this is for Unix only */
568 // OLD_IPHONE_AQUA #if !defined(AQUA) && !defined(_MSC_VER) && !defined(_ANDROID) && !defined(ANDROIDNDK) && !defined(GLES2)
569 #if !defined(_MSC_VER) && !defined(_ANDROID) && !defined(ANDROIDNDK) && !defined(GLES2)
570 
571 void sendXwinToPlugin()
572 {
573  int writeSizeThrowAway ;
574  UNUSED(writeSizeThrowAway); // compiler warning mitigation
575 
576  /* send the window id back to the plugin parent */
577  DEBUG_MSG("Executing sendXwinToPlugin...\n");
578 
579 #if KEEP_X11_INLIB
580  XWindowAttributes mywin;
581 
582  XGetWindowAttributes(Xdpy,Xwin, &mywin);
583  DEBUG_MSG("sendXwinToPlugin: sendXwin starting, mapped_state %d, IsUnmapped %d, isUnviewable %d isViewable %d\n",mywin.map_state, IsUnmapped, IsUnviewable, IsViewable);
584 
585  DEBUG_MSG("sendXwinToPlugin: sending Xwin ID back to plugin - %lu bytes\n",sizeof (Xwin));
586 
587  writeSizeThrowAway = write (_fw_pipe,&Xwin,sizeof(Xwin));
588  close (_fw_pipe);
589 
590  /* wait for the plugin to change the map_state */
591  XGetWindowAttributes(Xdpy,Xwin, &mywin);
592 
593  while (mywin.map_state == IsUnmapped) {
594  usleep (100);
595  XGetWindowAttributes(Xdpy,Xwin, &mywin);
596  #ifdef URLPRINTDEBUG
597  printf ("sendXwin in sleep loope, mapped_state %d, IsUnmapped %d, isUnviewable %d isViewable %d\n",mywin.map_state, IsUnmapped, IsUnviewable, IsViewable);
598  #endif
599 
600  }
601 
602  #ifdef URLPRINTDEBUG
603  XGetWindowAttributes(Xdpy,Xwin, &mywin);
604  printf ("sendXwin at end, mapped_state %d, IsUnmapped %d, isUnviewable %d isViewable %d\n",mywin.map_state, IsUnmapped, IsUnviewable, IsViewable);
605  printf ("x %d y %d wid %d height %d\n",mywin.x,mywin.y,mywin.width,mywin.height);
606  #endif
607 #endif /* KEEP_X11_INLIB */
608 
609 }
610 #endif
611 
Definition: list.h:37