gnunet-search.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your 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. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file fs/gnunet-search.c
  18. * @brief searching for files on GNUnet
  19. * @author Christian Grothoff
  20. * @author Krista Bennett
  21. * @author James Blackwell
  22. * @author Igor Wronsky
  23. */
  24. #include "platform.h"
  25. #include "gnunet_fs_service.h"
  26. static int ret;
  27. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  28. static struct GNUNET_FS_Handle *ctx;
  29. static struct GNUNET_FS_SearchContext *sc;
  30. static char *output_filename;
  31. static struct GNUNET_FS_DirectoryBuilder *db;
  32. static unsigned int anonymity = 1;
  33. /**
  34. * Timeout for the search, 0 means to wait for CTRL-C.
  35. */
  36. static struct GNUNET_TIME_Relative timeout;
  37. static unsigned int results_limit;
  38. static unsigned int results;
  39. static unsigned int verbose;
  40. static int local_only;
  41. static struct GNUNET_SCHEDULER_Task *tt;
  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. '&lt;zlib&gt;' 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 @a data
  57. * @return 0 to continue extracting, 1 to abort
  58. */
  59. static int
  60. item_printer (void *cls,
  61. const char *plugin_name,
  62. enum EXTRACTOR_MetaType type,
  63. enum EXTRACTOR_MetaFormat format,
  64. const char *data_mime_type,
  65. const char *data,
  66. size_t data_size)
  67. {
  68. if ((format != EXTRACTOR_METAFORMAT_UTF8) &&
  69. (format != EXTRACTOR_METAFORMAT_C_STRING))
  70. return 0;
  71. if (type == EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME)
  72. return 0;
  73. #if HAVE_LIBEXTRACTOR
  74. printf ("\t%20s: %s\n",
  75. dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN,
  76. EXTRACTOR_metatype_to_string (type)),
  77. data);
  78. #else
  79. printf ("\t%20d: %s\n", type, data);
  80. #endif
  81. return 0;
  82. }
  83. static void
  84. clean_task (void *cls)
  85. {
  86. size_t dsize;
  87. void *ddata;
  88. GNUNET_FS_stop (ctx);
  89. ctx = NULL;
  90. if (output_filename == NULL)
  91. return;
  92. if (GNUNET_OK !=
  93. GNUNET_FS_directory_builder_finish (db, &dsize, &ddata))
  94. {
  95. GNUNET_break (0);
  96. GNUNET_free (output_filename);
  97. return;
  98. }
  99. (void) GNUNET_DISK_directory_remove (output_filename);
  100. if (GNUNET_OK !=
  101. GNUNET_DISK_fn_write (output_filename,
  102. ddata,
  103. dsize,
  104. GNUNET_DISK_PERM_USER_READ
  105. | GNUNET_DISK_PERM_USER_WRITE))
  106. {
  107. fprintf (stderr,
  108. _ ("Failed to write directory with search results to `%s'\n"),
  109. output_filename);
  110. }
  111. GNUNET_free (ddata);
  112. GNUNET_free (output_filename);
  113. }
  114. /**
  115. * Called by FS client to give information about the progress of an
  116. * operation.
  117. *
  118. * @param cls closure
  119. * @param info details about the event, specifying the event type
  120. * and various bits about the event
  121. * @return client-context (for the next progress call
  122. * for this operation; should be set to NULL for
  123. * SUSPEND and STOPPED events). The value returned
  124. * will be passed to future callbacks in the respective
  125. * field in the GNUNET_FS_ProgressInfo struct.
  126. */
  127. static void *
  128. progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
  129. {
  130. static unsigned int cnt;
  131. int is_directory;
  132. char *uri;
  133. char *filename;
  134. switch (info->status)
  135. {
  136. case GNUNET_FS_STATUS_SEARCH_START:
  137. break;
  138. case GNUNET_FS_STATUS_SEARCH_RESULT:
  139. if (db != NULL)
  140. GNUNET_FS_directory_builder_add (db,
  141. info->value.search.specifics.result.uri,
  142. info->value.search.specifics.result.meta,
  143. NULL);
  144. uri = GNUNET_FS_uri_to_string (info->value.search.specifics.result.uri);
  145. printf ("#%u:\n", ++cnt);
  146. filename = GNUNET_CONTAINER_meta_data_get_by_type (
  147. info->value.search.specifics.result.meta,
  148. EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
  149. is_directory = GNUNET_FS_meta_data_test_for_directory (
  150. info->value.search.specifics.result.meta);
  151. if (NULL != filename)
  152. {
  153. while ((filename[0] != '\0') && ('/' == filename[strlen (filename) - 1]))
  154. filename[strlen (filename) - 1] = '\0';
  155. GNUNET_DISK_filename_canonicalize (filename);
  156. if (GNUNET_YES == is_directory)
  157. printf ("gnunet-download -o \"%s%s\" -R %s\n",
  158. filename,
  159. GNUNET_FS_DIRECTORY_EXT,
  160. uri);
  161. else
  162. printf ("gnunet-download -o \"%s\" %s\n", filename, uri);
  163. }
  164. else if (GNUNET_YES == is_directory)
  165. printf ("gnunet-download -o \"collection%s\" -R %s\n",
  166. GNUNET_FS_DIRECTORY_EXT,
  167. uri);
  168. else
  169. printf ("gnunet-download %s\n", uri);
  170. if (verbose)
  171. GNUNET_CONTAINER_meta_data_iterate (info->value.search.specifics.result
  172. .meta,
  173. &item_printer,
  174. NULL);
  175. printf ("\n");
  176. fflush (stdout);
  177. GNUNET_free (filename);
  178. GNUNET_free (uri);
  179. results++;
  180. if ((results_limit > 0) && (results >= results_limit))
  181. GNUNET_SCHEDULER_shutdown ();
  182. break;
  183. case GNUNET_FS_STATUS_SEARCH_UPDATE:
  184. break;
  185. case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
  186. /* ignore */
  187. break;
  188. case GNUNET_FS_STATUS_SEARCH_ERROR:
  189. fprintf (stderr,
  190. _ ("Error searching: %s.\n"),
  191. info->value.search.specifics.error.message);
  192. GNUNET_SCHEDULER_shutdown ();
  193. break;
  194. case GNUNET_FS_STATUS_SEARCH_STOPPED:
  195. GNUNET_SCHEDULER_add_now (&clean_task, NULL);
  196. break;
  197. default:
  198. fprintf (stderr, _ ("Unexpected status: %d\n"), info->status);
  199. break;
  200. }
  201. return NULL;
  202. }
  203. static void
  204. shutdown_task (void *cls)
  205. {
  206. if (sc != NULL)
  207. {
  208. GNUNET_FS_search_stop (sc);
  209. sc = NULL;
  210. }
  211. }
  212. static void
  213. timeout_task (void *cls)
  214. {
  215. tt = NULL;
  216. GNUNET_SCHEDULER_shutdown ();
  217. }
  218. /**
  219. * Main function that will be run by the scheduler.
  220. *
  221. * @param cls closure
  222. * @param args remaining command-line arguments
  223. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  224. * @param c configuration
  225. */
  226. static void
  227. run (void *cls,
  228. char *const *args,
  229. const char *cfgfile,
  230. const struct GNUNET_CONFIGURATION_Handle *c)
  231. {
  232. struct GNUNET_FS_Uri *uri;
  233. unsigned int argc;
  234. enum GNUNET_FS_SearchOptions options;
  235. argc = 0;
  236. while (NULL != args[argc])
  237. argc++;
  238. uri = GNUNET_FS_uri_ksk_create_from_args (argc, (const char **) args);
  239. if (NULL == uri)
  240. {
  241. fprintf (stderr,
  242. "%s",
  243. _ ("Could not create keyword URI from arguments.\n"));
  244. ret = 1;
  245. return;
  246. }
  247. cfg = c;
  248. ctx = GNUNET_FS_start (cfg,
  249. "gnunet-search",
  250. &progress_cb,
  251. NULL,
  252. GNUNET_FS_FLAGS_NONE,
  253. GNUNET_FS_OPTIONS_END);
  254. if (NULL == ctx)
  255. {
  256. fprintf (stderr, _ ("Could not initialize `%s' subsystem.\n"), "FS");
  257. GNUNET_FS_uri_destroy (uri);
  258. ret = 1;
  259. return;
  260. }
  261. if (output_filename != NULL)
  262. db = GNUNET_FS_directory_builder_create (NULL);
  263. options = GNUNET_FS_SEARCH_OPTION_NONE;
  264. if (local_only)
  265. options |= GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY;
  266. sc = GNUNET_FS_search_start (ctx, uri, anonymity, options, NULL);
  267. GNUNET_FS_uri_destroy (uri);
  268. if (NULL == sc)
  269. {
  270. fprintf (stderr, "%s", _ ("Could not start searching.\n"));
  271. GNUNET_FS_stop (ctx);
  272. ret = 1;
  273. return;
  274. }
  275. if (0 != timeout.rel_value_us)
  276. tt = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_task, NULL);
  277. GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
  278. }
  279. /**
  280. * The main function to search GNUnet.
  281. *
  282. * @param argc number of arguments from the command line
  283. * @param argv command line arguments
  284. * @return 0 ok, 1 on error
  285. */
  286. int
  287. main (int argc, char *const *argv)
  288. {
  289. struct GNUNET_GETOPT_CommandLineOption options[] =
  290. { GNUNET_GETOPT_option_uint ('a',
  291. "anonymity",
  292. "LEVEL",
  293. gettext_noop (
  294. "set the desired LEVEL of receiver-anonymity"),
  295. &anonymity),
  296. GNUNET_GETOPT_option_flag (
  297. 'n',
  298. "no-network",
  299. gettext_noop ("only search the local peer (no P2P network search)"),
  300. &local_only),
  301. GNUNET_GETOPT_option_string (
  302. 'o',
  303. "output",
  304. "PREFIX",
  305. gettext_noop ("write search results to file starting with PREFIX"),
  306. &output_filename),
  307. GNUNET_GETOPT_option_relative_time (
  308. 't',
  309. "timeout",
  310. "DELAY",
  311. gettext_noop ("automatically terminate search after DELAY"),
  312. &timeout),
  313. GNUNET_GETOPT_option_verbose (&verbose),
  314. GNUNET_GETOPT_option_uint ('N',
  315. "results",
  316. "VALUE",
  317. gettext_noop ("automatically terminate search "
  318. "after VALUE results are found"),
  319. &results_limit),
  320. GNUNET_GETOPT_OPTION_END };
  321. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  322. return 2;
  323. ret =
  324. (GNUNET_OK ==
  325. GNUNET_PROGRAM_run (argc,
  326. argv,
  327. "gnunet-search [OPTIONS] KEYWORD",
  328. gettext_noop (
  329. "Search GNUnet for files that were published on GNUnet"),
  330. options,
  331. &run,
  332. NULL))
  333. ? ret
  334. : 1;
  335. GNUNET_free_nz ((void *) argv);
  336. return ret;
  337. }
  338. /* end of gnunet-search.c */