|
NCBI Home IEB Home C Toolkit docs C++ Toolkit source browser C Toolkit source browser (2) |
NCBI C Toolkit Cross ReferenceC/vibrant/netscape.c |
source navigation diff markup identifier search freetext search file search |
1 /* $Id: netscape.c,v 6.7 2001/03/19 23:15:46 vakatov Exp $
2 * Copyright © 1996 Netscape Communications Corporation, all rights reserved.
3 * ===========================================================================
4 *
5 * PUBLIC DOMAIN NOTICE
6 * National Center for Biotechnology Information
7 *
8 * This software/database is a "United States Government Work" under the
9 * terms of the United States Copyright Act. It was written as part of
10 * the author's official duties as a United States Government employee and
11 * thus cannot be copyrighted. This software/database is freely available
12 * to the public for use. The National Library of Medicine and the U.S.
13 * Government have not placed any restriction on its use or reproduction.
14 *
15 * Although all reasonable efforts have been taken to ensure the accuracy
16 * and reliability of the software and data, the NLM and the U.S.
17 * Government do not and cannot warrant the performance or results that
18 * may be obtained by using this software or data. The NLM and the U.S.
19 * Government disclaim all warranties, express or implied, including
20 * warranties of performance, merchantability or fitness for any particular
21 * purpose.
22 *
23 * Please cite the author in any work or product based on this material.
24 *
25 * ===========================================================================
26 *
27 * File Name: $RCSfile: netscape.c,v $
28 *
29 * Author: Sergei Shavirin
30 *
31 * Initial Version Creation Date: 11/08/1997
32 *
33 * $Revision: 6.7 $
34 *
35 * File Description:
36 * API to remote-control Netscape(run Netscape browsers, open URLs)
37 *
38 * $Log: netscape.c,v $
39 * Revision 6.7 2001/03/19 23:15:46 vakatov
40 * NS_LoadNetscape() -- try execlp() in addition to execl(), and do not forget
41 * to exit on error. The bug was caught by H.Feldman <feldman@mshri.on.ca>.
42 *
43 * Revision 6.6 2000/01/13 23:37:14 beloslyu
44 * changes because of port to HP-UX 11.0
45 *
46 * Revision 6.5 1999/11/08 21:04:40 sinyakov
47 * Corrected const char* to char* assignmetn warning
48 *
49 * Revision 6.4 1999/10/15 21:19:40 sinyakov
50 * Fixed NS_SendCommand() to support long URLs
51 *
52 * Revision 6.3 1998/05/29 15:43:11 vakatov
53 * Patched this funny unstable prototype for "gethostname()"
54 *
55 * Revision 6.2 1998/01/22 17:06:43 vakatov
56 * Added "Xatom.h" header; use TRACE instead of fprintf() & perror()
57 *
58 * 01/21/98 D.Vakatov: cleaned up, Purify'd, CoreLib'd, prepared to ci, ci'd
59 * ==========================================================================
60 */
61
62 #include <vibtypes.h>
63 #include <vibprocs.h>
64 #include <vibincld.h>
65 #include <netscape.h>
66
67
68 #ifdef WIN_X
69
70 #include <X11/Xatom.h>
71 #if !defined(__hpux)
72 #include <X11/Xmu/WinUtil.h>
73 #endif
74
75 #define MOZILLA_VERSION_PROP "_MOZILLA_VERSION"
76 #define MOZILLA_LOCK_PROP "_MOZILLA_LOCK"
77 #define MOZILLA_COMMAND_PROP "_MOZILLA_COMMAND"
78 #define MOZILLA_RESPONSE_PROP "_MOZILLA_RESPONSE"
79 #define MOZILLA_URL_PROP "_MOZILLA_URL"
80
81 #ifdef OS_UNIX_IRIX
82 #define NETSCAPE_PATH "/usr/ncbi/bin/netscape"
83 #else
84 #define NETSCAPE_PATH "/usr/ncbi/X11/bin/netscape"
85 #endif
86
87 #define DEFAULT_URL "http://www.ncbi.nlm.nih.gov"
88
89 typedef struct NS_WindowTag {
90 Display *dpy;
91 Window window;
92 } NS_WindowStruct;
93
94 static Atom XA_MOZILLA_URL = 0;
95 static Atom XA_MOZILLA_VERSION = 0;
96 static Atom XA_MOZILLA_LOCK = 0;
97 static Atom XA_MOZILLA_COMMAND = 0;
98 static Atom XA_MOZILLA_RESPONSE = 0;
99
100 #define NO_NETSCAPE_LOADED 0
101 #define EXACT_URL_MATCH 1
102 #define SOME_WINDOW_FOUND 2
103
104 static Boolean NS_Init_atoms (Display *dpy)
105 {
106
107 if (! XA_MOZILLA_URL)
108 XA_MOZILLA_URL = XInternAtom (dpy, MOZILLA_URL_PROP, False);
109 if (! XA_MOZILLA_VERSION)
110 XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
111 if (! XA_MOZILLA_LOCK)
112 XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
113 if (! XA_MOZILLA_COMMAND)
114 XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
115 if (! XA_MOZILLA_RESPONSE)
116 XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
117
118 return TRUE;
119 }
120
121 static Nlm_Boolean NS_Find_window(NS_Window nswin, const Nlm_Char *url_to_load)
122 {
123 Nlm_Int4 i;
124 Window root, root2, parent, *kids;
125 unsigned int nkids;
126 Window tentative = 0;
127 Nlm_Boolean retvalue = NO_NETSCAPE_LOADED;
128
129 if (!nswin || !nswin->dpy)
130 return retvalue;
131
132 root = RootWindowOfScreen (DefaultScreenOfDisplay (nswin->dpy));
133
134 if (! XQueryTree (nswin->dpy, root, &root2, &parent, &kids, &nkids)) {
135 Message(MSG_ERROR, "NS_Find_window: XQueryTree failed on display %s",
136 DisplayString (nswin->dpy));
137 return retvalue;
138 }
139
140 /* root != root2 is possible with virtual root WMs. */
141
142 if (!(kids && nkids)) {
143 Message(MSG_ERROR, "NS_Find_window: Root window has no children "
144 "on display %s",
145 DisplayString (nswin->dpy));
146 return retvalue;
147 }
148
149 for (i = nkids-1; i >= 0; i--) {
150 Atom type;
151 int format;
152 unsigned long nitems, bytesafter;
153 unsigned char *urlstring = NULL;
154 Window w = XmuClientWindow (nswin->dpy, kids[i]);
155
156 int status = XGetWindowProperty (nswin->dpy, w, XA_MOZILLA_URL,
157 0, (65536 / sizeof (long)),
158 False, XA_STRING,
159 &type, &format, &nitems, &bytesafter,
160 &urlstring);
161
162 if (status != Success || type == None)
163 continue;
164
165 if (urlstring == NULL)
166 continue;
167
168 /* So... We have found at least one Netscape Window ... Cool.. */
169 if (!tentative && StringStr((Nlm_CharPtr)urlstring, url_to_load)) {
170 nswin->window = w;
171 XFree(urlstring);
172 retvalue = SOME_WINDOW_FOUND;
173 continue;
174 } else {
175 nswin->window = w;
176 XFree(urlstring);
177 retvalue = EXACT_URL_MATCH;
178 break;
179 }
180 }
181 XFree(kids);
182 return retvalue;
183 }
184
185 static Nlm_Boolean NS_Check_window (NS_Window nswin)
186 {
187 Atom type;
188 int format;
189 unsigned long nitems, bytesafter;
190 unsigned char *version = 0;
191 int status;
192
193 if (!nswin || !nswin->dpy || !nswin->window)
194 return FALSE;
195
196 status = XGetWindowProperty (nswin->dpy, nswin->window,
197 XA_MOZILLA_VERSION,
198 0, (65536 / sizeof (long)),
199 False, XA_STRING,
200 &type, &format, &nitems, &bytesafter,
201 &version);
202 if (status != Success || !version) {
203 if(version != NULL)
204 XFree (version);
205 return FALSE;
206 }
207 return TRUE;
208 }
209
210
211 static char *lock_data = 0;
212
213
214 /* patch to old SunOS/Solaris proto(cut&paste from Solaris 2.6 "unistd.h") */
215 #ifdef __cplusplus
216 extern "C" {
217 #endif
218
219 #if defined(OS_UNIX_SOL) || defined(OS_UNIX_SUN)
220 #if defined(_XPG4_2)
221 extern int gethostname(char *, size_t);
222 #elif defined(__EXTENSIONS__) || \
223 (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE))
224 extern int gethostname(char *, int);
225 #endif
226 #endif
227
228 #ifdef __cplusplus
229 }
230 #endif
231
232
233 static Nlm_Boolean NS_Obtain_lock (NS_Window nswin)
234 {
235 Bool locked = False;
236 Bool waited = False;
237
238 if (! lock_data) {
239 lock_data = (char *) malloc (255);
240 sprintf (lock_data, "pid%d@", (int)getpid());
241 if (gethostname (lock_data + strlen (lock_data), 100)) {
242 TRACE ( "gethostname() failed" );
243 return FALSE;
244 }
245 }
246
247 do {
248 int result;
249 Atom actual_type;
250 int actual_format;
251 unsigned long nitems, bytes_after;
252 unsigned char *data = 0;
253
254 /* ################################# DANGER! */
255 XGrabServer (nswin->dpy);
256
257 result = XGetWindowProperty (nswin->dpy, nswin->window,
258 XA_MOZILLA_LOCK,
259 0, (65536 / sizeof (long)),
260 False, /* don't delete */
261 XA_STRING,
262 &actual_type, &actual_format,
263 &nitems, &bytes_after,
264 &data);
265 if (result != Success || actual_type == None) {
266 /* It's not now locked - lock it. */
267 #ifdef DEBUG_PROPS
268 TRACE ( "NS_Obtain_lock: (writing " MOZILLA_LOCK_PROP
269 " \"%s\" to 0x%x)\n",
270 lock_data, (unsigned int) window);
271 #endif
272 XChangeProperty (nswin->dpy, nswin->window,
273 XA_MOZILLA_LOCK, XA_STRING, 8,
274 PropModeReplace, (unsigned char *) lock_data,
275 strlen (lock_data));
276 locked = True;
277 }
278
279 XUngrabServer (nswin->dpy);
280 /* ################################# danger over */
281
282 XSync (nswin->dpy, False);
283
284 if (! locked) {
285 /* We tried to grab the lock this time, and failed because someone
286 else is holding it already. So, wait for a PropertyDelete event
287 to come in, and try again. */
288
289 Message(MSG_OK, "NS_Obtain_lock: window 0x%x is "
290 "locked by %s; waiting...\n",
291 (unsigned int) nswin->window, data);
292
293 waited = True;
294
295 while (TRUE) {
296 XEvent event;
297 XNextEvent (nswin->dpy, &event);
298 if (event.xany.type == DestroyNotify &&
299 event.xdestroywindow.window == nswin->window) {
300 Message(MSG_ERROR, "NS_Obtain_lock: "
301 "window 0x%x unexpectedly destroyed.\n",
302 (unsigned int) nswin->window);
303 return FALSE;
304 } else if (event.xany.type == PropertyNotify &&
305 event.xproperty.state == PropertyDelete &&
306 event.xproperty.window == nswin->window &&
307 event.xproperty.atom == XA_MOZILLA_LOCK) {
308 /* Ok! Someone deleted their lock, so now we can try
309 again. */
310 #ifdef DEBUG_PROPS
311 TRACE ( "NS_Obtain_lock: "
312 "(0x%x unlocked, trying again...)\n",
313 (unsigned int) nswin->window);
314 #endif
315 break;
316 }
317 }
318 }
319 if (data)
320 XFree (data);
321 } while (! locked);
322
323 #ifdef DEBUG_PROPS
324 if (waited) {
325 TRACE ( "NS_Obtain_lock: obtained lock.\n");
326 }
327 #endif
328
329 return TRUE;
330 }
331
332 static Boolean NS_Free_lock (NS_Window nswin)
333 {
334 int result;
335 Atom actual_type;
336 int actual_format;
337 unsigned long nitems, bytes_after;
338 unsigned char *data = 0;
339
340 #ifdef DEBUG_PROPS
341 TRACE ( "NS_Free_lock: (deleting %s \"%s\" from 0x%x)\n",
342 MOZILLA_LOCK_PROP, lock_data, (unsigned int) nswin->window);
343 #endif
344
345 result = XGetWindowProperty (nswin->dpy, nswin->window, XA_MOZILLA_LOCK,
346 0, (65536 / sizeof (long)),
347 True, /* atomic delete after */
348 XA_STRING,
349 &actual_type, &actual_format,
350 &nitems, &bytes_after,
351 &data);
352 if (result != Success) {
353 TRACE ( "NS_Free_lock: unable to read and delete %s property\n",
354 MOZILLA_LOCK_PROP);
355 return FALSE;
356 } else if (!data || !*data) {
357 TRACE ( "NS_Free_lock: invalid data on %s of window 0x%x.\n",
358 MOZILLA_LOCK_PROP, (unsigned int) nswin->window);
359 return FALSE;
360 } else if (strcmp ((char *) data, lock_data)) {
361 TRACE ( "NS_Free_lock: %s was stolen! Expected \"%s\", "
362 "saw \"%s\"!\n", MOZILLA_LOCK_PROP, lock_data, data);
363 return FALSE;
364 }
365
366 if (data)
367 XFree (data);
368
369 return TRUE;
370 }
371
372
373 static int NS_Command(NS_Window nswin, const char *command, Bool raise_p)
374 {
375 int result;
376 Bool done = False;
377 char *new_command = 0;
378
379 /* The -noraise option is implemented by passing a "noraise" argument
380 to each command to which it should apply.
381 */
382 if (! raise_p) {
383 char *close;
384 new_command = (char *) malloc (strlen (command) + 20);
385 strcpy (new_command, command);
386 close = strrchr (new_command, ')');
387 if (close)
388 strcpy (close, ", noraise)");
389 else
390 strcat (new_command, "(noraise)");
391 command = new_command;
392 }
393
394 #ifdef DEBUG_PROPS
395 TRACE ( "NS_Command: (writing %s \"%s\" to 0x%x)\n",
396 MOZILLA_COMMAND_PROP, command, (unsigned int) nswin->window);
397 #endif
398
399 XChangeProperty (nswin->dpy, nswin->window, XA_MOZILLA_COMMAND,
400 XA_STRING, 8,
401 PropModeReplace, (unsigned char *) command,
402 strlen (command));
403
404 while (!done) {
405 XEvent event;
406 XNextEvent (nswin->dpy, &event);
407 if (event.xany.type == DestroyNotify &&
408 event.xdestroywindow.window == nswin->window) {
409 /* Print to warn user...*/
410 TRACE ( "NS_Command: window 0x%x was destroyed.\n",
411 (unsigned int) nswin->window);
412 result = 6;
413 goto DONE;
414 }
415 else if (event.xany.type == PropertyNotify &&
416 event.xproperty.state == PropertyNewValue &&
417 event.xproperty.window == nswin->window &&
418 event.xproperty.atom == XA_MOZILLA_RESPONSE) {
419 Atom actual_type;
420 int actual_format;
421 unsigned long nitems, bytes_after;
422 unsigned char *data = 0;
423
424 result = XGetWindowProperty (nswin->dpy, nswin->window,
425 XA_MOZILLA_RESPONSE,
426 0, (65536 / sizeof (long)),
427 True, /* atomic delete after */
428 XA_STRING,
429 &actual_type, &actual_format,
430 &nitems, &bytes_after,
431 &data);
432 #ifdef DEBUG_PROPS
433 if (result == Success && data && *data) {
434 TRACE ( "NS_Command: (server sent %s \"%s\" to 0x%x.)\n",
435 MOZILLA_RESPONSE_PROP, data, (unsigned int) nswin->window);
436 }
437 #endif
438
439 if (result != Success) {
440 TRACE ( "NS_Command: failed reading %s from window 0x%0x.\n",
441 MOZILLA_RESPONSE_PROP, (unsigned int)nswin->window);
442 result = 6;
443 done = True;
444 } else if (!data || strlen((char *) data) < 5) {
445 TRACE ( "NS_Command: invalid data on %s property of window 0x%0x.\n",
446 MOZILLA_RESPONSE_PROP, (unsigned int)nswin->window);
447 result = 6;
448 done = True;
449 } else if (*data == '1') { /* positive preliminary reply */
450 TRACE ( "NS_Command: %s\n", data + 4);
451 /* keep going */
452 done = False;
453 }
454 else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
455 {
456 result = 0;
457 done = True;
458 }
459 else if (*data == '2') /* positive completion */
460 {
461 TRACE ( "NS_Command: %s\n",data + 4);
462 result = 0;
463 done = True;
464 }
465 else if (*data == '3') /* positive intermediate reply */
466 {
467 TRACE ( "NS_Command: internal error: "
468 "server wants more information? (%s)\n", data);
469 result = 3;
470 done = True;
471 }
472 else if (*data == '4' || /* transient negative completion */
473 *data == '5') /* permanent negative completion */
474 {
475 TRACE ( "NS_Command: %s\n", data + 4);
476 result = (*data - '0');
477 done = True;
478 }
479 else
480 {
481 TRACE ( "NS_Command: unrecognised %s from "
482 "window 0x%x: %s\n",
483 MOZILLA_RESPONSE_PROP,
484 (unsigned int) nswin->window, data);
485 result = 6;
486 done = True;
487 }
488
489 if (data)
490 XFree (data);
491 }
492 #ifdef DEBUG_PROPS
493 else if (event.xany.type == PropertyNotify &&
494 event.xproperty.window == nswin->window &&
495 event.xproperty.state == PropertyDelete &&
496 event.xproperty.atom == XA_MOZILLA_COMMAND) {
497 TRACE ( "NS_Command: (server 0x%x has accepted %s.)\n",
498 MOZILLA_COMMAND_PROP, (unsigned int) nswin->window);
499 }
500 #endif /* DEBUG_PROPS */
501 }
502
503 DONE:
504
505 if (new_command)
506 free (new_command);
507
508 return result;
509 }
510
511
512 static Boolean NS_Init(NS_WindowPtr window)
513 {
514 NS_Window nswin;
515
516 if(window == NULL)
517 return FALSE;
518
519 if(*window != NULL)
520 return TRUE;
521
522 *window = nswin = (NS_Window)MemNew(sizeof(NS_WindowStruct));
523
524 if((nswin->dpy = XOpenDisplay(NULL)) == NULL) {
525 MemFree(nswin);
526 *window = NULL;
527 return FALSE;
528 }
529
530 NS_Init_atoms(nswin->dpy);
531 return TRUE;
532 }
533
534
535 static Boolean NS_LoadNetscape(const char *url)
536 {
537 int childpid = fork();
538
539 if (childpid < 0) {
540 return FALSE;
541 }
542
543 if (childpid > 0) {
544 /* ----- parent process ---------- */
545 /* Nothing much to be done here ... */
546 return TRUE;
547 /* -------------------------------- */
548 }
549
550 /* ---------- child process ------------ */
551 if (execlp("netscape", "netscape", url, NULL) < 0 &&
552 execl(NETSCAPE_PATH, NETSCAPE_PATH, url, NULL) < 0) {
553 Message(MSG_ERROR, "Failure to open URL in netscape window");
554 exit(1);
555 }
556
557 /* ----- must never get to this code! ----- */
558 ASSERT(0);
559 return FALSE;
560 }
561
562
563 extern void NS_ResetWindow(NS_Window window)
564 {
565 if ( window )
566 window->window = 0;
567 }
568
569
570 extern Nlm_Boolean NS_SendCommand(NS_WindowPtr window,
571 const Nlm_Char *cmd,
572 const Nlm_Char *url,
573 const Nlm_Char *wintag,
574 Nlm_Boolean raise)
575 {
576 int status = 0, find_status = EXACT_URL_MATCH;
577 NS_Window nswin;
578 Nlm_CharPtr command = 0;
579
580 if(!window || (!cmd && !url))
581 return FALSE;
582
583 if(cmd && url)
584 NS_ResetWindow(*window);
585
586 if ( !url )
587 url = DEFAULT_URL;
588
589 if ( !NS_Init(window) )
590 return FALSE;
591
592 nswin = *window;
593 if ( !NS_Check_window(nswin) ) {
594 find_status = NS_Find_window(nswin, url);
595
596 switch(find_status) {
597 case EXACT_URL_MATCH:
598 break;
599 case SOME_WINDOW_FOUND:
600 break;
601 case NO_NETSCAPE_LOADED:
602 default:
603 NS_LoadNetscape(url);
604 return TRUE;
605 }
606 }
607
608 /* OK We have valid existing window of Netscape and now play with it */
609 XSelectInput(nswin->dpy, nswin->window,
610 (PropertyChangeMask|StructureNotifyMask));
611
612 if ( !cmd ) {
613 const Nlm_Char *wintag_t = wintag ? wintag : "VibrantInterface";
614 command = (Nlm_CharPtr) MemNew (strlen (url) + strlen (wintag_t) + 20);
615 sprintf(command, "openURL(%s, %s)",
616 url, wintag_t);
617 }
618
619 NS_Obtain_lock(nswin);
620
621 status = NS_Command(nswin, cmd ? cmd : command, raise);
622
623 /* When status = 6, it means the window has been destroyed */
624 /* It is invalid to free the lock when window is destroyed. */
625 if (status != 6)
626 NS_Free_lock(nswin);
627
628 if(find_status == SOME_WINDOW_FOUND)
629 NS_Find_window (nswin, url);
630
631 MemFree(command);
632
633 return status ? FALSE : TRUE;
634 }
635
636
637 extern Nlm_Boolean NS_OpenURL(NS_WindowPtr window,
638 const Nlm_Char *url, const Nlm_Char *wintag,
639 Nlm_Boolean raise)
640 {
641 return NS_SendCommand(window, NULL, url, wintag, raise);
642 }
643
644
645 extern void NS_WindowFree(NS_Window window)
646 {
647 if ( window )
648 MemFree(window);
649 }
650
651 #else /* WIN_X */
652
653 typedef struct NS_WindowTag {
654 int dummy;
655 } NS_WindowStruct;
656
657
658 extern void NS_ResetWindow(NS_Window window) {
659 return;
660 }
661 extern Nlm_Boolean NS_SendCommand(NS_WindowPtr window,
662 const Nlm_Char *cmd,
663 const Nlm_Char *url,
664 const Nlm_Char *wintag,
665 Nlm_Boolean raise) {
666 return FALSE;
667 }
668 extern Nlm_Boolean NS_OpenURL(NS_WindowPtr window,
669 const Nlm_Char *url, const Nlm_Char *wintag,
670 Nlm_Boolean raise) {
671 return FALSE;
672 }
673 extern void NS_WindowFree(NS_Window window) {
674 return;
675 }
676
677 #endif /* WIN_X */
678
679
680 /************************************************************************/
681
682 #ifdef TEST_MODULE_NETSCAPE
683
684 #define SB_URL "http://inhouse.ncbi.nlm.nih.gov:6224/cgi-bin/SmartBlast/nph-smblast"
685 #define SB_ACC_URL "http://inhouse.ncbi.nlm.nih.gov:6224/cgi-bin/SmartBlast/sub_blast.pl"
686 #define SB_SEARCH_TAG "search_form"
687 #define SB_ACCESSION_TAG "accession_list"
688
689 static Nlm_Boolean NS_LoadSmartBlast(NS_WindowPtr window, char *accession)
690 {
691 Nlm_Char tmp[512];
692
693 sprintf(tmp, "%s?acc=%s", SB_URL, accession);
694
695 if(!NS_OpenURL(window, tmp, NULL, TRUE)) {
696 Message(MSG_ERROR, "Failure to open URL in netscape window");
697 return FALSE;
698 }
699 return TRUE;
700 }
701
702 Nlm_Int2 Main(void)
703 {
704 NS_Window window = NULL;
705
706 if (Nlm_GetArgc() < 2) {
707 TRACE ( "Usage: %s <accession>\n", Nlm_GetArgv()[0] );
708 exit(1);
709 }
710
711 if ( NS_LoadSmartBlast(&window, Nlm_GetArgv()[1]) )
712 NS_WindowFree(window);
713
714 return 0;
715 }
716 #endif /* TEST_MODULE_NETSCAPE */
717 |
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more information. |