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