aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-publish.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/gnunet-publish.c')
-rw-r--r--src/fs/gnunet-publish.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/src/fs/gnunet-publish.c b/src/fs/gnunet-publish.c
new file mode 100644
index 000000000..58885c234
--- /dev/null
+++ b/src/fs/gnunet-publish.c
@@ -0,0 +1,556 @@
1/*
2 This file is part of GNUnet.
3 (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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 * TODO:
29 * - support for some options is still missing (uri argument, simulate)
30 * - progress callbacks not implemented (and need verbosity option)
31 * - clean shutdown is not implemented (stop ctx, etc.)
32 */
33#include "platform.h"
34#include "gnunet_fs_service.h"
35
36#define DEFAULT_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS, 2)
37
38static int ret;
39
40static const struct GNUNET_CONFIGURATION_Handle *cfg;
41
42static struct GNUNET_FS_Handle *ctx;
43
44static struct GNUNET_FS_PublishContext *pc;
45
46static struct GNUNET_TIME_Absolute start_time;
47
48static struct GNUNET_CONTAINER_MetaData *meta;
49
50static struct GNUNET_FS_Uri *topKeywords;
51
52static unsigned int anonymity = 1;
53
54static unsigned int priority = 365;
55
56static char *uri_string;
57
58static char *next_id;
59
60static char *this_id;
61
62static char *pseudonym;
63
64static int do_insert;
65
66static int disable_extractor;
67
68static int do_simulate;
69
70static int extract_only;
71
72static int do_disable_creation_time;
73
74
75/**
76 * Called by FS client to give information about the progress of an
77 * operation.
78 *
79 * @param cls closure
80 * @param info details about the event, specifying the event type
81 * and various bits about the event
82 * @return client-context (for the next progress call
83 * for this operation; should be set to NULL for
84 * SUSPEND and STOPPED events). The value returned
85 * will be passed to future callbacks in the respective
86 * field in the GNUNET_FS_ProgressInfo struct.
87 */
88static void *
89progress_cb (void *cls,
90 const struct GNUNET_FS_ProgressInfo *info)
91{
92 return NULL;
93}
94
95
96/**
97 * Print metadata entries (except binary
98 * metadata and the filename).
99 *
100 * @param cls closure
101 * @param type type of the meta data
102 * @param data value of the meta data
103 * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
104 */
105static int
106meta_printer (void *cls,
107 EXTRACTOR_KeywordType type,
108 const char *data)
109{
110 if ( (type == EXTRACTOR_FILENAME) ||
111 (EXTRACTOR_isBinaryType (type)) )
112 return GNUNET_OK;
113 fprintf (stdout,
114 "%s - %s",
115 EXTRACTOR_getKeywordTypeAsString (type),
116 data);
117 return GNUNET_OK;
118}
119
120
121/**
122 * Merge metadata entries (except binary
123 * metadata).
124 *
125 * @param cls closure, target metadata structure
126 * @param type type of the meta data
127 * @param data value of the meta data
128 * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
129 */
130static int
131meta_merger (void *cls,
132 EXTRACTOR_KeywordType type,
133 const char *data)
134{
135 struct GNUNET_CONTAINER_MetaData *m = cls;
136 GNUNET_CONTAINER_meta_data_insert (m,
137 type,
138 data);
139 return GNUNET_OK;
140}
141
142
143/**
144 * Function called on all entries before the
145 * publication. This is where we perform
146 * modifications to the default based on
147 * command-line options.
148 *
149 * @param cls closure
150 * @param fi the entry in the publish-structure
151 * @param length length of the file or directory
152 * @param m metadata for the file or directory (can be modified)
153 * @param uri pointer to the keywords that will be used for this entry (can be modified)
154 * @param anonymity pointer to selected anonymity level (can be modified)
155 * @param priority pointer to selected priority (can be modified)
156 * @param expirationTime pointer to selected expiration time (can be modified)
157 * @param client_info pointer to client context set upon creation (can be modified)
158 * @return GNUNET_OK to continue, GNUNET_NO to remove
159 * this entry from the directory, GNUNET_SYSERR
160 * to abort the iteration
161 */
162static int
163publish_inspector (void *cls,
164 struct GNUNET_FS_FileInformation *fi,
165 uint64_t length,
166 struct GNUNET_CONTAINER_MetaData *m,
167 struct GNUNET_FS_Uri **uri,
168 unsigned int *anonymity,
169 unsigned int *priority,
170 struct GNUNET_TIME_Absolute *expirationTime,
171 void **client_info)
172{
173 char *fn;
174 char *fs;
175 struct GNUNET_FS_Uri *new_uri;
176
177 if (! do_disable_creation_time)
178 GNUNET_CONTAINER_meta_data_add_publication_date (meta);
179 if (NULL != topKeywords)
180 {
181 new_uri = GNUNET_FS_uri_ksk_merge (topKeywords,
182 *uri);
183 GNUNET_FS_uri_destroy (*uri);
184 *uri = new_uri;
185 GNUNET_FS_uri_destroy (topKeywords);
186 topKeywords = NULL;
187 }
188 if (NULL != meta)
189 {
190 GNUNET_CONTAINER_meta_data_get_contents (meta,
191 &meta_merger,
192 m);
193 GNUNET_CONTAINER_meta_data_destroy (meta);
194 meta = NULL;
195 }
196 if (extract_only)
197 {
198 fn = GNUNET_CONTAINER_meta_data_get_by_type (meta,
199 EXTRACTOR_FILENAME);
200 fs = GNUNET_STRINGS_byte_size_fancy (length);
201 fprintf (stdout,
202 _("Keywords for file `%s' (%s)\n"),
203 fn,
204 fs);
205 GNUNET_free (fn);
206 GNUNET_free (fs);
207 GNUNET_CONTAINER_meta_data_get_contents (meta,
208 &meta_printer,
209 NULL);
210 fprintf (stdout, "\n");
211 }
212 if (GNUNET_FS_meta_data_test_for_directory (meta))
213 GNUNET_FS_file_information_inspect (fi,
214 &publish_inspector,
215 NULL);
216 return GNUNET_OK;
217}
218
219
220/**
221 * Main function that will be run by the scheduler.
222 *
223 * @param cls closure
224 * @param sched the scheduler to use
225 * @param args remaining command-line arguments
226 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
227 * @param cfg configuration
228 */
229static void
230run (void *cls,
231 struct GNUNET_SCHEDULER_Handle *sched,
232 char *const *args,
233 const char *cfgfile,
234 const struct GNUNET_CONFIGURATION_Handle *c)
235{
236 struct GNUNET_FS_FileInformation *fi;
237 struct GNUNET_FS_Namespace *namespace;
238 EXTRACTOR_ExtractorList *l;
239 char *ex;
240 char *emsg;
241
242 /* check arguments */
243 if ( ( (uri_string == NULL) || (extract_only) )
244 && ( (args[0] == NULL) || (args[1] != NULL) ) )
245 {
246 printf (_
247 ("You must specify one and only one filename for insertion.\n"));
248 ret = -1;
249 return;
250 }
251 if ((uri_string != NULL) && (args[0] != NULL))
252 {
253 printf (_("You must NOT specify an URI and a filename.\n"));
254 ret = -1;
255 return;
256 }
257 if ((uri_string != NULL) && (extract_only))
258 {
259 printf (_("Cannot extract metadata from a URI!\n"));
260 ret = -1;
261 return;
262 }
263 if (pseudonym != NULL)
264 {
265 if (NULL == this_id)
266 {
267 fprintf (stderr,
268 _("Option `%s' is required when using option `%s'.\n"),
269 "-t", "-P");
270 ret = -1;
271 return;
272 }
273 }
274 else
275 { /* ordinary insertion checks */
276 if (NULL != next_id)
277 {
278 fprintf (stderr,
279 _("Option `%s' makes no sense without option `%s'.\n"),
280 "-N", "-P");
281 ret = -1;
282 return;
283 }
284 if (NULL != this_id)
285 {
286 fprintf (stderr,
287 _("Option `%s' makes no sense without option `%s'.\n"),
288 "-t", "-P");
289 ret = -1;
290 return;
291 }
292 }
293 if (args[0] == NULL)
294 {
295 fprintf (stderr,
296 _("Need the name of a file to publish!\n"));
297 ret = 1;
298 return;
299 }
300 cfg = c;
301 ctx = GNUNET_FS_start (sched,
302 cfg,
303 "gnunet-publish",
304 &progress_cb,
305 NULL);
306 if (NULL == ctx)
307 {
308 fprintf (stderr,
309 _("Could not initialize `%s' subsystem.\n"),
310 "FS");
311 ret = 1;
312 return;
313 }
314 namespace = NULL;
315 if (NULL != pseudonym)
316 {
317 namespace = GNUNET_FS_namespace_create (ctx,
318 pseudonym);
319 if (NULL == namespace)
320 {
321 fprintf (stderr,
322 _("Could not create namespace `%s'\n"),
323 pseudonym);
324 GNUNET_FS_stop (ctx);
325 ret = 1;
326 return;
327 }
328 }
329 if (NULL != uri_string)
330 {
331 // FIXME -- implement!
332 return;
333 }
334 start_time = GNUNET_TIME_absolute_get ();
335
336 l = NULL;
337 if (! disable_extractor)
338 {
339 l = EXTRACTOR_loadDefaultLibraries ();
340 if (GNUNET_OK ==
341 GNUNET_CONFIGURATION_get_value_string (cfg, "FS", "EXTRACTORS",
342 &ex))
343 {
344 if (strlen (ex) > 0)
345 l = EXTRACTOR_loadConfigLibraries (l, ex);
346 GNUNET_free (ex);
347 }
348 }
349 fi = GNUNET_FS_file_information_create_from_directory (NULL,
350 args[0],
351 &GNUNET_FS_directory_scanner_default,
352 l,
353 !do_insert,
354 anonymity,
355 priority,
356 GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION),
357 &emsg);
358 EXTRACTOR_removeAll (l);
359 if (fi == NULL)
360 {
361 fprintf (stderr,
362 _("Could not publish `%s': %s\n"),
363 args[0],
364 emsg);
365 GNUNET_free (emsg);
366 if (namespace != NULL)
367 GNUNET_FS_namespace_delete (namespace, GNUNET_NO);
368 GNUNET_FS_stop (ctx);
369 ret = 1;
370 return;
371 }
372 GNUNET_FS_file_information_inspect (fi,
373 &publish_inspector,
374 NULL);
375 if (extract_only)
376 {
377 if (namespace != NULL)
378 GNUNET_FS_namespace_delete (namespace, GNUNET_NO);
379 GNUNET_FS_file_information_destroy (fi, NULL, NULL);
380 GNUNET_FS_stop (ctx);
381 return;
382 }
383 pc = GNUNET_FS_publish_start (ctx,
384 NULL,
385 fi,
386 namespace,
387 this_id,
388 next_id);
389}
390
391
392/**
393 * gnunet-publish command line options
394 */
395static struct GNUNET_GETOPT_CommandLineOption options[] = {
396 {'a', "anonymity", "LEVEL",
397 gettext_noop ("set the desired LEVEL of sender-anonymity"),
398 1, &GNUNET_GETOPT_set_uint, &anonymity},
399 {'d', "disable-creation-time", NULL,
400 gettext_noop
401 ("disable adding the creation time to the metadata of the uploaded file"),
402 0, &GNUNET_GETOPT_set_one, &do_disable_creation_time},
403 {'D', "disable-extractor", NULL,
404 gettext_noop
405 ("do not use libextractor to add keywords or metadata"),
406 0, &GNUNET_GETOPT_set_one, &disable_extractor},
407 {'e', "extract", NULL,
408 gettext_noop
409 ("print list of extracted keywords that would be used, but do not perform upload"),
410 0, &GNUNET_GETOPT_set_one, &extract_only},
411 {'k', "key", "KEYWORD",
412 gettext_noop
413 ("add an additional keyword for the top-level file or directory"
414 " (this option can be specified multiple times)"),
415 1, &GNUNET_FS_getopt_set_keywords, &topKeywords},
416 // *: option not yet used... (can handle in a pass over FI)
417 {'m', "meta", "TYPE:VALUE",
418 gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
419 1, &GNUNET_FS_getopt_set_metadata, &meta},
420 {'n', "noindex", NULL,
421 gettext_noop ("do not index, perform full insertion (stores entire "
422 "file in encrypted form in GNUnet database)"),
423 0, &GNUNET_GETOPT_set_one, &do_insert},
424 {'N', "next", "ID",
425 gettext_noop
426 ("specify ID of an updated version to be published in the future"
427 " (for namespace insertions only)"),
428 1, &GNUNET_GETOPT_set_string, &next_id},
429 {'p', "priority", "PRIORITY",
430 gettext_noop ("specify the priority of the content"),
431 1, &GNUNET_GETOPT_set_uint, &priority},
432 {'P', "pseudonym", "NAME",
433 gettext_noop
434 ("publish the files under the pseudonym NAME (place file into namespace)"),
435 1, &GNUNET_GETOPT_set_string, &pseudonym},
436 // *: option not yet used... (need FS API support!)
437 {'s', "simulate-only", NULL,
438 gettext_noop ("only simulate the process but do not do any "
439 "actual publishing (useful to compute URIs)"),
440 0, &GNUNET_GETOPT_set_one, &do_simulate},
441 {'t', "this", "ID",
442 gettext_noop ("set the ID of this version of the publication"
443 " (for namespace insertions only)"),
444 1, &GNUNET_GETOPT_set_string, &this_id},
445 // *: option not yet used... (need FS API support!)
446 {'u', "uri", "URI",
447 gettext_noop ("URI to be published (can be used instead of passing a "
448 "file to add keywords to the file with the respective URI)"),
449 1, &GNUNET_GETOPT_set_string, &uri_string},
450 GNUNET_GETOPT_OPTION_END
451};
452
453
454/**
455 * The main function to publish content to GNUnet.
456 *
457 * @param argc number of arguments from the command line
458 * @param argv command line arguments
459 * @return 0 ok, 1 on error
460 */
461int
462main (int argc, char *const *argv)
463{
464 return (GNUNET_OK ==
465 GNUNET_PROGRAM_run (argc,
466 argv,
467 "gnunet-publish",
468 gettext_noop
469 ("Publish files on GNUnet."),
470 options, &run, NULL)) ? ret : 1;
471}
472
473/* end of gnunet-publish.c */
474
475////////////////////////////////////////////////////////////////
476
477
478/**
479 * Print progess message.
480 */
481static void *
482printstatus (void *ctx, const GNUNET_FSUI_Event * event)
483{
484 unsigned long long delta;
485 char *fstring;
486
487 switch (event->type)
488 {
489 case GNUNET_FSUI_upload_progress:
490 if (*verboselevel)
491 {
492 char *ret;
493 GNUNET_CronTime now;
494
495 now = GNUNET_get_time ();
496 delta = event->data.UploadProgress.eta - now;
497 if (event->data.UploadProgress.eta < now)
498 delta = 0;
499 ret = GNUNET_get_time_interval_as_fancy_string (delta);
500 PRINTF (_("%16llu of %16llu bytes inserted "
501 "(estimating %6s to completion) - %s\n"),
502 event->data.UploadProgress.completed,
503 event->data.UploadProgress.total,
504 ret, event->data.UploadProgress.filename);
505 GNUNET_free (ret);
506 }
507 break;
508 case GNUNET_FSUI_upload_completed:
509 if (*verboselevel)
510 {
511 delta = GNUNET_get_time () - start_time;
512 PRINTF (_("Upload of `%s' complete, "
513 "%llu bytes took %llu seconds (%8.3f KiB/s).\n"),
514 event->data.UploadCompleted.filename,
515 event->data.UploadCompleted.total,
516 delta / GNUNET_CRON_SECONDS,
517 (delta == 0)
518 ? (double) (-1.0)
519 : (double) (event->data.UploadCompleted.total
520 / 1024.0 * GNUNET_CRON_SECONDS / delta));
521 }
522 fstring = GNUNET_ECRS_uri_to_string (event->data.UploadCompleted.uri);
523 printf (_("File `%s' has URI: %s\n"),
524 event->data.UploadCompleted.filename, fstring);
525 GNUNET_free (fstring);
526 if (ul == event->data.UploadCompleted.uc.pos)
527 {
528 postProcess (event->data.UploadCompleted.uri);
529 errorCode = 0;
530 GNUNET_shutdown_initiate ();
531 }
532 break;
533 case GNUNET_FSUI_upload_aborted:
534 printf (_("\nUpload aborted.\n"));
535 errorCode = 2;
536 GNUNET_shutdown_initiate ();
537 break;
538 case GNUNET_FSUI_upload_error:
539 printf (_("\nError uploading file: %s"),
540 event->data.UploadError.message);
541 errorCode = 3;
542 GNUNET_shutdown_initiate ();
543 break;
544 case GNUNET_FSUI_upload_started:
545 case GNUNET_FSUI_upload_stopped:
546 break;
547 default:
548 printf (_("\nUnexpected event: %d\n"), event->type);
549 GNUNET_GE_BREAK (ectx, 0);
550 break;
551 }
552 return NULL;
553}
554#endif
555
556/* end of gnunet-publish.c */