34
34
* <ulink type="http" url="http://groups.google.com/group/Google-Docs-Data-APIs/browse_thread/thread/bfc50e94e303a29a?pli=1">
35
35
* online explanation about the problem</ulink>.
38
* <title>Uploading a Document from Disk</title>
40
* GDataDocumentsService *service;
41
* GDataDocumentsDocument *document, *uploaded_document;
42
* GFile *document_file;
43
* GDataDocumentsFolder *destination_folder;
44
* GFileInfo *file_info;
45
* const gchar *slug, *content_type;
46
* GFileInputStream *file_stream;
47
* GDataUploadStream *upload_stream;
48
* GError *error = NULL;
50
* /<!-- -->* Create a service *<!-- -->/
51
* service = create_documents_service ();
53
* /<!-- -->* Get the document file to upload and the folder to upload it into *<!-- -->/
54
* document_file = g_file_new_for_path ("document.odt");
55
* destination_folder = query_user_for_destination_folder (service);
57
* /<!-- -->* Get the file's display name and content type *<!-- -->/
58
* file_info = g_file_query_info (document_file, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
59
* G_FILE_QUERY_INFO_NONE, NULL, &error);
61
* if (error != NULL) {
62
* g_error ("Error getting document file information: %s", error->message);
63
* g_error_free (error);
64
* g_object_unref (destination_folder);
65
* g_object_unref (document_file);
66
* g_object_unref (service);
70
* slug = g_file_info_get_display_name (file_info);
71
* content_type = g_file_info_get_content_type (file_info);
73
* /<!-- -->* Get an input stream for the file *<!-- -->/
74
* file_stream = g_file_read (document_file, NULL, &error);
76
* g_object_unref (document_file);
78
* if (error != NULL) {
79
* g_error ("Error getting document file stream: %s", error->message);
80
* g_error_free (error);
81
* g_object_unref (file_info);
82
* g_object_unref (destination_folder);
83
* g_object_unref (service);
87
* /<!-- -->* Create the document metadata to upload *<!-- -->/
88
* document = gdata_documents_text_new (NULL);
89
* gdata_entry_set_title (GDATA_ENTRY (document), "Document Title");
91
* /<!-- -->* Get an upload stream for the document *<!-- -->/
92
* upload_stream = gdata_documents_service_upload_document (service, document, slug, content_type, destination_folder, NULL, &error);
94
* g_object_unref (document);
95
* g_object_unref (file_info);
96
* g_object_unref (destination_folder);
98
* if (error != NULL) {
99
* g_error ("Error getting upload stream: %s", error->message);
100
* g_error_free (error);
101
* g_object_unref (file_stream);
102
* g_object_unref (service);
106
* /<!-- -->* Upload the document. This is a blocking operation, and should normally be done asynchronously. *<!-- -->/
107
* g_output_stream_splice (G_OUTPUT_STREAM (upload_stream), G_INPUT_STREAM (file_stream),
108
* G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error);
110
* g_object_unref (file_stream);
112
* if (error != NULL) {
113
* g_error ("Error splicing streams: %s", error->message);
114
* g_error_free (error);
115
* g_object_unref (upload_stream);
116
* g_object_unref (service);
120
* /<!-- -->* Finish off the upload by parsing the returned updated document metadata entry *<!-- -->/
121
* uploaded_document = gdata_documents_service_finish_upload (service, upload_stream, &error);
123
* g_object_unref (upload_stream);
124
* g_object_unref (service);
126
* if (error != NULL) {
127
* g_error ("Error uploading document: %s", error->message);
128
* g_error_free (error);
132
* /<!-- -->* Do something with the uploaded document *<!-- -->/
134
* g_object_unref (uploaded_document);
138
* The Documents service can be manipulated using batch operations, too. See the
139
* <ulink type="http" url="http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html#ACLBatch">online documentation on batch
140
* operations</ulink> for more information.
143
* <title>Performing a Batch Operation on Documents</title>
145
* GDataDocumentsService *service;
146
* GDataBatchOperation *operation;
148
* GDataLink *batch_link;
150
* GError *error = NULL;
152
* /<!-- -->* Create a service *<!-- -->/
153
* service = create_documents_service ();
155
* /<!-- -->* Create the batch operation; this requires that we have done a query first so that we can get the batch link *<!-- -->/
156
* feed = do_some_query (service);
157
* batch_link = gdata_feed_look_up_link (feed, GDATA_LINK_BATCH);
158
* operation = gdata_batchable_create_operation (GDATA_BATCHABLE (service), gdata_link_get_uri (batch_link));
159
* g_object_unref (feed);
161
* gdata_batch_operation_add_query (operation, presentation_entry_id_to_query, GDATA_TYPE_DOCUMENTS_PRESENTATION,
162
* (GDataBatchOperationCallback) batch_query_cb, user_data);
163
* gdata_batch_operation_add_insertion (operation, new_entry, (GDataBatchOperationCallback) batch_insertion_cb, user_data);
164
* gdata_batch_operation_add_update (operation, old_entry, (GDataBatchOperationCallback) batch_update_cb, user_data);
165
* gdata_batch_operation_add_deletion (operation, entry_to_delete, (GDataBatchOperationCallback) batch_deletion_cb, user_data);
167
* /<!-- -->* Run the batch operation and handle the results in the various callbacks *<!-- -->/
168
* gdata_test_batch_operation_run (operation, NULL, &error);
170
* g_object_unref (operation);
171
* g_object_unref (service);
173
* if (error != NULL) {
174
* g_error ("Error running batch operation: %s", error->message);
175
* g_error_free (error);
180
* batch_query_cb (guint operation_id, GDataBatchOperationType operation_type, GDataEntry *entry, GError *error, gpointer user_data)
182
* /<!-- -->* operation_type == GDATA_BATCH_OPERATION_QUERY *<!-- -->/
183
* /<!-- -->* Reference and do something with the returned entry. *<!-- -->/
187
* batch_insertion_cb (guint operation_id, GDataBatchOperationType operation_type, GDataEntry *entry, GError *error, gpointer user_data)
189
* /<!-- -->* operation_type == GDATA_BATCH_OPERATION_INSERTION *<!-- -->/
190
* /<!-- -->* Reference and do something with the returned entry. *<!-- -->/
194
* batch_update_cb (guint operation_id, GDataBatchOperationType operation_type, GDataEntry *entry, GError *error, gpointer user_data)
196
* /<!-- -->* operation_type == GDATA_BATCH_OPERATION_UPDATE *<!-- -->/
197
* /<!-- -->* Reference and do something with the returned entry. *<!-- -->/
201
* batch_deletion_cb (guint operation_id, GDataBatchOperationType operation_type, GDataEntry *entry, GError *error, gpointer user_data)
203
* /<!-- -->* operation_type == GDATA_BATCH_OPERATION_DELETION, entry == NULL *<!-- -->/
291
460
gdata_service_set_proxy_uri (GDATA_DOCUMENTS_SERVICE (self)->priv->spreadsheet_service, proxy_uri);
294
static GDataDocumentsEntry *
295
upload_update_document (GDataDocumentsService *self, GDataDocumentsEntry *document, GFile *document_file, const gchar *method,
296
const gchar *upload_uri, GCancellable *cancellable, GError **error)
463
static GDataUploadStream *
464
upload_update_document (GDataDocumentsService *self, GDataDocumentsDocument *document, const gchar *slug, const gchar *content_type,
465
const gchar *method, const gchar *upload_uri, GCancellable *cancellable)
298
GDataDocumentsEntry *new_entry;
299
GOutputStream *output_stream;
300
GInputStream *input_stream;
301
const gchar *slug = NULL, *content_type = NULL, *response_body;
302
gssize response_length;
303
GFileInfo *file_info = NULL;
304
GType new_document_type = G_TYPE_INVALID;
305
GError *child_error = NULL;
307
/* Get some information about the file we're uploading */
308
if (document_file != NULL) {
309
/* Get the slug and content type */
310
file_info = g_file_query_info (document_file, "standard::display-name,standard::content-type", G_FILE_QUERY_INFO_NONE, NULL, error);
311
if (file_info == NULL)
314
slug = g_file_info_get_display_name (file_info);
315
content_type = g_file_info_get_content_type (file_info);
317
/* Corrects a bug on spreadsheet content types handling
318
* The content type for ODF spreadsheets is "application/vnd.oasis.opendocument.spreadsheet" for my ODF spreadsheet;
319
* but Google Documents' spreadsheet service is waiting for "application/x-vnd.oasis.opendocument.spreadsheet"
321
* Bug filed with Google: http://code.google.com/p/gdata-issues/issues/detail?id=1127 */
322
if (strcmp (content_type, "application/vnd.oasis.opendocument.spreadsheet") == 0)
323
content_type = "application/x-vnd.oasis.opendocument.spreadsheet";
325
if (document == NULL) {
326
/* Get the document type of the document which is being uploaded */
327
if (strcmp (content_type, "application/x-vnd.oasis.opendocument.spreadsheet") == 0 ||
328
strcmp (content_type, "text/tab-separated-values") == 0 ||
329
strcmp (content_type, "application/x-vnd.oasis.opendocument.spreadsheet") == 0 ||
330
strcmp (content_type, "application/vnd.ms-excel") == 0) {
331
new_document_type = GDATA_TYPE_DOCUMENTS_SPREADSHEET;
332
} else if (strcmp (content_type, "application/msword") == 0 ||
333
strcmp (content_type, "application/vnd.oasis.opendocument.text") == 0 ||
334
strcmp (content_type, "application/rtf") == 0 ||
335
strcmp (content_type, "text/html") == 0 ||
336
strcmp (content_type, "application/vnd.sun.xml.writer") == 0 ||
337
strcmp (content_type, "text/plain") == 0) {
338
new_document_type = GDATA_TYPE_DOCUMENTS_TEXT;
339
} else if (strcmp (content_type, "application/vnd.ms-powerpoint") == 0) {
340
new_document_type = GDATA_TYPE_DOCUMENTS_PRESENTATION;
342
g_set_error_literal (error, GDATA_DOCUMENTS_SERVICE_ERROR, GDATA_DOCUMENTS_SERVICE_ERROR_INVALID_CONTENT_TYPE,
343
_("The supplied document had an invalid content type."));
344
if (file_info != NULL)
345
g_object_unref (file_info);
351
/* Determine the type of the document we're uploading */
352
if (document != NULL)
353
new_document_type = G_OBJECT_TYPE (document);
467
/* Corrects a bug on spreadsheet content types handling
468
* The content type for ODF spreadsheets is "application/vnd.oasis.opendocument.spreadsheet" for my ODF spreadsheet;
469
* but Google Documents' spreadsheet service is waiting for "application/x-vnd.oasis.opendocument.spreadsheet"
471
* Bug filed with Google: http://code.google.com/p/gdata-issues/issues/detail?id=1127 */
472
if (strcmp (content_type, "application/vnd.oasis.opendocument.spreadsheet") == 0)
473
content_type = "application/x-vnd.oasis.opendocument.spreadsheet";
355
475
/* We need streaming file I/O: GDataUploadStream */
356
output_stream = gdata_upload_stream_new (GDATA_SERVICE (self), method, upload_uri, GDATA_ENTRY (document), slug, content_type);
358
if (file_info != NULL)
359
g_object_unref (file_info);
360
if (output_stream == NULL)
363
/* Open the document file for reading and pipe it to the upload stream */
364
input_stream = G_INPUT_STREAM (g_file_read (document_file, cancellable, error));
365
if (input_stream == NULL) {
366
g_object_unref (output_stream);
370
g_output_stream_splice (output_stream, input_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
371
cancellable, &child_error);
373
g_object_unref (input_stream);
374
if (child_error != NULL) {
375
g_object_unref (output_stream);
376
g_propagate_error (error, child_error);
380
/* Get and parse the response from the server */
381
response_body = gdata_upload_stream_get_response (GDATA_UPLOAD_STREAM (output_stream), &response_length);
382
g_assert (response_body != NULL && response_length > 0);
384
new_entry = GDATA_DOCUMENTS_ENTRY (gdata_parsable_new_from_xml (new_document_type, response_body, (gint) response_length, error));
385
g_object_unref (output_stream);
476
return GDATA_UPLOAD_STREAM (gdata_upload_stream_new (GDATA_SERVICE (self), method, upload_uri, GDATA_ENTRY (document), slug, content_type,
391
481
* gdata_documents_service_upload_document:
392
482
* @self: an authenticated #GDataDocumentsService
393
* @document: (allow-none): the #GDataDocumentsEntry to insert, or %NULL
394
* @document_file: (allow-none): the document to upload, or %NULL
483
* @document: (allow-none): the #GDataDocumentsDocument to insert, or %NULL
484
* @slug: the filename to give to the uploaded document
485
* @content_type: the content type of the uploaded data
395
486
* @folder: (allow-none): the folder to which the document should be uploaded, or %NULL
396
* @cancellable: optional #GCancellable object, or %NULL
487
* @cancellable: (allow-none): a #GCancellable for the entire upload stream, or %NULL
397
488
* @error: a #GError, or %NULL
399
* Uploads a document to Google Documents, using the properties from @document and the document file pointed to by @document_file.
401
* If @document is %NULL, only the document file will be uploaded. The new document entry will be named after the document file's name,
402
* and will have default metadata.
404
* If @document_file is %NULL, only the document metadata will be uploaded. A blank document file will be created with the name
405
* <literal>new document</literal> and the specified metadata. @document and @document_file cannot both be %NULL, but can both have values.
407
* The updated @document_entry will be returned on success, containing updated metadata.
409
* If there is a problem reading @document_file, an error from g_file_load_contents() or g_file_query_info() will be returned. Other errors from
410
* #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
412
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
490
* Uploads a document to Google Documents, using the properties from @document and the document data written to the resulting #GDataUploadStream. If
491
* the document data does not need to be provided at the moment, just the metadata, use gdata_service_insert_entry() instead (e.g. in the case of
492
* creating a new, empty file to be edited at a later date).
494
* If @document is %NULL, only the document data will be uploaded. The new document entry will be named using @slug, and will have default metadata.
496
* The stream returned by this function should be written to using the standard #GOutputStream methods, asychronously or synchronously. Once the stream
497
* is closed (using g_output_stream_close()), gdata_documents_service_finish_upload() should be called on it to parse and return the updated
498
* #GDataDocumentsDocument for the document. This must be done, as @document isn't updated in-place.
500
* In order to cancel the upload, a #GCancellable passed in to @cancellable must be cancelled using g_cancellable_cancel(). Cancelling the individual
501
* #GOutputStream operations on the #GDataUploadStream will not cancel the entire upload; merely the write or close operation in question. See the
502
* #GDataUploadStream:cancellable for more details.
504
* Any upload errors will be thrown by the stream methods, and may come from the #GDataServiceError domain.
506
* Return value: (transfer full): a #GDataUploadStream to write the document data to, or %NULL; unref with g_object_unref()
416
GDataDocumentsEntry *
417
gdata_documents_service_upload_document (GDataDocumentsService *self, GDataDocumentsEntry *document, GFile *document_file,
511
gdata_documents_service_upload_document (GDataDocumentsService *self, GDataDocumentsDocument *document, const gchar *slug, const gchar *content_type,
418
512
GDataDocumentsFolder *folder, GCancellable *cancellable, GError **error)
420
GDataDocumentsEntry *new_document;
514
GDataUploadStream *upload_stream;
421
515
gchar *upload_uri;
423
517
g_return_val_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self), NULL);
424
g_return_val_if_fail (document == NULL || GDATA_IS_DOCUMENTS_ENTRY (document), NULL);
425
g_return_val_if_fail (document_file == NULL || G_IS_FILE (document_file), NULL);
426
g_return_val_if_fail (document != NULL || document_file != NULL, NULL);
518
g_return_val_if_fail (document == NULL || GDATA_IS_DOCUMENTS_DOCUMENT (document), NULL);
519
g_return_val_if_fail (slug != NULL && *slug != '\0', NULL);
520
g_return_val_if_fail (content_type != NULL && *content_type != '\0', NULL);
427
521
g_return_val_if_fail (folder == NULL || GDATA_IS_DOCUMENTS_FOLDER (folder), NULL);
428
522
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
429
523
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
443
537
upload_uri = gdata_documents_service_get_upload_uri (folder);
445
if (document_file == NULL) {
446
new_document = GDATA_DOCUMENTS_ENTRY (gdata_service_insert_entry (GDATA_SERVICE (self), upload_uri, GDATA_ENTRY (document),
447
cancellable, error));
449
new_document = upload_update_document (self, document, document_file, SOUP_METHOD_POST, upload_uri, cancellable, error);
538
upload_stream = upload_update_document (self, document, slug, content_type, SOUP_METHOD_POST, upload_uri, cancellable);
451
539
g_free (upload_uri);
541
return upload_stream;
457
545
* gdata_documents_service_update_document:
458
546
* @self: a #GDataDocumentsService
459
* @document: the #GDataDocumentsEntry to update
460
* @document_file: (allow-none): the local document file containing the new data, or %NULL
461
* @cancellable: optional #GCancellable object, or %NULL
547
* @document: the #GDataDocumentsDocument to update
548
* @slug: the filename to give to the uploaded document
549
* @content_type: the content type of the uploaded data
550
* @cancellable: (allow-none): a #GCancellable for the entire upload stream, or %NULL
462
551
* @error: a #GError, or %NULL
464
* Update the document using the properties from @document and the document file pointed to by @document_file. If the document file does not
465
* need to be changed, @document_file can be %NULL.
467
* If there is a problem reading @document_file, an error from g_file_load_contents() or g_file_query_info() will be returned. Other errors from
468
* #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
470
* For more details, see gdata_service_insert_entry().
472
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
553
* Update the document using the properties from @document and the document data written to the resulting #GDataUploadStream. If the document data does
554
* not need to be changed, just the metadata, use gdata_service_update_entry() instead.
556
* The stream returned by this function should be written to using the standard #GOutputStream methods, asychronously or synchronously. Once the stream
557
* is closed (using g_output_stream_close()), gdata_documents_service_finish_upload() should be called on it to parse and return the updated
558
* #GDataDocumentsDocument for the document. This must be done, as @document isn't updated in-place.
560
* In order to cancel the update, a #GCancellable passed in to @cancellable must be cancelled using g_cancellable_cancel(). Cancelling the individual
561
* #GOutputStream operations on the #GDataUploadStream will not cancel the entire update; merely the write or close operation in question. See the
562
* #GDataUploadStream:cancellable for more details.
564
* Any upload errors will be thrown by the stream methods, and may come from the #GDataServiceError domain.
566
* For more information, see gdata_service_update_entry().
568
* Return value: (transfer full): a #GDataUploadStream to write the document data to; unref with g_object_unref()
476
GDataDocumentsEntry *
477
gdata_documents_service_update_document (GDataDocumentsService *self, GDataDocumentsEntry *document, GFile *document_file,
573
gdata_documents_service_update_document (GDataDocumentsService *self, GDataDocumentsDocument *document, const gchar *slug, const gchar *content_type,
478
574
GCancellable *cancellable, GError **error)
480
576
GDataLink *update_link;
482
578
g_return_val_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self), NULL);
483
g_return_val_if_fail (GDATA_IS_DOCUMENTS_ENTRY (document), NULL);
484
g_return_val_if_fail (document_file == NULL || G_IS_FILE (document_file), NULL);
579
g_return_val_if_fail (GDATA_IS_DOCUMENTS_DOCUMENT (document), NULL);
580
g_return_val_if_fail (slug != NULL && *slug != '\0', NULL);
581
g_return_val_if_fail (content_type != NULL && *content_type != '\0', NULL);
485
582
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
486
583
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
494
if (document_file == NULL)
495
return GDATA_DOCUMENTS_ENTRY (gdata_service_update_entry (GDATA_SERVICE (self), GDATA_ENTRY (document), cancellable, error));
497
591
update_link = gdata_entry_look_up_link (GDATA_ENTRY (document), GDATA_LINK_EDIT_MEDIA);
498
592
g_assert (update_link != NULL);
500
return upload_update_document (self, document, document_file, SOUP_METHOD_PUT, gdata_link_get_uri (update_link), cancellable, error);
504
* gdata_documents_service_move_document_to_folder:
594
return upload_update_document (self, document, slug, content_type, SOUP_METHOD_PUT, gdata_link_get_uri (update_link), cancellable);
598
* gdata_documents_service_finish_upload:
599
* @self: a #GDataDocumentsService
600
* @upload_stream: the #GDataUploadStream from the operation
601
* @error: a #GError, or %NULL
603
* Finish off a document upload or update operation started by gdata_documents_service_upload_document() or gdata_documents_service_update_document(),
604
* parsing the result and returning the new or updated #GDataDocumentsDocument.
606
* If an error occurred during the upload or update operation, it will have been returned during the operation (e.g. by g_output_stream_splice() or one
607
* of the other stream methods). In such a case, %NULL will be returned but @error will remain unset. @error is only set in the case that the server
608
* indicates that the operation was successful, but an error is encountered in parsing the result sent by the server.
610
* In the case that no #GDataDocumentsDocument was passed (to gdata_documents_service_upload_document() or gdata_documents_service_update_document())
611
* when starting the operation, %GDATA_DOCUMENTS_SERVICE_ERROR_INVALID_CONTENT_TYPE will be thrown in @error if the content type of the uploaded data
612
* could not be mapped to a document type with which to interpret the response from the server.
614
* Return value: (transfer full): the new or updated #GDataDocumentsDocument, or %NULL; unref with g_object_unref()
618
GDataDocumentsDocument *
619
gdata_documents_service_finish_upload (GDataDocumentsService *self, GDataUploadStream *upload_stream, GError **error)
621
const gchar *response_body, *content_type;
622
gssize response_length;
624
GType new_document_type = G_TYPE_INVALID;
626
/* Determine the type of the document we've uploaded */
627
entry = gdata_upload_stream_get_entry (upload_stream);
628
content_type = gdata_upload_stream_get_content_type (upload_stream);
631
new_document_type = G_OBJECT_TYPE (entry);
632
} else if (strcmp (content_type, "application/x-vnd.oasis.opendocument.spreadsheet") == 0 ||
633
strcmp (content_type, "text/tab-separated-values") == 0 ||
634
strcmp (content_type, "application/x-vnd.oasis.opendocument.spreadsheet") == 0 ||
635
strcmp (content_type, "application/vnd.ms-excel") == 0) {
636
new_document_type = GDATA_TYPE_DOCUMENTS_SPREADSHEET;
637
} else if (strcmp (content_type, "application/msword") == 0 ||
638
strcmp (content_type, "application/vnd.oasis.opendocument.text") == 0 ||
639
strcmp (content_type, "application/rtf") == 0 ||
640
strcmp (content_type, "text/html") == 0 ||
641
strcmp (content_type, "application/vnd.sun.xml.writer") == 0 ||
642
strcmp (content_type, "text/plain") == 0) {
643
new_document_type = GDATA_TYPE_DOCUMENTS_TEXT;
644
} else if (strcmp (content_type, "application/vnd.ms-powerpoint") == 0) {
645
new_document_type = GDATA_TYPE_DOCUMENTS_PRESENTATION;
648
if (g_type_is_a (new_document_type, GDATA_TYPE_DOCUMENTS_DOCUMENT) == FALSE) {
649
g_set_error (error, GDATA_DOCUMENTS_SERVICE_ERROR, GDATA_DOCUMENTS_SERVICE_ERROR_INVALID_CONTENT_TYPE,
650
_("The content type of the supplied document ('%s') could not be recognized."), content_type);
654
/* Get and parse the response from the server */
655
response_body = gdata_upload_stream_get_response (upload_stream, &response_length);
656
if (response_body == NULL || response_length == 0)
659
return GDATA_DOCUMENTS_DOCUMENT (gdata_parsable_new_from_xml (new_document_type, response_body, (gint) response_length, error));
663
* gdata_documents_service_add_entry_to_folder:
505
664
* @self: an authenticated #GDataDocumentsService
506
* @document: the #GDataDocumentsEntry to move
507
* @folder: the #GDataDocumentsFolder to move @document into
665
* @entry: the #GDataDocumentsEntry to move
666
* @folder: the #GDataDocumentsFolder to move @entry into
508
667
* @cancellable: optional #GCancellable object, or %NULL
509
668
* @error: a #GError, or %NULL
511
* Move the given @document to the specified @folder. If the document is already in another folder, it will be added to
512
* the new folder, but will also remain in any previous folders.
670
* Add the given @entry to the specified @folder, and return an updated #GDataDocumentsEntry for @entry. If the @entry is already in another folder, it
671
* will be added to the new folder, but will also remain in its other folders. Note that @entry can be either a #GDataDocumentsDocument or a
672
* #GDataDocumentsFolder.
514
* Errors from #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
674
* Errors from #GDataServiceError can be returned for exceptional conditions, as determined by the server.
516
676
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
520
680
GDataDocumentsEntry *
521
gdata_documents_service_move_document_to_folder (GDataDocumentsService *self, GDataDocumentsEntry *document, GDataDocumentsFolder *folder,
522
GCancellable *cancellable, GError **error)
681
gdata_documents_service_add_entry_to_folder (GDataDocumentsService *self, GDataDocumentsEntry *entry, GDataDocumentsFolder *folder,
682
GCancellable *cancellable, GError **error)
524
GDataDocumentsEntry *new_document;
684
GDataDocumentsEntry *new_entry;
525
685
gchar *uri, *upload_data;
526
686
const gchar *folder_id;
527
687
SoupMessage *message;
530
690
g_return_val_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self), NULL);
531
g_return_val_if_fail (GDATA_IS_DOCUMENTS_ENTRY (document), NULL);
691
g_return_val_if_fail (GDATA_IS_DOCUMENTS_ENTRY (entry), NULL);
532
692
g_return_val_if_fail (GDATA_IS_DOCUMENTS_FOLDER (folder), NULL);
533
693
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
534
694
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
536
696
if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
537
697
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
538
_("You must be authenticated to move documents."));
698
_("You must be authenticated to move documents and folders."));
570
/* Parse the XML; and update the document */
730
/* Parse the XML; and update the entry */
571
731
g_assert (message->response_body->data != NULL);
572
new_document = GDATA_DOCUMENTS_ENTRY (gdata_parsable_new_from_xml (G_OBJECT_TYPE (document), message->response_body->data,
573
message->response_body->length, error));
732
new_entry = GDATA_DOCUMENTS_ENTRY (gdata_parsable_new_from_xml (G_OBJECT_TYPE (entry), message->response_body->data,
733
message->response_body->length, error));
574
734
g_object_unref (message);
580
* gdata_documents_service_remove_document_from_folder:
581
* @self: a #GDataDocumentsService
582
* @document: the #GDataDocumentsEntry to remove
583
* @folder: the #GDataDocumentsFolder from which we should remove @document
584
* @cancellable: optional #GCancellable object, or %NULL
585
* @error: a #GError, or %NULL
587
* Remove the #GDataDocumentsEntry @document from the GDataDocumentsFolder @folder, and updates the document entry @document.
589
* Errors from #GDataServiceError can be returned for other exceptional conditions, as determined by the server.
591
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
595
GDataDocumentsEntry *
596
gdata_documents_service_remove_document_from_folder (GDataDocumentsService *self, GDataDocumentsEntry *document, GDataDocumentsFolder *folder,
597
GCancellable *cancellable, GError **error)
599
const gchar *folder_id, *document_id;
740
GDataDocumentsEntry *entry;
741
GDataDocumentsFolder *folder;
742
} AddEntryToFolderData;
745
add_entry_to_folder_data_free (AddEntryToFolderData *data)
747
g_object_unref (data->entry);
748
g_object_unref (data->folder);
749
g_slice_free (AddEntryToFolderData, data);
753
add_entry_to_folder_thread (GSimpleAsyncResult *result, GDataDocumentsService *service, GCancellable *cancellable)
755
GDataDocumentsEntry *updated_entry;
756
AddEntryToFolderData *data;
757
GError *error = NULL;
759
data = g_simple_async_result_get_op_res_gpointer (result);
761
/* Add the entry to the folder and return */
762
updated_entry = gdata_documents_service_add_entry_to_folder (service, data->entry, data->folder, cancellable, &error);
764
g_simple_async_result_set_from_error (result, error);
765
g_error_free (error);
769
/* Return the updated entry */
770
g_simple_async_result_set_op_res_gpointer (result, updated_entry, (GDestroyNotify) g_object_unref);
774
* gdata_documents_service_add_entry_to_folder_async:
775
* @self: a #GDataDocumentsService
776
* @entry: the #GDataDocumentsEntry to add to @folder
777
* @folder: the #GDataDocumentsFolder to add @entry to
778
* @cancellable: optional #GCancellable object, or %NULL
779
* @callback: a #GAsyncReadyCallback to call when the operation is finished, or %NULL
780
* @user_data: (closure): data to pass to the @callback function
782
* Add the given @entry to the specified @folder. @self, @entry and @folder are all reffed when this function is called, so can safely be unreffed
783
* after this function returns.
785
* For more details, see gdata_documents_service_add_entry_to_folder(), which is the synchronous version of this function.
787
* When the operation is finished, @callback will be called. You can then call gdata_documents_service_add_entry_to_folder_finish() to get the results
793
gdata_documents_service_add_entry_to_folder_async (GDataDocumentsService *self, GDataDocumentsEntry *entry, GDataDocumentsFolder *folder,
794
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
796
GSimpleAsyncResult *result;
797
AddEntryToFolderData *data;
799
g_return_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self));
800
g_return_if_fail (GDATA_IS_DOCUMENTS_ENTRY (entry));
801
g_return_if_fail (GDATA_IS_DOCUMENTS_FOLDER (folder));
802
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
804
data = g_slice_new (AddEntryToFolderData);
805
data->entry = g_object_ref (entry);
806
data->folder = g_object_ref (folder);
808
result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gdata_documents_service_add_entry_to_folder_async);
809
g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) add_entry_to_folder_data_free);
810
g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) add_entry_to_folder_thread, G_PRIORITY_DEFAULT, cancellable);
811
g_object_unref (result);
815
* gdata_documents_service_add_entry_to_folder_finish:
816
* @self: a #GDataDocumentsService
817
* @async_result: a #GAsyncResult
818
* @error: a #GError, or %NULL
820
* Finish an asynchronous operation to add a #GDataDocumentsEntry to a folder started with gdata_documents_service_add_entry_to_folder_async().
822
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
826
GDataDocumentsEntry *
827
gdata_documents_service_add_entry_to_folder_finish (GDataDocumentsService *self, GAsyncResult *async_result, GError **error)
829
GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (async_result);
830
GDataDocumentsEntry *entry;
832
g_return_val_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self), NULL);
833
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL);
834
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
836
g_warn_if_fail (g_simple_async_result_get_source_tag (result) == gdata_documents_service_add_entry_to_folder_async);
838
if (g_simple_async_result_propagate_error (result, error) == TRUE)
841
entry = g_simple_async_result_get_op_res_gpointer (result);
843
return g_object_ref (entry);
845
g_assert_not_reached ();
849
* gdata_documents_service_remove_entry_from_folder:
850
* @self: a #GDataDocumentsService
851
* @entry: the #GDataDocumentsEntry to remove
852
* @folder: the #GDataDocumentsFolder from which we should remove @entry
853
* @cancellable: optional #GCancellable object, or %NULL
854
* @error: a #GError, or %NULL
856
* Remove the given @entry from @folder, and return an updated #GDataDocumentsEntry for @entry. @entry will remain a member of any other folders it's
857
* currently in. Note that @entry can be either a #GDataDocumentsDocument or a #GDataDocumentsFolder.
859
* Errors from #GDataServiceError can be returned for exceptional conditions, as determined by the server.
861
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
865
GDataDocumentsEntry *
866
gdata_documents_service_remove_entry_from_folder (GDataDocumentsService *self, GDataDocumentsEntry *entry, GDataDocumentsFolder *folder,
867
GCancellable *cancellable, GError **error)
869
const gchar *folder_id, *entry_id;
600
870
SoupMessage *message;
604
874
g_return_val_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self), NULL);
605
g_return_val_if_fail (GDATA_IS_DOCUMENTS_ENTRY (document), NULL);
875
g_return_val_if_fail (GDATA_IS_DOCUMENTS_ENTRY (entry), NULL);
606
876
g_return_val_if_fail (GDATA_IS_DOCUMENTS_FOLDER (folder), NULL);
607
877
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
608
878
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
610
880
if (gdata_service_is_authenticated (GDATA_SERVICE (self)) == FALSE) {
611
881
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
612
_("You must be authenticated to move documents."));
882
_("You must be authenticated to move documents and folders."));
616
886
/* Get the document ID */
617
887
folder_id = gdata_documents_entry_get_document_id (GDATA_DOCUMENTS_ENTRY (folder));
618
document_id = gdata_documents_entry_get_document_id (GDATA_DOCUMENTS_ENTRY (document));
888
entry_id = gdata_documents_entry_get_document_id (entry);
619
889
g_assert (folder_id != NULL);
620
g_assert (document_id != NULL);
890
g_assert (entry_id != NULL);
622
if (GDATA_IS_DOCUMENTS_PRESENTATION (document)) {
892
if (GDATA_IS_DOCUMENTS_PRESENTATION (entry)) {
623
893
uri = _gdata_service_build_uri (FALSE, "http://docs.google.com/feeds/folders/private/full/folder%%3A%s/presentation%%3A%s",
624
folder_id, document_id);
625
} else if (GDATA_IS_DOCUMENTS_SPREADSHEET (document)) {
894
folder_id, entry_id);
895
} else if (GDATA_IS_DOCUMENTS_SPREADSHEET (entry)) {
626
896
uri = _gdata_service_build_uri (FALSE, "http://docs.google.com/feeds/folders/private/full/folder%%3A%s/spreadsheet%%3A%s",
627
folder_id, document_id);
628
} else if (GDATA_IS_DOCUMENTS_TEXT (document)) {
897
folder_id, entry_id);
898
} else if (GDATA_IS_DOCUMENTS_TEXT (entry)) {
629
899
uri = _gdata_service_build_uri (FALSE, "http://docs.google.com/feeds/folders/private/full/folder%%3A%s/document%%3A%s",
630
folder_id, document_id);
631
} else if (GDATA_IS_DOCUMENTS_FOLDER (document)) {
900
folder_id, entry_id);
901
} else if (GDATA_IS_DOCUMENTS_FOLDER (entry)) {
632
902
uri = _gdata_service_build_uri (FALSE, "http://docs.google.com/feeds/folders/private/full/folder%%3A%s/folder%%3A%s",
633
folder_id, document_id);
903
folder_id, entry_id);
635
905
g_assert_not_reached ();
638
message = _gdata_service_build_message (GDATA_SERVICE (self), SOUP_METHOD_DELETE, uri, gdata_entry_get_etag (GDATA_ENTRY (document)), TRUE);
908
message = _gdata_service_build_message (GDATA_SERVICE (self), SOUP_METHOD_DELETE, uri, gdata_entry_get_etag (GDATA_ENTRY (entry)), TRUE);
641
911
/* Send the message */
660
930
/* Google's servers don't return an updated copy of the entry, so we have to query for it again.
661
931
* See: http://code.google.com/p/gdata-issues/issues/detail?id=1380 */
662
return GDATA_DOCUMENTS_ENTRY (gdata_service_query_single_entry (GDATA_SERVICE (self), gdata_entry_get_id (GDATA_ENTRY (document)), NULL,
663
G_OBJECT_TYPE (document), cancellable, error));
932
return GDATA_DOCUMENTS_ENTRY (gdata_service_query_single_entry (GDATA_SERVICE (self), gdata_entry_get_id (GDATA_ENTRY (entry)), NULL,
933
G_OBJECT_TYPE (entry), cancellable, error));
937
GDataDocumentsEntry *entry;
938
GDataDocumentsFolder *folder;
939
} RemoveEntryFromFolderData;
942
remove_entry_from_folder_data_free (RemoveEntryFromFolderData *data)
944
g_object_unref (data->entry);
945
g_object_unref (data->folder);
946
g_slice_free (RemoveEntryFromFolderData, data);
950
remove_entry_from_folder_thread (GSimpleAsyncResult *result, GDataDocumentsService *service, GCancellable *cancellable)
952
GDataDocumentsEntry *updated_entry;
953
RemoveEntryFromFolderData *data;
954
GError *error = NULL;
956
data = g_simple_async_result_get_op_res_gpointer (result);
958
/* Remove the entry from the folder and return */
959
updated_entry = gdata_documents_service_remove_entry_from_folder (service, data->entry, data->folder, cancellable, &error);
961
g_simple_async_result_set_from_error (result, error);
962
g_error_free (error);
966
/* Return the updated entry */
967
g_simple_async_result_set_op_res_gpointer (result, updated_entry, (GDestroyNotify) g_object_unref);
971
* gdata_documents_service_remove_entry_from_folder_async:
972
* @self: a #GDataDocumentsService
973
* @entry: the #GDataDocumentsEntry to remove from @folder
974
* @folder: the #GDataDocumentsFolder to remove @entry from
975
* @cancellable: optional #GCancellable object, or %NULL
976
* @callback: a #GAsyncReadyCallback to call when the operation is finished, or %NULL
977
* @user_data: (closure): data to pass to the @callback function
979
* Remove the given @entry from the specified @folder. @self, @entry and @folder are all reffed when this function is called, so can safely be unreffed
980
* after this function returns.
982
* For more details, see gdata_documents_service_remove_entry_from_folder(), which is the synchronous version of this function.
984
* When the operation is finished, @callback will be called. You can then call gdata_documents_service_remove_entry_from_folder_finish() to get the
985
* results of the operation.
990
gdata_documents_service_remove_entry_from_folder_async (GDataDocumentsService *self, GDataDocumentsEntry *entry, GDataDocumentsFolder *folder,
991
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
993
GSimpleAsyncResult *result;
994
RemoveEntryFromFolderData *data;
996
g_return_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self));
997
g_return_if_fail (GDATA_IS_DOCUMENTS_ENTRY (entry));
998
g_return_if_fail (GDATA_IS_DOCUMENTS_FOLDER (folder));
999
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1001
data = g_slice_new (RemoveEntryFromFolderData);
1002
data->entry = g_object_ref (entry);
1003
data->folder = g_object_ref (folder);
1005
result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, gdata_documents_service_remove_entry_from_folder_async);
1006
g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) remove_entry_from_folder_data_free);
1007
g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) remove_entry_from_folder_thread, G_PRIORITY_DEFAULT, cancellable);
1008
g_object_unref (result);
1012
* gdata_documents_service_remove_entry_from_folder_finish:
1013
* @self: a #GDataDocumentsService
1014
* @async_result: a #GAsyncResult
1015
* @error: a #GError, or %NULL
1017
* Finish an asynchronous operation to remove a #GDataDocumentsEntry from a folder started with
1018
* gdata_documents_service_remove_entry_from_folder_async().
1020
* Return value: (transfer full): an updated #GDataDocumentsEntry, or %NULL; unref with g_object_unref()
1024
GDataDocumentsEntry *
1025
gdata_documents_service_remove_entry_from_folder_finish (GDataDocumentsService *self, GAsyncResult *async_result, GError **error)
1027
GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (async_result);
1028
GDataDocumentsEntry *entry;
1030
g_return_val_if_fail (GDATA_IS_DOCUMENTS_SERVICE (self), NULL);
1031
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL);
1032
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1034
g_warn_if_fail (g_simple_async_result_get_source_tag (result) == gdata_documents_service_remove_entry_from_folder_async);
1036
if (g_simple_async_result_propagate_error (result, error) == TRUE)
1039
entry = g_simple_async_result_get_op_res_gpointer (result);
1041
return g_object_ref (entry);
1043
g_assert_not_reached ();