gnunet-publish.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2001-2013 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-publish.c
  19. * @brief publishing 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. #include "gnunet_identity_service.h"
  28. /**
  29. * Global return value from 'main'.
  30. */
  31. static int ret = 1;
  32. /**
  33. * Command line option 'verbose' set
  34. */
  35. static int verbose;
  36. /**
  37. * Handle to our configuration.
  38. */
  39. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  40. /**
  41. * Handle for interaction with file-sharing service.
  42. */
  43. static struct GNUNET_FS_Handle *ctx;
  44. /**
  45. * Handle to FS-publishing operation.
  46. */
  47. static struct GNUNET_FS_PublishContext *pc;
  48. /**
  49. * Meta-data provided via command-line option.
  50. */
  51. static struct GNUNET_CONTAINER_MetaData *meta;
  52. /**
  53. * Keywords provided via command-line option.
  54. */
  55. static struct GNUNET_FS_Uri *topKeywords;
  56. /**
  57. * Options we set for published blocks.
  58. */
  59. static struct GNUNET_FS_BlockOptions bo = { {0LL}, 1, 365, 1 };
  60. /**
  61. * Value of URI provided on command-line (when not publishing
  62. * a file but just creating UBlocks to refer to an existing URI).
  63. */
  64. static char *uri_string;
  65. /**
  66. * Value of URI provided on command-line (when not publishing
  67. * a file but just creating UBlocks to refer to an existing URI);
  68. * parsed version of 'uri_string'.
  69. */
  70. static struct GNUNET_FS_Uri *uri;
  71. /**
  72. * Command-line option for namespace publishing: identifier for updates
  73. * to this publication.
  74. */
  75. static char *next_id;
  76. /**
  77. * Command-line option for namespace publishing: identifier for this
  78. * publication.
  79. */
  80. static char *this_id;
  81. /**
  82. * Command-line option identifying the pseudonym to use for the publication.
  83. */
  84. static char *pseudonym;
  85. /**
  86. * Command-line option for 'inserting'
  87. */
  88. static int do_insert;
  89. /**
  90. * Command-line option to disable meta data extraction.
  91. */
  92. static int disable_extractor;
  93. /**
  94. * Command-line option to merely simulate publishing operation.
  95. */
  96. static int do_simulate;
  97. /**
  98. * Command-line option to only perform meta data extraction, but not publish.
  99. */
  100. static int extract_only;
  101. /**
  102. * Command-line option to disable adding creation time.
  103. */
  104. static int do_disable_creation_time;
  105. /**
  106. * Task run on CTRL-C to kill everything nicely.
  107. */
  108. static GNUNET_SCHEDULER_TaskIdentifier kill_task;
  109. /**
  110. * Handle to the directory scanner (for recursive insertions).
  111. */
  112. static struct GNUNET_FS_DirScanner *ds;
  113. /**
  114. * Which namespace do we publish to? NULL if we do not publish to
  115. * a namespace.
  116. */
  117. static struct GNUNET_IDENTITY_Ego *namespace;
  118. /**
  119. * Handle to identity service.
  120. */
  121. static struct GNUNET_IDENTITY_Handle *identity;
  122. /**
  123. * We are finished with the publishing operation, clean up all
  124. * FS state.
  125. *
  126. * @param cls NULL
  127. * @param tc scheduler context
  128. */
  129. static void
  130. do_stop_task (void *cls,
  131. const struct GNUNET_SCHEDULER_TaskContext *tc)
  132. {
  133. struct GNUNET_FS_PublishContext *p;
  134. kill_task = GNUNET_SCHEDULER_NO_TASK;
  135. if (NULL != identity)
  136. {
  137. GNUNET_IDENTITY_disconnect (identity);
  138. identity = NULL;
  139. }
  140. if (NULL != pc)
  141. {
  142. p = pc;
  143. pc = NULL;
  144. GNUNET_FS_publish_stop (p);
  145. }
  146. if (NULL != meta)
  147. {
  148. GNUNET_CONTAINER_meta_data_destroy (meta);
  149. meta = NULL;
  150. }
  151. }
  152. /**
  153. * Stop the directory scanner (we had an error).
  154. *
  155. * @param cls closure
  156. * @param tc scheduler context
  157. */
  158. static void
  159. stop_scanner_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  160. {
  161. kill_task = GNUNET_SCHEDULER_NO_TASK;
  162. if (NULL != ds)
  163. {
  164. GNUNET_FS_directory_scan_abort (ds);
  165. ds = NULL;
  166. }
  167. if (NULL != identity)
  168. {
  169. GNUNET_IDENTITY_disconnect (identity);
  170. identity = NULL;
  171. }
  172. GNUNET_FS_stop (ctx);
  173. ctx = NULL;
  174. ret = 1;
  175. }
  176. /**
  177. * Called by FS client to give information about the progress of an
  178. * operation.
  179. *
  180. * @param cls closure
  181. * @param info details about the event, specifying the event type
  182. * and various bits about the event
  183. * @return client-context (for the next progress call
  184. * for this operation; should be set to NULL for
  185. * SUSPEND and STOPPED events). The value returned
  186. * will be passed to future callbacks in the respective
  187. * field in the GNUNET_FS_ProgressInfo struct.
  188. */
  189. static void *
  190. progress_cb (void *cls,
  191. const struct GNUNET_FS_ProgressInfo *info)
  192. {
  193. const char *s;
  194. char *suri;
  195. switch (info->status)
  196. {
  197. case GNUNET_FS_STATUS_PUBLISH_START:
  198. break;
  199. case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
  200. if (verbose)
  201. {
  202. s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.eta,
  203. GNUNET_YES);
  204. FPRINTF (stdout,
  205. _("Publishing `%s' at %llu/%llu (%s remaining)\n"),
  206. info->value.publish.filename,
  207. (unsigned long long) info->value.publish.completed,
  208. (unsigned long long) info->value.publish.size, s);
  209. }
  210. break;
  211. case GNUNET_FS_STATUS_PUBLISH_PROGRESS_DIRECTORY:
  212. if (verbose)
  213. {
  214. s = GNUNET_STRINGS_relative_time_to_string (info->value.publish.specifics.progress_directory.eta,
  215. GNUNET_YES);
  216. FPRINTF (stdout,
  217. _("Publishing `%s' at %llu/%llu (%s remaining)\n"),
  218. info->value.publish.filename,
  219. (unsigned long long) info->value.publish.specifics.progress_directory.completed,
  220. (unsigned long long) info->value.publish.specifics.progress_directory.total, s);
  221. }
  222. break;
  223. case GNUNET_FS_STATUS_PUBLISH_ERROR:
  224. FPRINTF (stderr, _("Error publishing: %s.\n"),
  225. info->value.publish.specifics.error.message);
  226. if (kill_task != GNUNET_SCHEDULER_NO_TASK)
  227. {
  228. GNUNET_SCHEDULER_cancel (kill_task);
  229. kill_task = GNUNET_SCHEDULER_NO_TASK;
  230. }
  231. kill_task = GNUNET_SCHEDULER_add_now (&do_stop_task, NULL);
  232. break;
  233. case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
  234. FPRINTF (stdout,
  235. _("Publishing `%s' done.\n"),
  236. info->value.publish.filename);
  237. suri = GNUNET_FS_uri_to_string (info->value.publish.specifics.
  238. completed.chk_uri);
  239. FPRINTF (stdout,
  240. _("URI is `%s'.\n"),
  241. suri);
  242. GNUNET_free (suri);
  243. if (NULL != info->value.publish.specifics.completed.sks_uri)
  244. {
  245. suri = GNUNET_FS_uri_to_string (info->value.publish.specifics.
  246. completed.sks_uri);
  247. FPRINTF (stdout,
  248. _("Namespace URI is `%s'.\n"),
  249. suri);
  250. GNUNET_free (suri);
  251. }
  252. if (NULL == info->value.publish.pctx)
  253. {
  254. if (GNUNET_SCHEDULER_NO_TASK != kill_task)
  255. GNUNET_SCHEDULER_cancel (kill_task);
  256. kill_task = GNUNET_SCHEDULER_add_now (&do_stop_task, NULL);
  257. }
  258. ret = 0;
  259. break;
  260. case GNUNET_FS_STATUS_PUBLISH_STOPPED:
  261. GNUNET_break (NULL == pc);
  262. return NULL;
  263. case GNUNET_FS_STATUS_UNINDEX_PROGRESS:
  264. return NULL;
  265. case GNUNET_FS_STATUS_UNINDEX_COMPLETED:
  266. FPRINTF (stderr,
  267. "%s",
  268. _("Cleanup after abort complete.\n"));
  269. return NULL;
  270. default:
  271. FPRINTF (stderr, _("Unexpected status: %d\n"), info->status);
  272. return NULL;
  273. }
  274. return ""; /* non-null */
  275. }
  276. /**
  277. * Print metadata entries (except binary
  278. * metadata and the filename).
  279. *
  280. * @param cls closure
  281. * @param plugin_name name of the plugin that generated the meta data
  282. * @param type type of the meta data
  283. * @param format format of data
  284. * @param data_mime_type mime type of data
  285. * @param data value of the meta data
  286. * @param data_size number of bytes in @a data
  287. * @return always 0
  288. */
  289. static int
  290. meta_printer (void *cls,
  291. const char *plugin_name,
  292. enum EXTRACTOR_MetaType type,
  293. enum EXTRACTOR_MetaFormat format,
  294. const char *data_mime_type,
  295. const char *data, size_t data_size)
  296. {
  297. if ((EXTRACTOR_METAFORMAT_UTF8 != format) &&
  298. (EXTRACTOR_METAFORMAT_C_STRING != format))
  299. return 0;
  300. if (EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME == type)
  301. return 0;
  302. FPRINTF (stdout, "\t%s - %s\n", EXTRACTOR_metatype_to_string (type), data);
  303. return 0;
  304. }
  305. /**
  306. * Iterator printing keywords
  307. *
  308. * @param cls closure
  309. * @param keyword the keyword
  310. * @param is_mandatory is the keyword mandatory (in a search)
  311. * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to abort
  312. */
  313. static int
  314. keyword_printer (void *cls,
  315. const char *keyword,
  316. int is_mandatory)
  317. {
  318. FPRINTF (stdout, "\t%s\n", keyword);
  319. return GNUNET_OK;
  320. }
  321. /**
  322. * Function called on all entries before the publication. This is
  323. * where we perform modifications to the default based on command-line
  324. * options.
  325. *
  326. * @param cls closure
  327. * @param fi the entry in the publish-structure
  328. * @param length length of the file or directory
  329. * @param m metadata for the file or directory (can be modified)
  330. * @param uri pointer to the keywords that will be used for this entry (can be modified)
  331. * @param bo block options
  332. * @param do_index should we index?
  333. * @param client_info pointer to client context set upon creation (can be modified)
  334. * @return #GNUNET_OK to continue, #GNUNET_NO to remove
  335. * this entry from the directory, #GNUNET_SYSERR
  336. * to abort the iteration
  337. */
  338. static int
  339. publish_inspector (void *cls,
  340. struct GNUNET_FS_FileInformation *fi,
  341. uint64_t length,
  342. struct GNUNET_CONTAINER_MetaData *m,
  343. struct GNUNET_FS_Uri **uri,
  344. struct GNUNET_FS_BlockOptions *bo,
  345. int *do_index,
  346. void **client_info)
  347. {
  348. char *fn;
  349. char *fs;
  350. struct GNUNET_FS_Uri *new_uri;
  351. if (cls == fi)
  352. return GNUNET_OK;
  353. if ( (disable_extractor) &&
  354. (NULL != *uri) )
  355. {
  356. GNUNET_FS_uri_destroy (*uri);
  357. *uri = NULL;
  358. }
  359. if (NULL != topKeywords)
  360. {
  361. if (NULL != *uri)
  362. {
  363. new_uri = GNUNET_FS_uri_ksk_merge (topKeywords, *uri);
  364. GNUNET_FS_uri_destroy (*uri);
  365. *uri = new_uri;
  366. GNUNET_FS_uri_destroy (topKeywords);
  367. }
  368. else
  369. {
  370. *uri = topKeywords;
  371. }
  372. topKeywords = NULL;
  373. }
  374. if (NULL != meta)
  375. {
  376. GNUNET_CONTAINER_meta_data_merge (m, meta);
  377. GNUNET_CONTAINER_meta_data_destroy (meta);
  378. meta = NULL;
  379. }
  380. if (!do_disable_creation_time)
  381. GNUNET_CONTAINER_meta_data_add_publication_date (m);
  382. if (extract_only)
  383. {
  384. fn = GNUNET_CONTAINER_meta_data_get_by_type (m,
  385. EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
  386. fs = GNUNET_STRINGS_byte_size_fancy (length);
  387. FPRINTF (stdout, _("Meta data for file `%s' (%s)\n"), fn, fs);
  388. GNUNET_CONTAINER_meta_data_iterate (m, &meta_printer, NULL);
  389. FPRINTF (stdout, _("Keywords for file `%s' (%s)\n"), fn, fs);
  390. GNUNET_free (fn);
  391. GNUNET_free (fs);
  392. if (NULL != *uri)
  393. GNUNET_FS_uri_ksk_get_keywords (*uri, &keyword_printer, NULL);
  394. FPRINTF (stdout, "%s", "\n");
  395. }
  396. if (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (m))
  397. GNUNET_FS_file_information_inspect (fi, &publish_inspector, fi);
  398. return GNUNET_OK;
  399. }
  400. /**
  401. * Function called upon completion of the publishing
  402. * of the UBLOCK for the SKS URI. As this is the last
  403. * step, stop our interaction with FS (clean up).
  404. *
  405. * @param cls NULL (closure)
  406. * @param sks_uri URI for the block that was published
  407. * @param emsg error message, NULL on success
  408. */
  409. static void
  410. uri_sks_continuation (void *cls,
  411. const struct GNUNET_FS_Uri *sks_uri,
  412. const char *emsg)
  413. {
  414. if (NULL != emsg)
  415. {
  416. FPRINTF (stderr, "%s\n", emsg);
  417. ret = 1;
  418. }
  419. GNUNET_FS_uri_destroy (uri);
  420. uri = NULL;
  421. GNUNET_FS_stop (ctx);
  422. ctx = NULL;
  423. }
  424. /**
  425. * Function called upon completion of the publishing
  426. * of the UBLOCK for the KSK URI. Continue with
  427. * publishing the SKS URI (if applicable) or clean up.
  428. *
  429. * @param cls NULL (closure)
  430. * @param ksk_uri URI for the block that was published
  431. * @param emsg error message, NULL on success
  432. */
  433. static void
  434. uri_ksk_continuation (void *cls,
  435. const struct GNUNET_FS_Uri *ksk_uri,
  436. const char *emsg)
  437. {
  438. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
  439. if (NULL != emsg)
  440. {
  441. FPRINTF (stderr, "%s\n", emsg);
  442. ret = 1;
  443. }
  444. if (NULL != namespace)
  445. {
  446. priv = GNUNET_IDENTITY_ego_get_private_key (namespace);
  447. GNUNET_FS_publish_sks (ctx, priv, this_id, next_id, meta, uri, &bo,
  448. GNUNET_FS_PUBLISH_OPTION_NONE,
  449. &uri_sks_continuation, NULL);
  450. return;
  451. }
  452. GNUNET_FS_uri_destroy (uri);
  453. uri = NULL;
  454. GNUNET_FS_stop (ctx);
  455. ctx = NULL;
  456. }
  457. /**
  458. * Iterate over the results from the directory scan and extract
  459. * the desired information for the publishing operation.
  460. *
  461. * @param item root with the data from the directroy scan
  462. * @return handle with the information for the publishing operation
  463. */
  464. static struct GNUNET_FS_FileInformation *
  465. get_file_information (struct GNUNET_FS_ShareTreeItem *item)
  466. {
  467. struct GNUNET_FS_FileInformation *fi;
  468. struct GNUNET_FS_FileInformation *fic;
  469. struct GNUNET_FS_ShareTreeItem *child;
  470. if (GNUNET_YES == item->is_directory)
  471. {
  472. GNUNET_CONTAINER_meta_data_delete (item->meta,
  473. EXTRACTOR_METATYPE_MIMETYPE,
  474. NULL, 0);
  475. GNUNET_FS_meta_data_make_directory (item->meta);
  476. if (NULL == item->ksk_uri)
  477. {
  478. const char *mime = GNUNET_FS_DIRECTORY_MIME;
  479. item->ksk_uri = GNUNET_FS_uri_ksk_create_from_args (1, &mime);
  480. }
  481. else
  482. GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME,
  483. GNUNET_NO);
  484. fi = GNUNET_FS_file_information_create_empty_directory (ctx, NULL,
  485. item->ksk_uri,
  486. item->meta,
  487. &bo, item->filename);
  488. for (child = item->children_head; child; child = child->next)
  489. {
  490. fic = get_file_information (child);
  491. GNUNET_break (GNUNET_OK == GNUNET_FS_file_information_add (fi, fic));
  492. }
  493. }
  494. else
  495. {
  496. fi = GNUNET_FS_file_information_create_from_file (ctx, NULL,
  497. item->filename,
  498. item->ksk_uri, item->meta,
  499. !do_insert,
  500. &bo);
  501. }
  502. return fi;
  503. }
  504. /**
  505. * We've finished scanning the directory and optimized the meta data.
  506. * Begin the publication process.
  507. *
  508. * @param directory_scan_result result from the directory scan, freed in this function
  509. */
  510. static void
  511. directory_trim_complete (struct GNUNET_FS_ShareTreeItem *directory_scan_result)
  512. {
  513. struct GNUNET_FS_FileInformation *fi;
  514. const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
  515. fi = get_file_information (directory_scan_result);
  516. GNUNET_FS_share_tree_free (directory_scan_result);
  517. if (NULL == fi)
  518. {
  519. FPRINTF (stderr,
  520. "%s",
  521. _("Could not publish\n"));
  522. GNUNET_SCHEDULER_shutdown ();
  523. ret = 1;
  524. return;
  525. }
  526. GNUNET_FS_file_information_inspect (fi, &publish_inspector, NULL);
  527. if (extract_only)
  528. {
  529. GNUNET_FS_file_information_destroy (fi, NULL, NULL);
  530. GNUNET_SCHEDULER_shutdown ();
  531. return;
  532. }
  533. if (NULL == namespace)
  534. priv = NULL;
  535. else
  536. priv = GNUNET_IDENTITY_ego_get_private_key (namespace);
  537. pc = GNUNET_FS_publish_start (ctx, fi,
  538. priv, this_id, next_id,
  539. (do_simulate) ?
  540. GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY :
  541. GNUNET_FS_PUBLISH_OPTION_NONE);
  542. if (NULL == pc)
  543. {
  544. FPRINTF (stderr,
  545. "%s",
  546. _("Could not start publishing.\n"));
  547. GNUNET_SCHEDULER_shutdown ();
  548. ret = 1;
  549. return;
  550. }
  551. }
  552. /**
  553. * Function called by the directory scanner as we build the tree
  554. * that we will need to publish later.
  555. *
  556. * @param cls closure
  557. * @param filename which file we are making progress on
  558. * @param is_directory #GNUNET_YES if this is a directory,
  559. * #GNUNET_NO if this is a file
  560. * #GNUNET_SYSERR if it is neither (or unknown)
  561. * @param reason kind of progress we are making
  562. */
  563. static void
  564. directory_scan_cb (void *cls,
  565. const char *filename,
  566. int is_directory,
  567. enum GNUNET_FS_DirScannerProgressUpdateReason reason)
  568. {
  569. struct GNUNET_FS_ShareTreeItem *directory_scan_result;
  570. switch (reason)
  571. {
  572. case GNUNET_FS_DIRSCANNER_FILE_START:
  573. if (verbose > 1)
  574. {
  575. if (is_directory == GNUNET_YES)
  576. FPRINTF (stdout,
  577. _("Scanning directory `%s'.\n"),
  578. filename);
  579. else
  580. FPRINTF (stdout,
  581. _("Scanning file `%s'.\n"),
  582. filename);
  583. }
  584. break;
  585. case GNUNET_FS_DIRSCANNER_FILE_IGNORED:
  586. FPRINTF (stderr,
  587. _("There was trouble processing file `%s', skipping it.\n"),
  588. filename);
  589. break;
  590. case GNUNET_FS_DIRSCANNER_ALL_COUNTED:
  591. if (verbose)
  592. FPRINTF (stdout,
  593. "%s",
  594. _("Preprocessing complete.\n"));
  595. break;
  596. case GNUNET_FS_DIRSCANNER_EXTRACT_FINISHED:
  597. if (verbose > 2)
  598. FPRINTF (stdout,
  599. _("Extracting meta data from file `%s' complete.\n"),
  600. filename);
  601. break;
  602. case GNUNET_FS_DIRSCANNER_FINISHED:
  603. if (verbose > 1)
  604. FPRINTF (stdout,
  605. "%s",
  606. _("Meta data extraction has finished.\n"));
  607. directory_scan_result = GNUNET_FS_directory_scan_get_result (ds);
  608. ds = NULL;
  609. GNUNET_FS_share_tree_trim (directory_scan_result);
  610. directory_trim_complete (directory_scan_result);
  611. break;
  612. case GNUNET_FS_DIRSCANNER_INTERNAL_ERROR:
  613. FPRINTF (stdout,
  614. "%s",
  615. _("Internal error scanning directory.\n"));
  616. if (kill_task != GNUNET_SCHEDULER_NO_TASK)
  617. {
  618. GNUNET_SCHEDULER_cancel (kill_task);
  619. kill_task = GNUNET_SCHEDULER_NO_TASK;
  620. }
  621. kill_task = GNUNET_SCHEDULER_add_now (&stop_scanner_task, NULL);
  622. break;
  623. default:
  624. GNUNET_assert (0);
  625. break;
  626. }
  627. fflush (stdout);
  628. }
  629. /**
  630. * Continuation proceeding with initialization after identity subsystem
  631. * has been initialized.
  632. *
  633. * @param args0 filename to publish
  634. */
  635. static void
  636. identity_continuation (const char *args0)
  637. {
  638. char *ex;
  639. char *emsg;
  640. if ( (NULL != pseudonym) &&
  641. (NULL == namespace) )
  642. {
  643. FPRINTF (stderr,
  644. _("Selected pseudonym `%s' unknown\n"),
  645. pseudonym);
  646. GNUNET_SCHEDULER_shutdown ();
  647. return;
  648. }
  649. if (NULL != uri_string)
  650. {
  651. emsg = NULL;
  652. if (NULL == (uri = GNUNET_FS_uri_parse (uri_string, &emsg)))
  653. {
  654. FPRINTF (stderr,
  655. _("Failed to parse URI: %s\n"),
  656. emsg);
  657. GNUNET_free (emsg);
  658. GNUNET_SCHEDULER_shutdown ();
  659. ret = 1;
  660. return;
  661. }
  662. GNUNET_FS_publish_ksk (ctx, topKeywords,
  663. meta, uri,
  664. &bo,
  665. GNUNET_FS_PUBLISH_OPTION_NONE,
  666. &uri_ksk_continuation,
  667. NULL);
  668. return;
  669. }
  670. if (GNUNET_OK !=
  671. GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS", &ex))
  672. ex = NULL;
  673. if (0 != ACCESS (args0, R_OK))
  674. {
  675. FPRINTF (stderr,
  676. _("Failed to access `%s': %s\n"),
  677. args0,
  678. STRERROR (errno));
  679. GNUNET_free_non_null (ex);
  680. return;
  681. }
  682. ds = GNUNET_FS_directory_scan_start (args0,
  683. disable_extractor,
  684. ex,
  685. &directory_scan_cb, NULL);
  686. if (NULL == ds)
  687. {
  688. FPRINTF (stderr,
  689. "%s",
  690. _("Failed to start meta directory scanner. Is gnunet-helper-publish-fs installed?\n"));
  691. GNUNET_free_non_null (ex);
  692. return;
  693. }
  694. GNUNET_free_non_null (ex);
  695. }
  696. /**
  697. * Function called by identity service with known pseudonyms.
  698. *
  699. * @param cls closure with 'const char *' of filename to publish
  700. * @param ego ego handle
  701. * @param ctx context for application to store data for this ego
  702. * (during the lifetime of this process, initially NULL)
  703. * @param name name assigned by the user for this ego,
  704. * NULL if the user just deleted the ego and it
  705. * must thus no longer be used
  706. */
  707. static void
  708. identity_cb (void *cls,
  709. struct GNUNET_IDENTITY_Ego *ego,
  710. void **ctx,
  711. const char *name)
  712. {
  713. const char *args0 = cls;
  714. if (NULL == ego)
  715. {
  716. identity_continuation (args0);
  717. return;
  718. }
  719. if (NULL == name)
  720. return;
  721. if (0 == strcmp (name, pseudonym))
  722. namespace = ego;
  723. }
  724. /**
  725. * Main function that will be run by the scheduler.
  726. *
  727. * @param cls closure
  728. * @param args remaining command-line arguments
  729. * @param cfgfile name of the configuration file used (for saving, can be NULL!)
  730. * @param c configuration
  731. */
  732. static void
  733. run (void *cls,
  734. char *const *args,
  735. const char *cfgfile,
  736. const struct GNUNET_CONFIGURATION_Handle *c)
  737. {
  738. /* check arguments */
  739. if ((NULL != uri_string) && (extract_only))
  740. {
  741. printf (_("Cannot extract metadata from a URI!\n"));
  742. ret = -1;
  743. return;
  744. }
  745. if (((NULL == uri_string) || (extract_only)) &&
  746. ((NULL == args[0]) || (NULL != args[1])))
  747. {
  748. printf (_("You must specify one and only one filename for insertion.\n"));
  749. ret = -1;
  750. return;
  751. }
  752. if ((NULL != uri_string) && (NULL != args[0]))
  753. {
  754. printf (_("You must NOT specify an URI and a filename.\n"));
  755. ret = -1;
  756. return;
  757. }
  758. if (NULL != pseudonym)
  759. {
  760. if (NULL == this_id)
  761. {
  762. FPRINTF (stderr, _("Option `%s' is required when using option `%s'.\n"),
  763. "-t", "-P");
  764. ret = -1;
  765. return;
  766. }
  767. }
  768. else
  769. { /* ordinary insertion checks */
  770. if (NULL != next_id)
  771. {
  772. FPRINTF (stderr,
  773. _("Option `%s' makes no sense without option `%s'.\n"),
  774. "-N", "-P");
  775. ret = -1;
  776. return;
  777. }
  778. if (NULL != this_id)
  779. {
  780. FPRINTF (stderr,
  781. _("Option `%s' makes no sense without option `%s'.\n"),
  782. "-t", "-P");
  783. ret = -1;
  784. return;
  785. }
  786. }
  787. cfg = c;
  788. ctx =
  789. GNUNET_FS_start (cfg, "gnunet-publish", &progress_cb, NULL,
  790. GNUNET_FS_FLAGS_NONE, GNUNET_FS_OPTIONS_END);
  791. if (NULL == ctx)
  792. {
  793. FPRINTF (stderr,
  794. _("Could not initialize `%s' subsystem.\n"),
  795. "FS");
  796. ret = 1;
  797. return;
  798. }
  799. kill_task =
  800. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
  801. &do_stop_task,
  802. NULL);
  803. if (NULL != pseudonym)
  804. identity = GNUNET_IDENTITY_connect (cfg,
  805. &identity_cb,
  806. args[0]);
  807. else
  808. identity_continuation (args[0]);
  809. }
  810. /**
  811. * The main function to publish content to GNUnet.
  812. *
  813. * @param argc number of arguments from the command line
  814. * @param argv command line arguments
  815. * @return 0 ok, 1 on error
  816. */
  817. int
  818. main (int argc, char *const *argv)
  819. {
  820. static const struct GNUNET_GETOPT_CommandLineOption options[] = {
  821. {'a', "anonymity", "LEVEL",
  822. gettext_noop ("set the desired LEVEL of sender-anonymity"),
  823. 1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level},
  824. {'d', "disable-creation-time", NULL,
  825. gettext_noop
  826. ("disable adding the creation time to the metadata of the uploaded file"),
  827. 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time},
  828. {'D', "disable-extractor", NULL,
  829. gettext_noop ("do not use libextractor to add keywords or metadata"),
  830. 0, &GNUNET_GETOPT_set_one, &disable_extractor},
  831. {'e', "extract", NULL,
  832. gettext_noop
  833. ("print list of extracted keywords that would be used, but do not perform upload"),
  834. 0, &GNUNET_GETOPT_set_one, &extract_only},
  835. {'k', "key", "KEYWORD",
  836. gettext_noop
  837. ("add an additional keyword for the top-level file or directory"
  838. " (this option can be specified multiple times)"),
  839. 1, &GNUNET_FS_getopt_set_keywords, &topKeywords},
  840. {'m', "meta", "TYPE:VALUE",
  841. gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
  842. 1, &GNUNET_FS_getopt_set_metadata, &meta},
  843. {'n', "noindex", NULL,
  844. gettext_noop ("do not index, perform full insertion (stores entire "
  845. "file in encrypted form in GNUnet database)"),
  846. 0, &GNUNET_GETOPT_set_one, &do_insert},
  847. {'N', "next", "ID",
  848. gettext_noop
  849. ("specify ID of an updated version to be published in the future"
  850. " (for namespace insertions only)"),
  851. 1, &GNUNET_GETOPT_set_string, &next_id},
  852. {'p', "priority", "PRIORITY",
  853. gettext_noop ("specify the priority of the content"),
  854. 1, &GNUNET_GETOPT_set_uint, &bo.content_priority},
  855. {'P', "pseudonym", "NAME",
  856. gettext_noop
  857. ("publish the files under the pseudonym NAME (place file into namespace)"),
  858. 1, &GNUNET_GETOPT_set_string, &pseudonym},
  859. {'r', "replication", "LEVEL",
  860. gettext_noop ("set the desired replication LEVEL"),
  861. 1, &GNUNET_GETOPT_set_uint, &bo.replication_level},
  862. {'s', "simulate-only", NULL,
  863. gettext_noop ("only simulate the process but do not do any "
  864. "actual publishing (useful to compute URIs)"),
  865. 0, &GNUNET_GETOPT_set_one, &do_simulate},
  866. {'t', "this", "ID",
  867. gettext_noop ("set the ID of this version of the publication"
  868. " (for namespace insertions only)"),
  869. 1, &GNUNET_GETOPT_set_string, &this_id},
  870. {'u', "uri", "URI",
  871. gettext_noop ("URI to be published (can be used instead of passing a "
  872. "file to add keywords to the file with the respective URI)"),
  873. 1, &GNUNET_GETOPT_set_string, &uri_string},
  874. {'V', "verbose", NULL,
  875. gettext_noop ("be verbose (print progress information)"),
  876. 0, &GNUNET_GETOPT_set_one, &verbose},
  877. GNUNET_GETOPT_OPTION_END
  878. };
  879. bo.expiration_time =
  880. GNUNET_TIME_year_to_time (GNUNET_TIME_get_current_year () + 2);
  881. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  882. return 2;
  883. ret = (GNUNET_OK ==
  884. GNUNET_PROGRAM_run (argc, argv, "gnunet-publish [OPTIONS] FILENAME",
  885. gettext_noop
  886. ("Publish a file or directory on GNUnet"),
  887. options, &run, NULL)) ? ret : 1;
  888. GNUNET_free ((void*) argv);
  889. return ret;
  890. }
  891. /* end of gnunet-publish.c */