PageRenderTime 48ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/reference/fish-1.23.0/mimedb.c

http://github.com/cardmagic/lucash
C | 1442 lines | 1013 code | 214 blank | 215 comment | 158 complexity | 588aa3778125499848c5456cfa07c25a MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0, LGPL-2.0
  1. /** \file mimedb.c
  2. mimedb is a program for checking the mimetype, description and
  3. default action associated with a file or mimetype. It uses the
  4. xdgmime library written by the fine folks at freedesktop.org. There does
  5. not seem to be any standard way for the user to change the preferred
  6. application yet.
  7. The first implementation of mimedb used xml_grep to parse the xml
  8. file for the mime entry to determine the description. This was abandoned
  9. because of the performance implications of parsing xml. The current
  10. version only does a simple string search, which is much, much
  11. faster but it might fall on it's head.
  12. This code is Copyright 2005-2008 Axel Liljencrantz.
  13. It is released under the GPL.
  14. The xdgmime library is dual licensed under LGPL/artistic
  15. license. Read the source code of the library for more information.
  16. */
  17. #include "config.h"
  18. #include <string.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <unistd.h>
  24. #include <fcntl.h>
  25. #include <libgen.h>
  26. #include <errno.h>
  27. #include <regex.h>
  28. #include <locale.h>
  29. #ifdef HAVE_GETOPT_H
  30. #include <getopt.h>
  31. #endif
  32. #if HAVE_LIBINTL_H
  33. #include <libintl.h>
  34. #endif
  35. #include "xdgmime.h"
  36. #include "fallback.h"
  37. #include "util.h"
  38. #include "print_help.h"
  39. /**
  40. Location of the applications .desktop file, relative to a base mime directory
  41. */
  42. #define APPLICATIONS_DIR "applications/"
  43. /**
  44. Location of the mime xml database, relative to a base mime directory
  45. */
  46. #define MIME_DIR "mime/"
  47. /**
  48. Filename suffix for XML files
  49. */
  50. #define MIME_SUFFIX ".xml"
  51. /**
  52. Start tag for langauge-specific comment
  53. */
  54. #define START_TAG "<comment( +xml:lang *= *(\"%s\"|'%s'))? *>"
  55. /**
  56. End tab for comment
  57. */
  58. #define STOP_TAG "</comment *>"
  59. /**
  60. File contains cached list of mime actions
  61. */
  62. #define DESKTOP_DEFAULT "applications/defaults.list"
  63. /**
  64. Size for temporary string buffer used to make a regex for language
  65. specific descriptions
  66. */
  67. #define BUFF_SIZE 1024
  68. /**
  69. Program name
  70. */
  71. #define MIMEDB "mimedb"
  72. /**
  73. Getopt short switches for mimedb
  74. */
  75. #define GETOPT_STRING "tfimdalhv"
  76. /**
  77. All types of input and output possible
  78. */
  79. enum
  80. {
  81. FILEDATA,
  82. FILENAME,
  83. MIMETYPE,
  84. DESCRIPTION,
  85. ACTION,
  86. LAUNCH
  87. }
  88. ;
  89. /**
  90. Regular expression variable used to find start tag of description
  91. */
  92. static regex_t *start_re=0;
  93. /**
  94. Regular expression variable used to find end tag of description
  95. */
  96. static regex_t *stop_re=0;
  97. /**
  98. Error flag. Non-zero if something bad happened.
  99. */
  100. static int error = 0;
  101. /**
  102. String of characters to send to system() to launch a file
  103. */
  104. static char *launch_buff=0;
  105. /**
  106. Length of the launch_buff buffer
  107. */
  108. static int launch_len=0;
  109. /**
  110. Current position in the launch_buff buffer
  111. */
  112. static int launch_pos=0;
  113. /**
  114. gettext alias
  115. */
  116. #ifdef USE_GETTEXT
  117. #define _(string) gettext(string)
  118. #else
  119. #define _(string) (string)
  120. #endif
  121. /**
  122. Call malloc, set error flag and print message on failure
  123. */
  124. void *my_malloc( size_t s )
  125. {
  126. void *res = malloc( s );
  127. if( !s )
  128. {
  129. error=1;
  130. fprintf( stderr, _("%s: Out of memory\n"), MIMEDB );
  131. }
  132. return res;
  133. }
  134. /**
  135. Duplicate string, set error flag and print message on failure
  136. */
  137. char *my_strdup( char *s )
  138. {
  139. char *res = strdup( s );
  140. if( !s )
  141. {
  142. error=1;
  143. fprintf( stderr, _("%s: Out of memory\n"), MIMEDB );
  144. }
  145. return res;
  146. }
  147. /**
  148. Search the file \c filename for the first line starting with \c
  149. match, which is returned in a newly allocated string.
  150. */
  151. static char * search_ini( const char *filename, const char *match )
  152. {
  153. FILE *f = fopen( filename, "r" );
  154. char buf[4096];
  155. int len=strlen(match);
  156. int done = 0;
  157. if(!f )
  158. {
  159. perror( "fopen" );
  160. error=1;
  161. return 0;
  162. }
  163. while( !done )
  164. {
  165. if( !fgets( buf, 4096, f ) )
  166. {
  167. if( !feof( f ) )
  168. {
  169. perror( "fgets" );
  170. error=1;
  171. }
  172. buf[0]=0;
  173. done = 1;
  174. }
  175. else if( strncmp( buf, match,len )==0)
  176. {
  177. done=1;
  178. }
  179. }
  180. fclose( f );
  181. if( buf[0] )
  182. {
  183. char *res=strdup(buf);
  184. if( res )
  185. {
  186. if(res[strlen(res)-1]=='\n' )
  187. res[strlen(res)-1]='\0';
  188. }
  189. return res;
  190. }
  191. else
  192. return (char *)0;
  193. }
  194. /**
  195. Test if the specified file exists. If it does not, also try
  196. replacing dashes with slashes in \c in.
  197. */
  198. static char *file_exists( const char *dir, const char *in )
  199. {
  200. char *filename = my_malloc( strlen( dir ) + strlen(in) + 1 );
  201. char *replaceme;
  202. struct stat buf;
  203. // fprintf( stderr, "Check %s%s\n", dir, in );
  204. if( !filename )
  205. {
  206. return 0;
  207. }
  208. strcpy( filename, dir );
  209. strcat( filename, in );
  210. if( !stat( filename, &buf ) )
  211. return filename;
  212. free( filename );
  213. /*
  214. DOH! File does not exist. But all is not lost. KDE sometimes uses
  215. a slash in the name as a directory separator. We try to replace
  216. a dash with a slash and try again.
  217. */
  218. replaceme = strchr( in, '-' );
  219. if( replaceme )
  220. {
  221. char *res;
  222. *replaceme = '/';
  223. res = file_exists( dir, in );
  224. *replaceme = '-';
  225. return res;
  226. }
  227. /*
  228. OK, no more slashes left. We really are screwed. Nothing to to
  229. but admit defeat and go home.
  230. */
  231. return 0;
  232. }
  233. /**
  234. Try to find the specified file in any of the possible directories
  235. where mime files can be located. This code is shamelessly stolen
  236. from xdg_run_command_on_dirs.
  237. */
  238. static char *get_filename( char *f )
  239. {
  240. char *result;
  241. const char *xdg_data_home;
  242. const char *xdg_data_dirs;
  243. const char *ptr;
  244. xdg_data_home = getenv ("XDG_DATA_HOME");
  245. if (xdg_data_home)
  246. {
  247. result = file_exists( xdg_data_home, f );
  248. if (result)
  249. return result;
  250. }
  251. else
  252. {
  253. const char *home;
  254. home = getenv ("HOME");
  255. if (home != NULL)
  256. {
  257. char *guessed_xdg_home;
  258. guessed_xdg_home = my_malloc (strlen (home) + strlen ("/.local/share/") + 1);
  259. if( !guessed_xdg_home )
  260. return 0;
  261. strcpy (guessed_xdg_home, home);
  262. strcat (guessed_xdg_home, "/.local/share/");
  263. result = file_exists( guessed_xdg_home, f );
  264. free (guessed_xdg_home);
  265. if (result)
  266. return result;
  267. }
  268. }
  269. xdg_data_dirs = getenv ("XDG_DATA_DIRS");
  270. if (xdg_data_dirs == NULL)
  271. xdg_data_dirs = "/usr/local/share/:/usr/share/";
  272. ptr = xdg_data_dirs;
  273. while (*ptr != '\000')
  274. {
  275. const char *end_ptr;
  276. char *dir;
  277. int len;
  278. end_ptr = ptr;
  279. while (*end_ptr != ':' && *end_ptr != '\000')
  280. end_ptr ++;
  281. if (end_ptr == ptr)
  282. {
  283. ptr++;
  284. continue;
  285. }
  286. if (*end_ptr == ':')
  287. len = end_ptr - ptr;
  288. else
  289. len = end_ptr - ptr + 1;
  290. dir = my_malloc (len + 1);
  291. if( !dir )
  292. return 0;
  293. strncpy (dir, ptr, len);
  294. dir[len] = '\0';
  295. result = file_exists( dir, f );
  296. free (dir);
  297. if (result)
  298. return result;
  299. ptr = end_ptr;
  300. }
  301. return 0;
  302. }
  303. /**
  304. Remove excessive whitespace from string. Replaces arbitrary sequence
  305. of whitespace with a single space. Also removes any leading and
  306. trailing whitespace
  307. */
  308. static char *munge( char *in )
  309. {
  310. char *out = my_malloc( strlen( in )+1 );
  311. char *p=out;
  312. int had_whitespace = 0;
  313. int printed = 0;
  314. if( !out )
  315. {
  316. return 0;
  317. }
  318. while( 1 )
  319. {
  320. // fprintf( stderr, "%c\n", *in );
  321. switch( *in )
  322. {
  323. case ' ':
  324. case '\n':
  325. case '\t':
  326. case '\r':
  327. {
  328. had_whitespace = 1;
  329. break;
  330. }
  331. case '\0':
  332. *p = '\0';
  333. return out;
  334. default:
  335. {
  336. if( printed && had_whitespace )
  337. {
  338. *(p++)=' ';
  339. }
  340. printed=1;
  341. had_whitespace=0;
  342. *(p++)=*in;
  343. break;
  344. }
  345. }
  346. in++;
  347. }
  348. fprintf( stderr, _( "%s: Unknown error in munge()\n"), MIMEDB );
  349. error=1;
  350. return 0;
  351. }
  352. /**
  353. Return a regular expression that matches all strings specifying the current locale
  354. */
  355. static char *get_lang_re()
  356. {
  357. static char buff[BUFF_SIZE];
  358. const char *lang = setlocale( LC_MESSAGES, 0 );
  359. int close=0;
  360. char *out=buff;
  361. if( (1+strlen(lang)*4) >= BUFF_SIZE )
  362. {
  363. fprintf( stderr, _( "%s: Locale string too long\n"), MIMEDB );
  364. error = 1;
  365. return 0;
  366. }
  367. for( ; *lang; lang++ )
  368. {
  369. switch( *lang )
  370. {
  371. case '@':
  372. case '.':
  373. case '_':
  374. if( close )
  375. {
  376. *out++ = ')';
  377. *out++ = '?';
  378. }
  379. close=1;
  380. *out++ = '(';
  381. *out++ = *lang;
  382. break;
  383. default:
  384. *out++ = *lang;
  385. }
  386. }
  387. if( close )
  388. {
  389. *out++ = ')';
  390. *out++ = '?';
  391. }
  392. *out++=0;
  393. return buff;
  394. }
  395. /**
  396. Get description for a specified mimetype.
  397. */
  398. static char *get_description( const char *mimetype )
  399. {
  400. char *fn_part;
  401. char *fn;
  402. int fd;
  403. struct stat st;
  404. char *contents;
  405. char *start=0, *stop=0;
  406. if( !start_re )
  407. {
  408. char *lang;
  409. char buff[BUFF_SIZE];
  410. lang = get_lang_re();
  411. if( !lang )
  412. return 0;
  413. snprintf( buff, BUFF_SIZE, START_TAG, lang, lang );
  414. start_re = my_malloc( sizeof(regex_t));
  415. stop_re = my_malloc( sizeof(regex_t));
  416. int reg_status;
  417. if( ( reg_status = regcomp( start_re, buff, REG_EXTENDED ) ) )
  418. {
  419. char regerrbuf[BUFF_SIZE];
  420. regerror(reg_status, start_re, regerrbuf, BUFF_SIZE);
  421. fprintf( stderr, _( "%s: Could not compile regular expressions %s with error %s\n"), MIMEDB, buff, regerrbuf);
  422. error=1;
  423. }
  424. else if ( ( reg_status = regcomp( stop_re, STOP_TAG, REG_EXTENDED ) ) )
  425. {
  426. char regerrbuf[BUFF_SIZE];
  427. regerror(reg_status, stop_re, regerrbuf, BUFF_SIZE);
  428. fprintf( stderr, _( "%s: Could not compile regular expressions %s with error %s\n"), MIMEDB, buff, regerrbuf);
  429. error=1;
  430. }
  431. if( error )
  432. {
  433. free( start_re );
  434. free( stop_re );
  435. start_re = stop_re = 0;
  436. return 0;
  437. }
  438. }
  439. fn_part = my_malloc( strlen(MIME_DIR) + strlen( mimetype) + strlen(MIME_SUFFIX) + 1 );
  440. if( !fn_part )
  441. {
  442. return 0;
  443. }
  444. strcpy( fn_part, MIME_DIR );
  445. strcat( fn_part, mimetype );
  446. strcat( fn_part, MIME_SUFFIX );
  447. fn = get_filename(fn_part); //malloc( strlen(MIME_DIR) +strlen( MIME_SUFFIX)+ strlen( mimetype ) + 1 );
  448. free(fn_part );
  449. if( !fn )
  450. {
  451. return 0;
  452. }
  453. fd = open( fn, O_RDONLY );
  454. // fprintf( stderr, "%s\n", fn );
  455. if( fd == -1 )
  456. {
  457. perror( "open" );
  458. error=1;
  459. return 0;
  460. }
  461. if( stat( fn, &st) )
  462. {
  463. perror( "stat" );
  464. error=1;
  465. return 0;
  466. }
  467. contents = my_malloc( st.st_size + 1 );
  468. if( !contents )
  469. {
  470. return 0;
  471. }
  472. if( read( fd, contents, st.st_size ) != st.st_size )
  473. {
  474. perror( "read" );
  475. error=1;
  476. return 0;
  477. }
  478. /*
  479. Don't need to check exit status of close on read-only file descriptors
  480. */
  481. close( fd );
  482. free( fn );
  483. contents[st.st_size]=0;
  484. regmatch_t match[1];
  485. int w = -1;
  486. start=contents;
  487. /*
  488. On multiple matches, use the longest match, should be a pretty
  489. good heuristic for best match...
  490. */
  491. while( !regexec(start_re, start, 1, match, 0) )
  492. {
  493. int new_w = match[0].rm_eo - match[0].rm_so;
  494. if( new_w > w )
  495. {
  496. /*
  497. New match is for a longer match then the previous
  498. match, so we use the new match
  499. */
  500. w=new_w;
  501. start += match[0].rm_eo;
  502. }
  503. }
  504. if( w != -1 )
  505. {
  506. if( !regexec(stop_re, start, 1, match, 0) )
  507. {
  508. /*
  509. We've found the beginning and the end of a suitable description
  510. */
  511. char *res;
  512. stop = start + match[0].rm_so;
  513. *stop = '\0';
  514. res = munge( start );
  515. free( contents );
  516. return res;
  517. }
  518. }
  519. free( contents );
  520. fprintf( stderr, _( "%s: No description for type %s\n"), MIMEDB, mimetype );
  521. error=1;
  522. return 0;
  523. }
  524. /**
  525. Get default action for a specified mimetype.
  526. */
  527. static char *get_action( const char *mimetype )
  528. {
  529. char *res=0;
  530. char *launcher;
  531. char *end;
  532. char *mime_filename;
  533. char *launcher_str;
  534. char *launcher_filename, *launcher_command_str, *launcher_command;
  535. char *launcher_full;
  536. mime_filename = get_filename( DESKTOP_DEFAULT );
  537. if( !mime_filename )
  538. return 0;
  539. launcher_str = search_ini( mime_filename, mimetype );
  540. free( mime_filename );
  541. if( !launcher_str )
  542. {
  543. /*
  544. This type does not have a launcher. Try the supertype!
  545. */
  546. // fprintf( stderr, "mimedb: %s does not have launcher, try supertype\n", mimetype );
  547. const char ** parents = xdg_mime_get_mime_parents(mimetype);
  548. const char **p;
  549. if( parents )
  550. {
  551. for( p=parents; *p; p++ )
  552. {
  553. char *a = get_action(*p);
  554. if( a != 0 )
  555. return a;
  556. }
  557. }
  558. /*
  559. Just in case subclassing doesn't work, (It doesn't on Fedora
  560. Core 3) we also test some common subclassings.
  561. */
  562. if( strncmp( mimetype, "text/", 5 ) == 0 )
  563. return get_action( "text/plain" );
  564. return 0;
  565. }
  566. // fprintf( stderr, "WOOT %s\n", launcher_str );
  567. launcher = strchr( launcher_str, '=' );
  568. if( !launcher )
  569. {
  570. fprintf( stderr, _("%s: Could not parse launcher string '%s'\n"), MIMEDB, launcher_str );
  571. error=1;
  572. return 0;
  573. }
  574. /* Skip the = */
  575. launcher++;
  576. /* Only use first launcher */
  577. end = strchr( launcher, ';' );
  578. if( end )
  579. *end = '\0';
  580. launcher_full = my_malloc( strlen( launcher) + strlen( APPLICATIONS_DIR)+1 );
  581. if( !launcher_full )
  582. {
  583. free( launcher_str );
  584. return 0;
  585. }
  586. strcpy( launcher_full, APPLICATIONS_DIR );
  587. strcat( launcher_full, launcher );
  588. free( launcher_str );
  589. launcher_filename = get_filename( launcher_full );
  590. free( launcher_full );
  591. launcher_command_str = search_ini( launcher_filename, "Exec=" );
  592. if( !launcher_command_str )
  593. {
  594. fprintf( stderr,
  595. _( "%s: Default launcher '%s' does not specify how to start\n"), MIMEDB,
  596. launcher_filename );
  597. free( launcher_filename );
  598. return 0;
  599. }
  600. free( launcher_filename );
  601. launcher_command = strchr( launcher_command_str, '=' );
  602. launcher_command++;
  603. res = my_strdup( launcher_command );
  604. free( launcher_command_str );
  605. return res;
  606. }
  607. /**
  608. Helper function for launch. Write the specified byte to the string we will execute
  609. */
  610. static void writer( char c )
  611. {
  612. if( launch_len == -1 )
  613. return;
  614. if( launch_len <= launch_pos )
  615. {
  616. int new_len = launch_len?2*launch_len:256;
  617. char *new_buff = realloc( launch_buff, new_len );
  618. if( !new_buff )
  619. {
  620. free( launch_buff );
  621. launch_len = -1;
  622. error=1;
  623. return;
  624. }
  625. launch_buff = new_buff;
  626. launch_len = new_len;
  627. }
  628. launch_buff[launch_pos++]=c;
  629. }
  630. /**
  631. Write out the specified byte in hex
  632. */
  633. static void writer_hex( int num )
  634. {
  635. int a, b;
  636. a = num /16;
  637. b = num %16;
  638. writer( a>9?('A'+a-10):('0'+a));
  639. writer( b>9?('A'+b-10):('0'+b));
  640. }
  641. /**
  642. Return current directory in newly allocated string
  643. */
  644. static char *my_getcwd ()
  645. {
  646. size_t size = 100;
  647. while (1)
  648. {
  649. char *buffer = (char *) malloc (size);
  650. if (getcwd (buffer, size) == buffer)
  651. return buffer;
  652. free (buffer);
  653. if (errno != ERANGE)
  654. return 0;
  655. size *= 2;
  656. }
  657. }
  658. /**
  659. Return absolute filename of specified file
  660. */
  661. static char *get_fullfile( char *file )
  662. {
  663. char *fullfile;
  664. if( file[0] == '/' )
  665. {
  666. fullfile = file;
  667. }
  668. else
  669. {
  670. char *cwd = my_getcwd();
  671. if( !cwd )
  672. {
  673. error = 1;
  674. perror( "getcwd" );
  675. return 0;
  676. }
  677. int l = strlen(cwd);
  678. fullfile = my_malloc( l + strlen(file)+2 );
  679. if( !fullfile )
  680. {
  681. free(cwd);
  682. return 0;
  683. }
  684. strcpy( fullfile, cwd );
  685. if( cwd[l-1] != '/' )
  686. strcat(fullfile, "/" );
  687. strcat( fullfile, file );
  688. free(cwd);
  689. }
  690. return fullfile;
  691. }
  692. /**
  693. Write specified file as an URL
  694. */
  695. static void write_url( char *file )
  696. {
  697. char *fullfile = get_fullfile( file );
  698. char *str = fullfile;
  699. if( str == 0 )
  700. {
  701. launch_len = -1;
  702. return;
  703. }
  704. writer( 'f');
  705. writer( 'i');
  706. writer( 'l');
  707. writer( 'e');
  708. writer( ':');
  709. writer( '/');
  710. writer( '/');
  711. while( *str )
  712. {
  713. if( ((*str >= 'a') && (*str <='z')) ||
  714. ((*str >= 'A') && (*str <='Z')) ||
  715. ((*str >= '0') && (*str <='9')) ||
  716. (strchr( "-_.~/",*str) != 0) )
  717. {
  718. writer(*str);
  719. }
  720. else if(strchr( "()?&=",*str) != 0)
  721. {
  722. writer('\\');
  723. writer(*str);
  724. }
  725. else
  726. {
  727. writer( '%' );
  728. writer_hex( (unsigned char)*str );
  729. }
  730. str++;
  731. }
  732. if( fullfile != file )
  733. free( fullfile );
  734. }
  735. /**
  736. Write specified file
  737. */
  738. static void write_file( char *file, int print_path )
  739. {
  740. char *fullfile;
  741. char *str;
  742. if( print_path )
  743. {
  744. fullfile = get_fullfile( file );
  745. str = fullfile;
  746. }
  747. else
  748. {
  749. fullfile = my_strdup( file );
  750. if( !fullfile )
  751. {
  752. return;
  753. }
  754. str = basename( fullfile );
  755. }
  756. if( !str )
  757. {
  758. error = 1;
  759. return;
  760. }
  761. while( *str )
  762. {
  763. switch(*str )
  764. {
  765. case ')':
  766. case '(':
  767. case '-':
  768. case '#':
  769. case '$':
  770. case '}':
  771. case '{':
  772. case ']':
  773. case '[':
  774. case '*':
  775. case '?':
  776. case ' ':
  777. case '|':
  778. case '<':
  779. case '>':
  780. case '^':
  781. case '&':
  782. case '\\':
  783. case '`':
  784. case '\'':
  785. case '\"':
  786. writer('\\');
  787. writer(*str);
  788. break;
  789. case '\n':
  790. writer('\\');
  791. writer('n');
  792. break;
  793. case '\r':
  794. writer('\\');
  795. writer('r');
  796. break;
  797. case '\t':
  798. writer('\\');
  799. writer('t');
  800. break;
  801. case '\b':
  802. writer('\\');
  803. writer('b');
  804. break;
  805. case '\v':
  806. writer('\\');
  807. writer('v');
  808. break;
  809. default:
  810. writer(*str);
  811. break;
  812. }
  813. str++;
  814. }
  815. if( fullfile != file )
  816. free( fullfile );
  817. }
  818. /**
  819. Use the specified launch filter to launch all the files in the specified list.
  820. \param filter the action to take
  821. \param files the list of files for which to perform the action
  822. \param fileno an internal value. Should always be set to zero.
  823. */
  824. static void launch( char *filter, array_list_t *files, int fileno )
  825. {
  826. char *filter_org=filter;
  827. int count=0;
  828. int launch_again=0;
  829. if( al_get_count( files ) <= fileno )
  830. return;
  831. launch_pos=0;
  832. for( ;*filter && !error; filter++)
  833. {
  834. if(*filter == '%')
  835. {
  836. filter++;
  837. switch( *filter )
  838. {
  839. case 'u':
  840. {
  841. launch_again = 1;
  842. write_url( (char *)al_get( files, fileno ) );
  843. break;
  844. }
  845. case 'U':
  846. {
  847. int i;
  848. for( i=0; i<al_get_count( files ); i++ )
  849. {
  850. if( i != 0 )
  851. writer( ' ' );
  852. write_url( (char *)al_get( files, i ) );
  853. if( error )
  854. break;
  855. }
  856. break;
  857. }
  858. case 'f':
  859. case 'n':
  860. {
  861. launch_again = 1;
  862. write_file( (char *)al_get( files, fileno ), *filter == 'f' );
  863. break;
  864. }
  865. case 'F':
  866. case 'N':
  867. {
  868. int i;
  869. for( i=0; i<al_get_count( files ); i++ )
  870. {
  871. if( i != 0 )
  872. writer( ' ' );
  873. write_file( (char *)al_get( files, i ), *filter == 'F' );
  874. if( error )
  875. break;
  876. }
  877. break;
  878. }
  879. case 'd':
  880. {
  881. char *cpy = get_fullfile( (char *)al_get( files, fileno ) );
  882. char *dir;
  883. launch_again=1;
  884. /*
  885. We wish to modify this string, make sure it is only a copy
  886. */
  887. if( cpy == al_get( files, fileno ) )
  888. cpy = my_strdup( cpy );
  889. if( cpy == 0 )
  890. {
  891. break;
  892. }
  893. dir=dirname( cpy );
  894. write_file( dir, 1 );
  895. free( cpy );
  896. break;
  897. }
  898. case 'D':
  899. {
  900. int i;
  901. for( i=0; i<al_get_count( files ); i++ )
  902. {
  903. char *cpy = get_fullfile( (char *)al_get( files, i ) );
  904. char *dir;
  905. /*
  906. We wish to modify this string, make sure it is only a copy
  907. */
  908. if( cpy == al_get( files, i ) )
  909. cpy = my_strdup( cpy );
  910. if( cpy == 0 )
  911. {
  912. break;
  913. }
  914. dir=dirname( cpy );
  915. if( i != 0 )
  916. writer( ' ' );
  917. write_file( dir, 1 );
  918. free( cpy );
  919. }
  920. break;
  921. }
  922. default:
  923. fprintf( stderr, _("%s: Unsupported switch '%c' in launch string '%s'\n"), MIMEDB, *filter, filter_org );
  924. launch_len=0;
  925. break;
  926. }
  927. }
  928. else
  929. {
  930. writer( *filter );
  931. count++;
  932. }
  933. }
  934. if( error )
  935. return;
  936. switch( launch_len )
  937. {
  938. case -1:
  939. {
  940. launch_len = 0;
  941. fprintf( stderr, _( "%s: Out of memory\n"), MIMEDB );
  942. return;
  943. }
  944. case 0:
  945. {
  946. return;
  947. }
  948. default:
  949. {
  950. writer( ' ' );
  951. writer( '&' );
  952. writer( '\0' );
  953. // fprintf( stderr, "mimedb: %s\n", launch_buff );
  954. system( launch_buff );
  955. break;
  956. }
  957. }
  958. if( launch_again )
  959. {
  960. launch( filter_org, files, fileno+1 );
  961. }
  962. }
  963. /**
  964. Clean up one entry from the hash table of launch files
  965. */
  966. static void clear_entry( void *key, void *val )
  967. {
  968. /*
  969. The key is a mime value, either from the libraries internal hash
  970. table of mime types or from the command line. Either way, it
  971. should not be freed.
  972. The value is an array_list_t of filenames. The filenames com from
  973. the argument list and should not be freed. The arraylist,
  974. however, should be destroyed and freed.
  975. */
  976. array_list_t *l = (array_list_t *)val;
  977. al_destroy( l );
  978. free( l );
  979. }
  980. /**
  981. Do locale specific init
  982. */
  983. static void locale_init()
  984. {
  985. setlocale( LC_ALL, "" );
  986. bindtextdomain( PACKAGE_NAME, LOCALEDIR );
  987. textdomain( PACKAGE_NAME );
  988. }
  989. /**
  990. Main function. Parses options and calls helper function for any heavy lifting.
  991. */
  992. int main (int argc, char *argv[])
  993. {
  994. int input_type=FILEDATA;
  995. int output_type=MIMETYPE;
  996. const char *mimetype;
  997. char *output=0;
  998. int i;
  999. hash_table_t launch_hash;
  1000. locale_init();
  1001. /*
  1002. Parse options
  1003. */
  1004. while( 1 )
  1005. {
  1006. static struct option
  1007. long_options[] =
  1008. {
  1009. {
  1010. "input-file-data", no_argument, 0, 't'
  1011. }
  1012. ,
  1013. {
  1014. "input-filename", no_argument, 0, 'f'
  1015. }
  1016. ,
  1017. {
  1018. "input-mime", no_argument, 0, 'i'
  1019. }
  1020. ,
  1021. {
  1022. "output-mime", no_argument, 0, 'm'
  1023. }
  1024. ,
  1025. {
  1026. "output-description", no_argument, 0, 'd'
  1027. }
  1028. ,
  1029. {
  1030. "output-action", no_argument, 0, 'a'
  1031. }
  1032. ,
  1033. {
  1034. "help", no_argument, 0, 'h'
  1035. }
  1036. ,
  1037. {
  1038. "version", no_argument, 0, 'v'
  1039. }
  1040. ,
  1041. {
  1042. "launch", no_argument, 0, 'l'
  1043. }
  1044. ,
  1045. {
  1046. 0, 0, 0, 0
  1047. }
  1048. }
  1049. ;
  1050. int opt_index = 0;
  1051. int opt = getopt_long( argc,
  1052. argv,
  1053. GETOPT_STRING,
  1054. long_options,
  1055. &opt_index );
  1056. if( opt == -1 )
  1057. break;
  1058. switch( opt )
  1059. {
  1060. case 0:
  1061. break;
  1062. case 't':
  1063. input_type=FILEDATA;
  1064. break;
  1065. case 'f':
  1066. input_type=FILENAME;
  1067. break;
  1068. case 'i':
  1069. input_type=MIMETYPE;
  1070. break;
  1071. case 'm':
  1072. output_type=MIMETYPE;
  1073. break;
  1074. case 'd':
  1075. output_type=DESCRIPTION;
  1076. break;
  1077. case 'a':
  1078. output_type=ACTION;
  1079. break;
  1080. case 'l':
  1081. output_type=LAUNCH;
  1082. break;
  1083. case 'h':
  1084. print_help( argv[0], 1 );
  1085. exit(0);
  1086. case 'v':
  1087. printf( _("%s, version %s\n"), MIMEDB, PACKAGE_VERSION );
  1088. exit( 0 );
  1089. case '?':
  1090. return 1;
  1091. }
  1092. }
  1093. if( ( output_type == LAUNCH )&&(input_type==MIMETYPE))
  1094. {
  1095. fprintf( stderr, _("%s: Can not launch a mimetype\n"), MIMEDB );
  1096. print_help( argv[0], 2 );
  1097. exit(1);
  1098. }
  1099. if( output_type == LAUNCH )
  1100. hash_init( &launch_hash, &hash_str_func, &hash_str_cmp );
  1101. /*
  1102. Loop over all non option arguments and do the specified lookup
  1103. */
  1104. //fprintf( stderr, "Input %d, output %d\n", input_type, output_type );
  1105. for (i = optind; (i < argc)&&(!error); i++)
  1106. {
  1107. /* Convert from filename to mimetype, if needed */
  1108. if( input_type == FILENAME )
  1109. {
  1110. mimetype = xdg_mime_get_mime_type_from_file_name(argv[i]);
  1111. }
  1112. else if( input_type == FILEDATA )
  1113. {
  1114. mimetype = xdg_mime_get_mime_type_for_file(argv[i]);
  1115. }
  1116. else
  1117. mimetype = xdg_mime_is_valid_mime_type(argv[i])?argv[i]:0;
  1118. mimetype = xdg_mime_unalias_mime_type (mimetype);
  1119. if( !mimetype )
  1120. {
  1121. fprintf( stderr, _( "%s: Could not parse mimetype from argument '%s'\n"), MIMEDB, argv[i] );
  1122. error=1;
  1123. return 1;
  1124. }
  1125. /*
  1126. Convert from mimetype to whatever, if needed
  1127. */
  1128. switch( output_type )
  1129. {
  1130. case MIMETYPE:
  1131. {
  1132. output = (char *)mimetype;
  1133. break;
  1134. }
  1135. case DESCRIPTION:
  1136. {
  1137. output = get_description( mimetype );
  1138. if( !output )
  1139. output = strdup( _("Unknown") );
  1140. break;
  1141. }
  1142. case ACTION:
  1143. {
  1144. output = get_action( mimetype );
  1145. break;
  1146. }
  1147. case LAUNCH:
  1148. {
  1149. /*
  1150. There may be more files using the same launcher, we
  1151. add them all up in little array_list_ts and launched
  1152. them together after all the arguments have been
  1153. parsed.
  1154. */
  1155. array_list_t *l= (array_list_t *)hash_get( &launch_hash, mimetype );
  1156. output = 0;
  1157. if( !l )
  1158. {
  1159. l = my_malloc( sizeof( array_list_t ) );
  1160. if( l == 0 )
  1161. {
  1162. break;
  1163. }
  1164. al_init( l );
  1165. hash_put( &launch_hash, mimetype, l );
  1166. }
  1167. al_push( l, argv[i] );
  1168. }
  1169. }
  1170. /*
  1171. Print the glorious result
  1172. */
  1173. if( output )
  1174. {
  1175. printf( "%s\n", output );
  1176. if( output != mimetype )
  1177. free( output );
  1178. }
  1179. output = 0;
  1180. }
  1181. /*
  1182. Perform the actual launching
  1183. */
  1184. if( output_type == LAUNCH && !error )
  1185. {
  1186. int i;
  1187. array_list_t mimes;
  1188. al_init( &mimes );
  1189. hash_get_keys( &launch_hash, &mimes );
  1190. for( i=0; i<al_get_count( &mimes ); i++ )
  1191. {
  1192. char *mimetype = (char *)al_get( &mimes, i );
  1193. array_list_t *files = (array_list_t *)hash_get( &launch_hash, mimetype );
  1194. if( !files )
  1195. {
  1196. fprintf( stderr, _( "%s: Unknown error\n"), MIMEDB );
  1197. error=1;
  1198. break;
  1199. }
  1200. char *launcher = get_action( mimetype );
  1201. if( launcher )
  1202. {
  1203. launch( launcher, files, 0 );
  1204. free( launcher );
  1205. }
  1206. }
  1207. hash_foreach( &launch_hash, &clear_entry );
  1208. hash_destroy( &launch_hash );
  1209. al_destroy( &mimes );
  1210. }
  1211. if( launch_buff )
  1212. free( launch_buff );
  1213. if( start_re )
  1214. {
  1215. regfree( start_re );
  1216. regfree( stop_re );
  1217. free( start_re );
  1218. free( stop_re );
  1219. }
  1220. xdg_mime_shutdown();
  1221. return error;
  1222. }