|
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) ![]() |
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 //