fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_open_uri.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_open_uri.cxx 8063 2010-12-19 21:20:10Z matt $"
00003 //
00004 // fl_open_uri() code for FLTK.
00005 //
00006 // Test with:
00007 //
00008 //    gcc -I/fltk/dir -I/fltk/dir/src -DTEST -o fl_open_uri fl_open_uri.cxx -lfltk
00009 //
00010 // Copyright 2003-2010 by Michael R Sweet
00011 //
00012 // This library is free software; you can redistribute it and/or
00013 // modify it under the terms of the GNU Library General Public
00014 // License as published by the Free Software Foundation; either
00015 // version 2 of the License, or (at your option) any later version.
00016 //
00017 // This library is distributed in the hope that it will be useful,
00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020 // Library General Public License for more details.
00021 //
00022 // You should have received a copy of the GNU Library General Public
00023 // License along with this library; if not, write to the Free Software
00024 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00025 // USA.
00026 //
00027 
00028 //
00029 // Include necessary headers...
00030 //
00031 
00032 #include <FL/filename.H>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <errno.h>
00036 #include <sys/types.h>
00037 #include "flstring.h"
00038 #ifdef WIN32
00039 #  include <windows.h>
00040 #  include <shellapi.h>
00041 #else
00042 #  include <sys/wait.h>
00043 #  include <signal.h>
00044 #  include <fcntl.h>
00045 #  include <unistd.h>
00046 #endif // WIN32
00047 
00048 
00049 //
00050 // Local functions...
00051 //
00052 
00053 #if !defined(WIN32) && !defined(__APPLE__)
00054 static char     *path_find(const char *program, char *filename, int filesize);
00055 #endif // !WIN32 && !__APPLE__
00056 #ifndef WIN32
00057 static int      run_program(const char *program, char **argv, char *msg, int msglen);
00058 #endif // !WIN32
00059 
00094 int
00095 fl_open_uri(const char *uri, char *msg, int msglen) {
00096   // Supported URI schemes...
00097   static const char * const schemes[] = {
00098     "file://",
00099     "ftp://",
00100     "http://",
00101     "https://",
00102     "mailto:",
00103     "news://",
00104     NULL
00105   };
00106 
00107   // Validate the URI scheme...
00108   int i;
00109   for (i = 0; schemes[i]; i ++)
00110     if (!strncmp(uri, schemes[i], strlen(schemes[i])))
00111       break;
00112 
00113   if (!schemes[i]) {
00114     if (msg) {
00115       char scheme[255];
00116       if (sscanf(uri, "%254[^:]", scheme) == 1) {
00117         snprintf(msg, msglen, "URI scheme \"%s\" not supported.", scheme);
00118       } else {
00119         snprintf(msg, msglen, "Bad URI \"%s\"", uri);
00120       }
00121     }
00122 
00123     return 0;
00124   }
00125 
00126 #ifdef WIN32
00127   if (msg) snprintf(msg, msglen, "open %s", uri);
00128 
00129   return (int)(ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > (void *)32);
00130 
00131 #elif defined(__APPLE__)
00132   char  *argv[3];                       // Command-line arguments
00133 
00134   argv[0] = (char*)"open";
00135   argv[1] = (char*)uri;
00136   argv[2] = (char*)0;
00137 
00138   if (msg) snprintf(msg, msglen, "open %s", uri);
00139 
00140   return run_program("/usr/bin/open", argv, msg, msglen) != 0;
00141 
00142 #else // !WIN32 && !__APPLE__
00143   // Run any of several well-known commands to open the URI.
00144   //
00145   // We give preference to the Portland group's xdg-utils
00146   // programs which run the user's preferred web browser, etc.
00147   // based on the current desktop environment in use.  We fall
00148   // back on older standards and then finally test popular programs
00149   // until we find one we can use.
00150   //
00151   // Note that we specifically do not support the MAILER and
00152   // BROWSER environment variables because we have no idea whether
00153   // we need to run the listed commands in a terminal program.
00154 
00155   char  command[FL_PATH_MAX],           // Command to run...
00156         *argv[4],                       // Command-line arguments
00157         remote[1024];                   // Remote-mode command...
00158   const char * const *commands;         // Array of commands to check...
00159   static const char * const browsers[] = {
00160     "xdg-open", // Portland
00161     "htmlview", // Freedesktop.org
00162     "firefox",
00163     "mozilla",
00164     "netscape",
00165     "konqueror", // KDE
00166     "opera",
00167     "hotjava", // Solaris
00168     "mosaic",
00169     NULL
00170   };
00171   static const char * const readers[] = {
00172     "xdg-email", // Portland
00173     "thunderbird",
00174     "mozilla",
00175     "netscape",
00176     "evolution", // GNOME
00177     "kmailservice", // KDE
00178     NULL
00179   };
00180   static const char * const managers[] = {
00181     "xdg-open", // Portland
00182     "fm", // IRIX
00183     "dtaction", // CDE
00184     "nautilus", // GNOME
00185     "konqueror", // KDE
00186     NULL
00187   };
00188 
00189   // Figure out which commands to check for...
00190   if (!strncmp(uri, "file://", 7)) commands = managers;
00191   else if (!strncmp(uri, "mailto:", 7) ||
00192            !strncmp(uri, "news:", 5)) commands = readers;
00193   else commands = browsers;
00194 
00195   // Find the command to run...
00196   for (i = 0; commands[i]; i ++)
00197     if (path_find(commands[i], command, sizeof(command))) break;
00198 
00199   if (!commands[i]) {
00200     if (msg) {
00201       snprintf(msg, msglen, "No helper application found for \"%s\"", uri);
00202     }
00203 
00204     return 0;
00205   }
00206 
00207   // Handle command-specific arguments...
00208   argv[0] = (char *)commands[i];
00209 
00210   if (!strcmp(commands[i], "firefox") ||
00211       !strcmp(commands[i], "mozilla") ||
00212       !strcmp(commands[i], "netscape") ||
00213       !strcmp(commands[i], "thunderbird")) {
00214     // program -remote openURL(uri)
00215     snprintf(remote, sizeof(remote), "openURL(%s)", uri);
00216 
00217     argv[1] = (char *)"-remote";
00218     argv[2] = remote;
00219     argv[3] = 0;
00220   } else if (!strcmp(commands[i], "dtaction")) {
00221     // dtaction open uri
00222     argv[1] = (char *)"open";
00223     argv[2] = (char *)uri;
00224     argv[3] = 0;
00225   } else {
00226     // program uri
00227     argv[1] = (char *)uri;
00228     argv[2] = 0;
00229   }
00230 
00231   if (msg) {
00232     strlcpy(msg, argv[0], msglen);
00233 
00234     for (i = 1; argv[i]; i ++) {
00235       strlcat(msg, " ", msglen);
00236       strlcat(msg, argv[i], msglen);
00237     }
00238   }
00239 
00240   return run_program(command, argv, msg, msglen) != 0;
00241 #endif // WIN32
00242 }
00243 
00246 #if !defined(WIN32) && !defined(__APPLE__)
00247 // Find a program in the path...
00248 static char *path_find(const char *program, char *filename, int filesize) {
00249   const char    *path;                  // Search path
00250   char          *ptr,                   // Pointer into filename
00251                 *end;                   // End of filename buffer
00252 
00253 
00254   if ((path = getenv("PATH")) == NULL) path = "/bin:/usr/bin";
00255 
00256   for (ptr = filename, end = filename + filesize - 1; *path; path ++) {
00257     if (*path == ':') {
00258       if (ptr > filename && ptr[-1] != '/' && ptr < end) *ptr++ = '/';
00259 
00260       strlcpy(ptr, program, end - ptr + 1);
00261 
00262       if (!access(filename, X_OK)) return filename;
00263 
00264       ptr = filename;
00265     } else if (ptr < end) *ptr++ = *path;
00266   }
00267 
00268   if (ptr > filename) {
00269     if (ptr[-1] != '/' && ptr < end) *ptr++ = '/';
00270 
00271     strlcpy(ptr, program, end - ptr + 1);
00272 
00273     if (!access(filename, X_OK)) return filename;
00274   }
00275 
00276   return 0;
00277 }
00278 #endif // !WIN32 && !__APPLE__
00279 
00280 
00281 #ifndef WIN32
00282 // Run the specified program, returning 1 on success and 0 on failure
00283 static int
00284 run_program(const char *program, char **argv, char *msg, int msglen) {
00285   pid_t pid;                            // Process ID of first child
00286   int status;                           // Exit status from first child
00287   sigset_t set, oldset;                 // Signal masks
00288 
00289 
00290   // Block SIGCHLD while we run the program...
00291   //
00292   // Note that I only use the POSIX signal APIs, however older operating
00293   // systems may either not support POSIX signals or have side effects.
00294   // IRIX, for example, provides three separate and incompatible signal
00295   // APIs, so it is possible that an application setting a signal handler
00296   // via signal() or sigset() will not have its SIGCHLD signals blocked...
00297 
00298   sigemptyset(&set);
00299   sigaddset(&set, SIGCHLD);
00300   sigprocmask(SIG_BLOCK, &set, &oldset);
00301 
00302   // Create child processes that actually run the program for us...
00303   if ((pid = fork()) == 0) {
00304     // First child comes here, fork a second child and exit...
00305     if (!fork()) {
00306       // Second child comes here, redirect stdin/out/err to /dev/null...
00307       close(0);
00308       open("/dev/null", O_RDONLY);
00309 
00310       close(1);
00311       open("/dev/null", O_WRONLY);
00312 
00313       close(2);
00314       open("/dev/null", O_WRONLY);
00315 
00316       // Detach from the current process group...
00317       setsid();
00318 
00319       // Run the program...
00320       execv(program, argv);
00321       _exit(0);
00322     } else {
00323       // First child gets here, exit immediately...
00324       _exit(0);
00325     }
00326   } else if (pid < 0) {
00327     // Restore signal handling...
00328     sigprocmask(SIG_SETMASK, &oldset, NULL);
00329 
00330     // Return indicating failure...
00331     return 0;
00332   }
00333 
00334   // Wait for the first child to exit...
00335   while (waitpid(pid, &status, 0) < 0) {
00336     if (errno != EINTR) {
00337       // Someone else grabbed the child status...
00338       if (msg) snprintf(msg, msglen, "waitpid(%ld) failed: %s", (long)pid,
00339                         strerror(errno));
00340 
00341       // Restore signal handling...
00342       sigprocmask(SIG_SETMASK, &oldset, NULL);
00343 
00344       // Return indicating failure...
00345       return 0;
00346     }
00347   }
00348 
00349   // Restore signal handling...
00350   sigprocmask(SIG_SETMASK, &oldset, NULL);
00351 
00352   // Return indicating success...
00353   return 1;
00354 }
00355 #endif // !WIN32
00356 
00357 
00358 #ifdef TEST
00359 //
00360 // Test code...
00361 //
00362 
00363 // Open the URI on the command-line...
00364 int main(int argc, char **argv) {
00365   char msg[1024];
00366 
00367 
00368   if (argc != 2) {
00369     puts("Usage: fl_open_uri URI");
00370     return 1;
00371   }
00372 
00373   if (!fl_open_uri(argv[1], msg, sizeof(msg))) {
00374     puts(msg);
00375     return 1;
00376   } else return 0;
00377 }
00378 #endif // TEST
00379 
00380 
00381 //
00382 // End of "$Id: fl_open_uri.cxx 8063 2010-12-19 21:20:10Z matt $".
00383 //