gnunet-search.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file fs/gnunet-search.c
  19. * @brief searching for files on GNUnet
  20. * @author Christian Grothoff
  21. * @author Krista Bennett
  22. * @author James Blackwell
  23. * @author Igor Wronsky
  24. */
  25. #include "platform.h"
  26. #include "gnunet_fs_service.h"
  27. static int ret;
  28. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  29. static struct GNUNET_FS_Handle *ctx;
  30. static struct GNUNET_FS_SearchContext *sc;
  31. static char *output_filename;
  32. static struct GNUNET_FS_DirectoryBuilder *db;
  33. static unsigned int anonymity = 1;
  34. /**
  35. * Timeout for the search, 0 means to wait for CTRL-C.
  36. */
  37. static struct GNUNET_TIME_Relative timeout;
  38. static unsigned int results_limit;
  39. static unsigned int results;
  40. static int verbose;
  41. static int local_only;
  42. /**
  43. * Type of a function that libextractor calls for each
  44. * meta data item found.
  45. *
  46. * @param cls closure (user-defined, unused)
  47. * @param plugin_name name of the plugin that produced this value;
  48. * special values can be used (i.e. '<zlib>' for zlib being
  49. * used in the main libextractor library and yielding
  50. * meta data).
  51. * @param type libextractor-type describing the meta data
  52. * @param format basic format information about data
  53. * @param data_mime_type mime-type of data (not of the original file);
  54. * can be NULL (if mime-type is not known)
  55. * @param data actual meta-data found
  56. * @param data_size number of bytes in data
  57. * @return 0 to continue extracting, 1 to abort
  58. */
  59. static int
  60. item_printer (void *cls, const char *plugin_name, enum EXTRACTOR_MetaType type,
  61. enum EXTRACTOR_MetaFormat format, const char *data_mime_type,
  62. const char *data, size_t data_size)
  63. {
  64. if ((format != EXTRACTOR_METAFORMAT_UTF8) &&
  65. (format != EXTRACTOR_METAFORMAT_C_STRING))
  66. return 0;
  67. if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME)
  68. return 0;
  69. printf ("\t%20s: %s\n",
  70. dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN,
  71. EXTRACTOR_metatype_to_string (type)), data);
  72. return 0;
  73. }
  74. static void
  75. clean_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  76. {
  77. size_t dsize;
  78. void *ddata;
  79. GNUNET_FS_stop (ctx);
  80. ctx = NULL;
  81. if (output_filename == NULL)
  82. return;
  83. if (GNUNET_OK != GNUNET_FS_directory_builder_finish (db, &dsize, &ddata))
  84. {
  85. GNUNET_break (0);
  86. GNUNET_free (output_filename);
  87. return;
  88. }
  89. if (dsize !=
  90. GNUNET_DISK_fn_write (output_filename, ddata, dsize,
  91. GNUNET_DISK_PERM_USER_READ |
  92. GNUNET_DISK_PERM_USER_WRITE))
  93. {
  94. FPRINTF (stderr,
  95. _("Failed to write directory with search results to `%s'\n"),
  96. output_filename);
  97. }
  98. GNUNET_free_non_null (ddata);
  99. GNUNET_free (output_filename);
  100. }
  101. /**
  102. * Called by FS client to give information about the progress of an
  103. * operation.
  104. *
  105. * @param cls closure
  106. * @param info details about the event, specifying the event type
  107. * and various bits about the event
  108. * @return client-context (for the next progress call
  109. * for this operation; should be set to NULL for
  110. * SUSPEND and STOPPED events). The value returned
  111. * will be passed to future callbacks in the respective
  112. * field in the GNUNET_FS_ProgressInfo struct.
  113. */
  114. static void *
  115. progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
  116. {
  117. static unsigned int cnt;
  118. int is_directory;
  119. char *uri;
  120. char *filename;
  121. switch (info->status)
  122. {
  123. case GNUNET_FS_STATUS_SEARCH_START:
  124. break;
  125. case GNUNET_FS_STATUS_SEARCH_RESULT:
  126. if (db != NULL)
  127. GNUNET_FS_directory_builder_add (db,
  128. info->value.search.specifics.result.uri,
  129. info->value.search.specifics.result.meta,
  130. NULL);
  131. uri = GNUNET_FS_uri_to_string (info->value.search.specifics.result.uri);
  132. printf ("#%u:\n", cnt++);
  133. filename =
  134. GNUNET_CONTAINER_meta_data_get_by_type (info->value.search.
  135. specifics.result.meta,
  136. EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
  137. is_directory =
  138. GNUNET_FS_meta_data_test_for_directory (info->value.search.
  139. specifics.result.meta);
  140. if (filename != NULL)
  141. {
  142. GNUNET_DISK_filename_canonicalize (filename);
  143. if (GNUNET_YES == is_directory)
  144. printf ("gnunet-download -o \"%s%s\" -R %s\n", filename, GNUNET_FS_DIRECTORY_EXT, uri);
  145. else
  146. printf ("gnunet-download -o \"%s\" %s\n", filename, uri);
  147. }
  148. else if (GNUNET_YES == is_directory)
  149. printf ("gnunet-download -o \"collection%s\" -R %s\n", GNUNET_FS_DIRECTORY_EXT, uri);
  150. else
  151. printf ("gnunet-download %s\n", uri);
  152. if (verbose)
  153. GNUNET_CONTAINER_meta_data_iterate (info->value.search.specifics.
  154. result.meta, &item_printer, NULL);
  155. printf ("\n");
  156. fflush (stdout);
  157. GNUNET_free_non_null (filename);
  158. GNUNET_free (uri);
  159. results++;
  160. if ((results_limit > 0) && (results >= results_limit))
  161. GNUNET_SCHEDULER_shutdown ();
  162. break;
  163. case GNUNET_FS_STATUS_SEARCH_UPDATE:
  164. break;
  165. case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
  166. /* ignore */
  167. break;
  168. case GNUNET_FS_STATUS_SEARCH_ERROR:
  169. FPRINTF (stderr, _("Error searching: %s.\n"),
  170. info->value.search.specifics.error.message);
  171. GNUNET_SCHEDULER_shutdown ();
  172. break;
  173. case GNUNET_FS_STATUS_SEARCH_STOPPED:
  174. GNUNET_SCHEDULER_add_continuation (&clean_task, NULL,
  175. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  176. break;
  177. default:
  178. FPRINTF (stderr, _("Unexpected status: %d\n"), info->status);
  179. break;
  180. }
  181. return NULL;
  182. }
  183. static void
  184. shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  185. {
  186. if (sc != NULL)
  187. {
  188. GNUNET_FS_search_stop (sc);
  189. sc = NULL;
  190. }
  191. }
  192. /**
  193. * Main function that will be run by the scheduler.
  194. *
  195. * @param cls closure
  196. * @param args remaining command-line arguments
  197. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  198. * @param c configuration
  199. */
  200. static void
  201. run (void *cls, char *const *args, const char *cfgfile,
  202. const struct GNUNET_CONFIGURATION_Handle *c)
  203. {
  204. struct GNUNET_FS_Uri *uri;
  205. unsigned int argc;
  206. enum GNUNET_FS_SearchOptions options;
  207. argc = 0;
  208. while (NULL != args[argc])
  209. argc++;
  210. uri = GNUNET_FS_uri_ksk_create_from_args (argc, (const char **) args);
  211. if (NULL == uri)
  212. {
  213. FPRINTF (stderr, "%s", _("Could not create keyword URI from arguments.\n"));
  214. ret = 1;
  215. return;
  216. }
  217. cfg = c;
  218. ctx =
  219. GNUNET_FS_start (cfg, "gnunet-search", &progress_cb, NULL,
  220. GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END);
  221. if (NULL == ctx)
  222. {
  223. FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS");
  224. GNUNET_FS_uri_destroy (uri);
  225. ret = 1;
  226. return;
  227. }
  228. if (output_filename != NULL)
  229. db = GNUNET_FS_directory_builder_create (NULL);
  230. options = GNUNET_FS_SEARCH_OPTION_NONE;
  231. if (local_only)
  232. options |= GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY;
  233. sc = GNUNET_FS_search_start (ctx, uri, anonymity, options, NULL);
  234. GNUNET_FS_uri_destroy (uri);
  235. if (NULL == sc)
  236. {
  237. FPRINTF (stderr, "%s", _("Could not start searching.\n"));
  238. GNUNET_FS_stop (ctx);
  239. ret = 1;
  240. return;
  241. }
  242. if (0 != timeout.rel_value_us)
  243. GNUNET_SCHEDULER_add_delayed (timeout, &shutdown_task, NULL);
  244. else
  245. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
  246. NULL);
  247. }
  248. /**
  249. * The main function to search GNUnet.
  250. *
  251. * @param argc number of arguments from the command line
  252. * @param argv command line arguments
  253. * @return 0 ok, 1 on error
  254. */
  255. int
  256. main (int argc, char *const *argv)
  257. {
  258. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  259. {'a', "anonymity", "LEVEL",
  260. gettext_noop ("set the desired LEVEL of receiver-anonymity"),
  261. 1, &GNUNET_GETOPT_set_uint, &anonymity},
  262. {'n', "no-network", NULL,
  263. gettext_noop ("only search the local peer (no P2P network search)"),
  264. 0, &GNUNET_GETOPT_set_one, &local_only},
  265. {'o', "output", "PREFIX",
  266. gettext_noop ("write search results to file starting with PREFIX"),
  267. 1, &GNUNET_GETOPT_set_string, &output_filename},
  268. {'t', "timeout", "DELAY",
  269. gettext_noop ("automatically terminate search after DELAY"),
  270. 1, &GNUNET_GETOPT_set_relative_time, &timeout},
  271. {'V', "verbose", NULL,
  272. gettext_noop ("be verbose (print progress information)"),
  273. 0, &GNUNET_GETOPT_set_one, &verbose},
  274. {'N', "results", "VALUE",
  275. gettext_noop
  276. ("automatically terminate search after VALUE results are found"),
  277. 1, &GNUNET_GETOPT_set_uint, &results_limit},
  278. GNUNET_GETOPT_OPTION_END
  279. };
  280. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  281. return 2;
  282. ret = (GNUNET_OK ==
  283. GNUNET_PROGRAM_run (argc, argv, "gnunet-search [OPTIONS] KEYWORD",
  284. gettext_noop
  285. ("Search GNUnet for files that were published on GNUnet"),
  286. options, &run, NULL)) ? ret : 1;
  287. GNUNET_free ((void*) argv);
  288. return ret;
  289. }
  290. /* end of gnunet-search.c */