Yattm - unified GTK instant-messaging client logo
   [Generated for version 0.2-17 - Mon Jan 6 19:01:23 GMT+1 2003]

Home - Main Page - Data Structures - File List - Data Fields - Globals

browser.c

Go to the documentation of this file.
00001 /*
00002  * Yattm
00003  * Copyright (C) 1999, Torrey Searle <tsearle@uci.edu>
00004  *
00005  * Source Code taked from GAIM, by Mark Spencer
00006  *
00007  * some code: (most in this file)
00008  * Copyright (C) 1996 Netscape Communications Corporation, all rights reserved.
00009  * Created: Jamie Zawinski <jwz@netscape.com>, 24-Dec-94.
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * This code is mainly taken from Netscape's sample implementation of
00026  * their protocol.  Nifty.
00027  *
00028  */
00029 
00030 
00031 #include "intl.h"
00032 #include <stdio.h>
00033 #include <string.h>
00034 
00035 #ifdef __MINGW32__
00036 #include <gdk/gdkwin32.h>
00037 #else
00038 #include <gdk/gdkx.h>
00039 #include <stdlib.h>
00040 #endif
00041 
00042 #include <gdk/gdkprivate.h>
00043 
00044 #include "dialog.h"
00045 #include "util.h"
00046 #include "gtk_globals.h"
00047 #include "prefs.h"
00048 
00049 enum
00050 {
00051     BROWSER_NETSCAPE,
00052     BROWSER_KFM,
00053     BROWSER_MANUAL,
00054     BROWSER_INTERNAL
00055 };
00056 
00057 #ifndef _WIN32
00058 gint web_browser = BROWSER_NETSCAPE;
00059 
00060 
00061 
00062 
00063 
00064 #include <X11/Xlib.h>
00065 #include <X11/Xatom.h>
00066 
00067 
00068 // static const char *progname = "Yattm"; // Nobody uses this
00069 static const char *expected_mozilla_version = "1.1";
00070 
00071 #define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
00072 #define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
00073 #define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
00074 #define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
00075 
00076 static GdkAtom XA_MOZILLA_VERSION  = 0;
00077 static GdkAtom XA_MOZILLA_LOCK     = 0;
00078 static GdkAtom XA_MOZILLA_COMMAND  = 0;
00079 static GdkAtom XA_MOZILLA_RESPONSE = 0;
00080 
00081 
00082 static int netscape_lock;
00083 
00084 
00085 static Window
00086 VirtualRootWindowOfScreen(screen)
00087         Screen *screen;
00088 {
00089         static Screen *save_screen = (Screen *)0;
00090         static Window root = (Window)0;
00091 
00092         if (screen != save_screen) {
00093                 Display *dpy = DisplayOfScreen(screen);
00094                 Atom __SWM_VROOT = None;
00095                 unsigned int i;
00096                 Window rootReturn, parentReturn, *children;
00097                 unsigned int numChildren;
00098 
00099                 root = RootWindowOfScreen(screen);
00100 
00101                 /* go look for a virtual root */
00102                 __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
00103                 if (XQueryTree(dpy, root, &rootReturn, &parentReturn,
00104                                  &children, &numChildren)) {
00105                         for (i = 0; i < numChildren; i++) {
00106                                 Atom actual_type;
00107                                 int actual_format;
00108                                 unsigned long nitems, bytesafter;
00109                                 Window *newRoot = (Window *)0;
00110 
00111                                 if (XGetWindowProperty(dpy, children[i],
00112                                         __SWM_VROOT, 0, 1, False, XA_WINDOW,
00113                                         &actual_type, &actual_format,
00114                                         &nitems, &bytesafter,
00115                                         (unsigned char **) &newRoot) == Success
00116                                     && newRoot) {
00117                                     root = *newRoot;
00118                                     break;
00119                                 }
00120                         }
00121                         if (children)
00122                                 XFree((char *)children);
00123                 }
00124 
00125                 save_screen = screen;
00126         }
00127 
00128         return root;
00129 }
00130 
00131 /* The following code is Copyright (C) 1989 X Consortium */
00132 
00133 static Window TryChildren();
00134 
00135 /* Find a window with WM_STATE, else return win itself, as per ICCCM */
00136 
00137 static Window GClientWindow (dpy, win)
00138     Display *dpy;
00139     Window win;
00140 {
00141     Atom WM_STATE;
00142     Atom type = None;
00143     int format;
00144     unsigned long nitems, after;
00145     unsigned char *data;
00146     Window inf;
00147 
00148     WM_STATE = XInternAtom(dpy, "WM_STATE", True);
00149     if (!WM_STATE)
00150         return win;
00151     XGetWindowProperty(dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
00152                        &type, &format, &nitems, &after, &data);
00153     if (type)
00154         return win;
00155     inf = TryChildren(dpy, win, WM_STATE);
00156     if (!inf)
00157         inf = win;
00158     return inf;
00159 }
00160 
00161 static
00162 Window TryChildren (dpy, win, WM_STATE)
00163     Display *dpy;
00164     Window win;
00165     Atom WM_STATE;
00166 {
00167     Window root, parent;
00168     Window *children;
00169     unsigned int nchildren;
00170     unsigned int i;
00171     Atom type = None;
00172     int format;
00173     unsigned long nitems, after;
00174     unsigned char *data;
00175     Window inf = 0;
00176 
00177     if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren))
00178         return 0;
00179     for (i = 0; !inf && (i < nchildren); i++) {
00180         XGetWindowProperty(dpy, children[i], WM_STATE, 0, 0, False,
00181                            AnyPropertyType, &type, &format, &nitems,
00182                            &after, &data);
00183         if (type)
00184             inf = children[i];
00185     }
00186     for (i = 0; !inf && (i < nchildren); i++)
00187         inf = TryChildren(dpy, children[i], WM_STATE);
00188     if (children) XFree((char *)children);
00189     return inf;
00190 }
00191 
00192 /* END X Consortium code */
00193 
00194 
00195 
00196 static void mozilla_remote_init_atoms()
00197 {
00198     if (!XA_MOZILLA_VERSION)
00199         XA_MOZILLA_VERSION = gdk_atom_intern(MOZILLA_VERSION_PROP, 0);
00200     if (!XA_MOZILLA_LOCK)
00201                 XA_MOZILLA_LOCK = gdk_atom_intern(MOZILLA_LOCK_PROP, 0);
00202         if (! XA_MOZILLA_COMMAND)
00203                 XA_MOZILLA_COMMAND = gdk_atom_intern(MOZILLA_COMMAND_PROP, 0);
00204     if (! XA_MOZILLA_RESPONSE)
00205         XA_MOZILLA_RESPONSE = gdk_atom_intern(MOZILLA_RESPONSE_PROP, 0);
00206 }
00207 
00208 static GdkWindow *mozilla_remote_find_window()
00209 {
00210         int i;
00211         Window root = VirtualRootWindowOfScreen(DefaultScreenOfDisplay(gdk_display));
00212         Window root2, parent, *kids;
00213         unsigned int nkids;
00214         Window result = 0;
00215         Window tenative = 0;
00216         unsigned char *tenative_version = 0;
00217 
00218         if (!XQueryTree (gdk_display, root, &root2, &parent, &kids, &nkids))
00219         {
00220         }
00221 
00222         /* root != root2 is possible with virtual root WMs. */
00223 
00224         if (!(kids && nkids)) {
00225                 return NULL;
00226         }
00227 
00228         for (i = nkids-1; i >= 0; i--)
00229         {
00230                 Atom type;
00231                 int format;
00232                 unsigned long nitems, bytesafter;
00233                 unsigned char *version = 0;
00234                 Window w = GClientWindow (gdk_display, kids[i]);
00235                 int status = XGetWindowProperty (gdk_display, w, XA_MOZILLA_VERSION,
00236                                                  0, (65536 / sizeof (long)),
00237                                                  False, XA_STRING,
00238                                                  &type, &format, &nitems, &bytesafter,
00239                                                  &version);
00240                 if (! version)
00241                         continue;
00242                 if (strcmp ((char *) version, expected_mozilla_version) &&
00243                     !tenative)
00244                 {
00245                         tenative = w;
00246                         tenative_version = version;
00247                         continue;
00248                 }
00249                 g_free (version);
00250                 if (status == Success && type != None)
00251                 {
00252                         result = w;
00253                         break;
00254                 }
00255         }
00256 
00257         if (result && tenative)
00258         {
00259             g_free (tenative_version);
00260             return gdk_window_foreign_new(result);
00261         }
00262         else if (tenative)
00263         {
00264             g_free (tenative_version);
00265             return gdk_window_foreign_new(tenative);
00266         }
00267         else if (result)
00268         {
00269                 return gdk_window_foreign_new(result);
00270         }
00271         else
00272         {
00273             return NULL;
00274         }
00275 }
00276 
00277 
00278 static char *lock_data = 0;
00279 
00280 static void mozilla_remote_obtain_lock (GdkWindow *window)
00281 {
00282         Bool locked = False;
00283 
00284         if (!lock_data) {
00285         lock_data = (char *)g_malloc (255);
00286         sprintf (lock_data, "pid%d@", getpid ());
00287         if (gethostname (lock_data + strlen (lock_data), 100)) {
00288             return;
00289         }
00290     }
00291 
00292         do {
00293                 int result;
00294                 GdkAtom actual_type;
00295                 gint actual_format;
00296         gint nitems;
00297                 unsigned char *data = 0;
00298 
00299                 result = gdk_property_get (window, XA_MOZILLA_LOCK,
00300                        XA_STRING, 0,
00301                        (65536 / sizeof (long)), 0,
00302                        &actual_type, &actual_format,
00303                        &nitems, &data);
00304                 if (result != Success || actual_type == None)
00305                 {
00306                         /* It's not now locked - lock it. */
00307 
00308                     gdk_property_change(window, XA_MOZILLA_LOCK, XA_STRING,
00309                             8, PropModeReplace,
00310                             (unsigned char *) lock_data,
00311                             strlen (lock_data));
00312                     locked = True;
00313                 }
00314 
00315                 if (!locked) {
00316                         /* Then just fuck it. */
00317                         if (data)
00318                                 g_free(data);
00319                         return;
00320                 }
00321                 if (data)
00322                         g_free(data);
00323         } while (!locked);
00324 }
00325 
00326 
00327 static void mozilla_remote_free_lock (GdkWindow *window)
00328 {
00329         int result = 0;
00330         GdkAtom actual_type;
00331         gint actual_format;
00332         gint nitems;
00333         unsigned char *data = 0;
00334 
00335 
00336         result = gdk_property_get(window, XA_MOZILLA_LOCK, XA_STRING,
00337                   0, (65536 / sizeof (long)),
00338                   1, &actual_type, &actual_format,
00339                   &nitems, &data);
00340         if (result != Success)
00341         {
00342              return;
00343         }
00344         else if (!data || !*data)
00345         {
00346               return;
00347         }
00348         else if (strcmp ((char *) data, lock_data))
00349         {
00350             return;
00351         }
00352 
00353         if (data)
00354                 g_free(data);
00355 }
00356 
00357 
00358 static int
00359 mozilla_remote_command (GdkWindow *window, const char *command,
00360                         Bool raise_p)
00361 {
00362         int result = 0;
00363         Bool done = False;
00364         char *new_command = 0;
00365 
00366         /* The -noraise option is implemented by passing a "noraise" argument
00367          to each command to which it should apply.
00368          */
00369         if (!raise_p)
00370         {
00371                 char *close;
00372                 new_command = (char *) malloc (strlen (command) + 20);
00373                 strcpy (new_command, command);
00374                 close = strrchr (new_command, ')');
00375                 if (close)
00376                         strcpy (close, ", noraise)");
00377                 else
00378                         strcat (new_command, "(noraise)");
00379                 command = new_command;
00380         }
00381 
00382 
00383     gdk_property_change(window, XA_MOZILLA_COMMAND, XA_STRING, 8,
00384                 GDK_PROP_MODE_REPLACE, (unsigned char *) command,
00385                 strlen (command));
00386 
00387     while (!done) {
00388                 GdkEvent *event;
00389         
00390                 event = gdk_event_get();
00391         
00392         if (!event)
00393             continue;
00394         
00395         if (event->any.window != window) {
00396             gtk_main_do_event(event);
00397             continue;
00398         }
00399 
00400                 if (event->type == GDK_DESTROY &&
00401                     event->any.window == window) {
00402 
00403                         /* Print to warn user...*/
00404                         result = 6;
00405                         goto DONE;
00406         } else if (event->type == GDK_PROPERTY_NOTIFY &&
00407                          event->property.state == GDK_PROPERTY_NEW_VALUE &&
00408                          event->property.window == window &&
00409                          event->property.atom == XA_MOZILLA_RESPONSE) {
00410             GdkAtom actual_type;
00411             gint actual_format, nitems;
00412             unsigned char *data = 0;
00413 
00414             result = gdk_property_get (window, XA_MOZILLA_RESPONSE,
00415                            XA_STRING, 0,
00416                            (65536 / sizeof (long)),
00417                            1,
00418                            &actual_type, &actual_format,
00419                            &nitems, &data);
00420 
00421             
00422             if (result == Success && data && *data) {
00423             }
00424 
00425             if (result != Success) {
00426                 result = 6;
00427                 done = True;
00428             } else if (!data || strlen((char *) data) < 5) {
00429                 result = 6;
00430                 done = True;
00431             } else if (*data == '1') { /* positive preliminary reply */
00432             } else if (!strncmp ((char *)data, "200", 3)) {
00433                 result = 0;
00434                 done = True;
00435             } else if (*data == '2') {
00436                 result = 0;
00437                 done = True;
00438             } else if (*data == '3') {
00439                 result = 3;
00440                 done = True;
00441             } else if (*data == '4' || *data == '5') {
00442                 result = (*data - '0');
00443                 done = True;
00444             } else {
00445                 result = 6;
00446                 done = True;
00447             }
00448 
00449             if (data)
00450                 g_free(data);
00451         }
00452         else if (event->type == GDK_PROPERTY_NOTIFY &&
00453                          event->property.window == window &&
00454                          event->property.state == GDK_PROPERTY_DELETE &&
00455                          event->property.atom == XA_MOZILLA_COMMAND) {
00456         }
00457         gdk_event_free(event);
00458     }
00459 
00460 DONE:
00461 
00462     if (new_command)
00463         g_free (new_command);
00464 
00465     return result;
00466 }
00467 
00468 
00469 gint check_netscape(char *msg)
00470 {
00471         int status;
00472         GdkWindow *window;
00473 
00474         mozilla_remote_init_atoms ();
00475         window = mozilla_remote_find_window();
00476 
00477         if (window) {
00478 
00479         XSelectInput(gdk_display, ((GdkWindowPrivate *)window)->xwindow,
00480                  (PropertyChangeMask|StructureNotifyMask));
00481 
00482         
00483                 mozilla_remote_obtain_lock(window);
00484 
00485                 status = mozilla_remote_command(window, msg, False);
00486 
00487                 if (status != 6)
00488                         mozilla_remote_free_lock(window);
00489 
00490                 gtk_timeout_add(1000, (GtkFunction)clean_pid, NULL);
00491 
00492                 netscape_lock = 0;
00493         
00494         g_free(msg);
00495                 return FALSE;
00496         } else
00497                 return TRUE;
00498 }
00499 
00500 
00501 static void netscape_command(char *command)
00502 {
00503         int status;
00504         pid_t pid;
00505     GdkWindow *window;
00506 
00507     if (netscape_lock)
00508         return;
00509 
00510     netscape_lock = 1;
00511 
00512 
00513 
00514     mozilla_remote_init_atoms();
00515     window = mozilla_remote_find_window();
00516 
00517     if (window) {
00518 
00519         XSelectInput(gdk_display, ((GdkWindowPrivate *)window)->xwindow,
00520                  (PropertyChangeMask|StructureNotifyMask));
00521 
00522         mozilla_remote_obtain_lock(window);
00523 
00524         status = mozilla_remote_command(window, command, False);
00525 
00526         if (status != 6)
00527             mozilla_remote_free_lock(window);
00528 
00529         netscape_lock = 0;
00530         
00531     } else {
00532         pid = fork();
00533         if (pid == 0) {
00534             char *args[2];
00535             int e;
00536 
00537             args[0] = g_strdup("netscape");
00538             args[1] = NULL;
00539                         e = execvp(args[0], args);
00540                         
00541             _exit(0);
00542         } else {
00543             char *tmp = g_strdup(command);
00544             gtk_timeout_add(200, (GtkFunction)check_netscape, tmp);
00545         }
00546     }
00547 
00548 }
00549 
00550 void open_url(GtkWidget *w, char *url) {
00551     if (web_browser == BROWSER_NETSCAPE) {
00552                 char *command = g_malloc(1024);
00553 
00554         g_snprintf(command, 1024, "OpenURL(%s)", url);
00555 
00556         netscape_command(command);
00557         g_free(command);
00558     } else if (web_browser == BROWSER_KFM) {
00559         pid_t pid;
00560 
00561         pid = fork();
00562 
00563         if (pid == 0) {
00564             char *args[4];
00565 
00566             args[0] = g_strdup("kfmclient");
00567             args[1] = g_strdup("openURL");
00568                         args[2] = url;;
00569             args[3] = NULL;
00570 
00571             execvp(args[0], args);
00572             _exit(0);
00573         } else {
00574             gtk_timeout_add(1000, (GtkFunction)clean_pid, NULL);
00575         }
00576     }  
00577 }
00578 
00579 void add_bookmark(GtkWidget *w, char *url) {
00580     if (web_browser == BROWSER_NETSCAPE) {
00581                 char *command = g_malloc(1024);
00582 
00583         g_snprintf(command, 1024, "AddBookmark(%s)", url);
00584 
00585         netscape_command(command);
00586         g_free(command);
00587     }
00588 }
00589 
00590 void open_url_nw(GtkWidget *w, char *url) {
00591     char *alternate_browser=cGetLocalPref("alternate_browser");
00592     if ((use_alternate_browser == 1) && (strlen(alternate_browser) > 0)) {
00593         char *command = g_malloc(1024);
00594         char *url_pos = strstr(alternate_browser, "%s");
00595         /*
00596          * if alternate_browser contains a %s, then we put
00597          * the url in place of the %s, else, put the url
00598          * at the end.
00599          */
00600         if(url_pos) {
00601             int pre_len = url_pos-alternate_browser;
00602             strncpy(command, alternate_browser, pre_len);
00603             command[pre_len] = 0;
00604             strncat(command, url, 1024 - pre_len);
00605             strncat(command, url_pos+2, 1024 - strlen(command));
00606             strncat(command, " &", 1024 - strlen(command));
00607         } else
00608             g_snprintf(command, 1024, "%s \"%s\" &", alternate_browser, url);
00609         eb_debug(DBG_CORE, "launching %s\n", command);
00610         system(command);
00611         g_free(command);
00612     } else if (web_browser == BROWSER_NETSCAPE) {
00613         char *command = g_malloc(1024);
00614         g_snprintf(command, 1024, "OpenURL(%s, new-window)", url);
00615 
00616         netscape_command(command);
00617         g_free(command);
00618     }
00619 }
00620 
00621 #else
00622 #include <shellapi.h>
00623 #include <process.h>
00624 gint web_browser = BROWSER_INTERNAL;
00625 
00626 void add_bookmark(GtkWidget *w, char *url) { 
00627 }
00628 
00629 void open_url_nw(GdkWindow *w, char *url) {
00630     ShellExecute(GDK_DRAWABLE_XID(w),"open",url,NULL,"C:\\",0);
00631 }
00632 
00633 void open_url(GdkWindow *w, char *url) {
00634     open_url_nw(w,url);
00635 }
00636 
00637 #endif // _WIN32

Contact: Andy Maloney     [Documentation generated by doxygen]