~ubuntu-branches/ubuntu/oneiric/libgdata/oneiric-backports

« back to all changes in this revision

Viewing changes to gdata/services/contacts/gdata-contacts-contact.c

  • Committer: Package Import Robot
  • Author(s): Evan Broder
  • Date: 2011-11-15 21:59:48 UTC
  • mfrom: (4.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20111115215948-e17s889ocgu5fv4f
Tags: 0.10.1-1~oneiric1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
214
214
enum {
215
215
        PROP_EDITED = 1,
216
216
        PROP_DELETED,
217
 
        PROP_HAS_PHOTO,
218
217
        PROP_NAME,
219
218
        PROP_NICKNAME,
220
219
        PROP_BIRTHDAY,
229
228
        PROP_PRIORITY,
230
229
        PROP_SENSITIVITY,
231
230
        PROP_SHORT_NAME,
232
 
        PROP_SUBJECT
 
231
        PROP_SUBJECT,
 
232
        PROP_PHOTO_ETAG
233
233
};
234
234
 
235
235
G_DEFINE_TYPE (GDataContactsContact, gdata_contacts_contact, GDATA_TYPE_ENTRY)
286
286
                                                               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
287
287
 
288
288
        /**
289
 
         * GDataContactsContact:has-photo:
290
 
         *
291
 
         * Whether the contact has a photo.
292
 
         *
293
 
         * Since: 0.4.0
 
289
         * GDataContactsContact:photo-etag:
 
290
         *
 
291
         * The ETag of the contact's photo, if the contact has a photo; %NULL otherwise.
 
292
         *
 
293
         * Since: 0.9.0
294
294
         **/
295
 
        g_object_class_install_property (gobject_class, PROP_HAS_PHOTO,
296
 
                                         g_param_spec_boolean ("has-photo",
297
 
                                                               "Has photo?", "Whether the contact has a photo.",
298
 
                                                               FALSE,
 
295
        g_object_class_install_property (gobject_class, PROP_PHOTO_ETAG,
 
296
                                         g_param_spec_string ("photo-etag",
 
297
                                                               "Photo ETag", "The ETag of the contact's photo.",
 
298
                                                               NULL,
299
299
                                                               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
300
300
 
301
301
        /**
649
649
                case PROP_DELETED:
650
650
                        g_value_set_boolean (value, priv->deleted);
651
651
                        break;
652
 
                case PROP_HAS_PHOTO:
653
 
                        g_value_set_boolean (value, (priv->photo_etag != NULL) ? TRUE : FALSE);
 
652
                case PROP_PHOTO_ETAG:
 
653
                        g_value_set_string (value, priv->photo_etag);
654
654
                        break;
655
655
                case PROP_NAME:
656
656
                        g_value_set_object (value, priv->name);
896
896
                        /* gContact:userDefinedField */
897
897
                        xmlChar *name, *value;
898
898
 
 
899
                        /* Note that while we require the property to be present, we don't require it to be non-empty. See bgo#648058 */
899
900
                        name = xmlGetProp (node, (xmlChar*) "key");
900
 
                        if (name == NULL || *name == '\0') {
 
901
                        if (name == NULL) {
901
902
                                xmlFree (name);
902
903
                                return gdata_parser_error_required_property_missing (node, "key", error);
903
904
                        }
1173
1174
get_entry_uri (const gchar *id)
1174
1175
{
1175
1176
        const gchar *base_pos;
1176
 
        gchar *uri = g_strdup (id);
 
1177
        gchar *uri;
 
1178
 
 
1179
        /* Ensure it uses the HTTPS protocol */
 
1180
        if (g_str_has_prefix (id, "http://") == TRUE) {
 
1181
                guint id_length = strlen (id);
 
1182
 
 
1183
                uri = g_malloc (id_length + 2);
 
1184
                strcpy (uri, "https://");
 
1185
                strcpy (uri + strlen ("https://"), id + strlen ("http://"));
 
1186
        } else {
 
1187
                uri = g_strdup (id);
 
1188
        }
1177
1189
 
1178
1190
        /* The service API sometimes stubbornly insists on using the "base" view instead of the "full" view, which we have
1179
1191
         * to fix, or our extended attributes are never visible */
2843
2855
 * Gets the value of a user-defined field of the contact. User-defined fields are settable by the user through the Google Contacts web interface,
2844
2856
 * in contrast to extended properties, which are visible and settable only through the GData interface.
2845
2857
 *
 
2858
 * The @name of the field may not be %NULL, but may be an empty string.
 
2859
 *
2846
2860
 * Return value: the field's value, or %NULL
2847
2861
 *
2848
2862
 * Since: 0.7.0
2851
2865
gdata_contacts_contact_get_user_defined_field (GDataContactsContact *self, const gchar *name)
2852
2866
{
2853
2867
        g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (self), NULL);
2854
 
        g_return_val_if_fail (name != NULL && *name != '\0', NULL);
 
2868
        g_return_val_if_fail (name != NULL, NULL);
2855
2869
        return g_hash_table_lookup (self->priv->user_defined_fields, name);
2856
2870
}
2857
2871
 
2881
2895
 * Sets the value of a contact's user-defined field. User-defined field names are unique (but of the client's choosing),
2882
2896
 * and reusing the same field name will result in the old value of that field being overwritten.
2883
2897
 *
 
2898
 * The @name of the field may not be %NULL, but may be an empty string.
 
2899
 *
2884
2900
 * To unset a field, set @value to %NULL.
2885
2901
 *
2886
2902
 * Since: 0.7.0
2889
2905
gdata_contacts_contact_set_user_defined_field (GDataContactsContact *self, const gchar *name, const gchar *value)
2890
2906
{
2891
2907
        g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
2892
 
        g_return_if_fail (name != NULL && *name != '\0');
 
2908
        g_return_if_fail (name != NULL);
2893
2909
 
2894
2910
        if (value == NULL) {
2895
2911
                /* Removing a field */
3014
3030
}
3015
3031
 
3016
3032
/**
3017
 
 * gdata_contacts_contact_has_photo:
 
3033
 * gdata_contacts_contact_get_photo_etag:
3018
3034
 * @self: a #GDataContactsContact
3019
3035
 *
3020
 
 * Returns whether the contact has a photo attached to their contact entry. If the contact
3021
 
 * does have a photo, it can be returned using gdata_contacts_contact_get_photo().
3022
 
 *
3023
 
 * Return value: %TRUE if the contact has a photo, %FALSE otherwise
3024
 
 *
3025
 
 * Since: 0.4.0
 
3036
 * Returns the ETag for the contact's attached photo, if it exists. If it does exist, the contact's photo can be retrieved using
 
3037
 * gdata_contacts_contact_get_photo(). If it doesn't exist, %NULL will be returned, and the contact doesn't have a photo (so calling
 
3038
 * gdata_contacts_contact_get_photo() will also return %NULL)
 
3039
 *
 
3040
 * Return value: the contact's photo's ETag if it exists, %NULL otherwise
 
3041
 *
 
3042
 * Since: 0.9.0
3026
3043
 **/
3027
 
gboolean
3028
 
gdata_contacts_contact_has_photo (GDataContactsContact *self)
 
3044
const gchar *
 
3045
gdata_contacts_contact_get_photo_etag (GDataContactsContact *self)
3029
3046
{
3030
 
        g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (self), FALSE);
3031
 
        return (self->priv->photo_etag != NULL) ? TRUE : FALSE;
 
3047
        g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (self), NULL);
 
3048
        return self->priv->photo_etag;
3032
3049
}
3033
3050
 
3034
3051
/**
3037
3054
 * @service: a #GDataContactsService
3038
3055
 * @length: (out caller-allocates): return location for the image length, in bytes
3039
3056
 * @content_type: (out callee-allocates) (transfer full) (allow-none): return location for the image's content type, or %NULL; free with g_free()
3040
 
 * @cancellable: optional #GCancellable object, or %NULL
 
3057
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
3041
3058
 * @error: a #GError, or %NULL
3042
3059
 *
3043
3060
 * Downloads and returns the contact's photo, if they have one. If the contact doesn't
3044
 
 * have a photo (i.e. gdata_contacts_contact_has_photo() returns %FALSE), %NULL is returned, but
 
3061
 * have a photo (i.e. gdata_contacts_contact_get_photo_etag() returns %NULL), %NULL is returned, but
3045
3062
 * no error is set in @error.
3046
3063
 *
3047
3064
 * If @cancellable is not %NULL, then the operation can be cancelled by triggering the @cancellable object from another thread.
3069
3086
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
3070
3087
 
3071
3088
        /* Return if there is no photo */
3072
 
        if (gdata_contacts_contact_has_photo (self) == FALSE)
 
3089
        if (gdata_contacts_contact_get_photo_etag (self) == NULL)
3073
3090
                return NULL;
3074
3091
 
3075
3092
        /* Get the photo URI */
3076
3093
        /* TODO: ETag support */
3077
3094
        _link = gdata_entry_look_up_link (GDATA_ENTRY (self), "http://schemas.google.com/contacts/2008/rel#photo");
3078
3095
        g_assert (_link != NULL);
3079
 
        message = _gdata_service_build_message (GDATA_SERVICE (service), SOUP_METHOD_GET, gdata_link_get_uri (_link), NULL, FALSE);
 
3096
        message = _gdata_service_build_message (GDATA_SERVICE (service), gdata_contacts_service_get_primary_authorization_domain (),
 
3097
                                                SOUP_METHOD_GET, gdata_link_get_uri (_link), NULL, FALSE);
3080
3098
 
3081
3099
        /* Send the message */
3082
3100
        status = _gdata_service_send_message (GDATA_SERVICE (service), message, cancellable, error);
3155
3173
 * gdata_contacts_contact_get_photo_async:
3156
3174
 * @self: a #GDataContactsContact
3157
3175
 * @service: a #GDataContactsService
3158
 
 * @cancellable: optional #GCancellable object, or %NULL
 
3176
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
3159
3177
 * @callback: a #GAsyncReadyCallback to call when the photo has been retrieved, or %NULL
3160
3178
 * @user_data: (closure): data to pass to the @callback function
3161
3179
 *
3200
3218
 * @error: a #GError, or %NULL
3201
3219
 *
3202
3220
 * Finishes an asynchronous contact photo retrieval operation started with gdata_contacts_contact_get_photo_async(). If the contact doesn't have a
3203
 
 * photo (i.e. gdata_contacts_contact_has_photo() returns %FALSE), %NULL is returned, but no error is set in @error.
 
3221
 * photo (i.e. gdata_contacts_contact_get_photo_etag() returns %NULL), %NULL is returned, but no error is set in @error.
3204
3222
 *
3205
 
 * If there is an error getting the photo, a %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error will be returned.
 
3223
 * If there is an error getting the photo, a %GDATA_SERVICE_ERROR_PROTOCOL_ERROR error will be returned. @length will be set to
 
3224
 * <code class="literal">0</code> and @content_type will be set to %NULL.
3206
3225
 *
3207
3226
 * Return value: the image data, or %NULL; free with g_free()
3208
3227
 *
3222
3241
 
3223
3242
        g_warn_if_fail (g_simple_async_result_get_source_tag (result) == gdata_contacts_contact_get_photo_async);
3224
3243
 
3225
 
        if (g_simple_async_result_propagate_error (result, error) == TRUE)
 
3244
        if (g_simple_async_result_propagate_error (result, error) == TRUE) {
 
3245
                /* Error */
 
3246
                *length = 0;
 
3247
 
 
3248
                if (content_type != NULL) {
 
3249
                        *content_type = NULL;
 
3250
                }
 
3251
 
3226
3252
                return NULL;
 
3253
        }
3227
3254
 
3228
3255
        /* Return the photo (steal the data from the PhotoData struct so we don't have to copy it again) */
3229
3256
        data = g_simple_async_result_get_op_res_gpointer (result);
3245
3272
 * @data: (allow-none): the image data, or %NULL
3246
3273
 * @length: the image length, in bytes
3247
3274
 * @content_type: (allow-none): the content type of the image, or %NULL
3248
 
 * @cancellable: optional #GCancellable object, or %NULL
 
3275
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
3249
3276
 * @error: a #GError, or %NULL
3250
3277
 *
3251
3278
 * Sets the contact's photo to @data or, if @data is %NULL, deletes the contact's photo. @content_type must be specified if @data is non-%NULL.
3266
3293
        GDataLink *_link;
3267
3294
        SoupMessage *message;
3268
3295
        guint status;
3269
 
        gboolean adding_photo = FALSE, deleting_photo = FALSE;
 
3296
        gboolean deleting_photo = FALSE;
 
3297
        const gchar *etag;
3270
3298
 
3271
3299
        g_return_val_if_fail (GDATA_IS_CONTACTS_CONTACT (self), FALSE);
3272
3300
        g_return_val_if_fail (GDATA_IS_CONTACTS_SERVICE (service), FALSE);
3274
3302
        g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
3275
3303
        g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
3276
3304
 
3277
 
        if (self->priv->photo_etag == NULL && data != NULL)
3278
 
                adding_photo = TRUE;
3279
 
        else if (self->priv->photo_etag != NULL && data == NULL)
 
3305
        if (self->priv->photo_etag != NULL && data == NULL)
3280
3306
                deleting_photo = TRUE;
3281
3307
 
3282
3308
        /* Get the photo URI */
3283
3309
        _link = gdata_entry_look_up_link (GDATA_ENTRY (self), "http://schemas.google.com/contacts/2008/rel#photo");
3284
3310
        g_assert (_link != NULL);
3285
 
        message = _gdata_service_build_message (GDATA_SERVICE (service), (deleting_photo == TRUE) ? SOUP_METHOD_DELETE : SOUP_METHOD_PUT,
3286
 
                                                gdata_link_get_uri (_link), self->priv->photo_etag, TRUE);
 
3311
 
 
3312
        /* We always have to set an If-Match header. */
 
3313
        etag = self->priv->photo_etag;
 
3314
        if (etag == NULL || *etag == '\0') {
 
3315
                etag = "*";
 
3316
        }
 
3317
 
 
3318
        message = _gdata_service_build_message (GDATA_SERVICE (service), gdata_contacts_service_get_primary_authorization_domain (),
 
3319
                                                (deleting_photo == TRUE) ? SOUP_METHOD_DELETE : SOUP_METHOD_PUT,
 
3320
                                                gdata_link_get_uri (_link), etag, TRUE);
3287
3321
 
3288
3322
        /* Append the data */
3289
3323
        if (deleting_photo == FALSE)
3309
3343
        /* Update the stored photo ETag */
3310
3344
        g_free (self->priv->photo_etag);
3311
3345
        self->priv->photo_etag = g_strdup (soup_message_headers_get_one (message->response_headers, "ETag"));
 
3346
        g_object_notify (G_OBJECT (self), "photo-etag");
 
3347
 
3312
3348
        g_object_unref (message);
3313
3349
 
3314
 
        if (adding_photo == TRUE || deleting_photo == TRUE)
3315
 
                g_object_notify (G_OBJECT (self), "has-photo");
3316
 
 
3317
3350
        return TRUE;
3318
3351
}
3319
3352
 
3346
3379
 * @data: (allow-none): the image data, or %NULL
3347
3380
 * @length: the image length, in bytes
3348
3381
 * @content_type: (allow-none): the content type of the image, or %NULL
3349
 
 * @cancellable: optional #GCancellable object, or %NULL
 
3382
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
3350
3383
 * @callback: a #GAsyncReadyCallback to call when the photo has been set, or %NULL
3351
3384
 * @user_data: (closure): data to pass to the @callback function
3352
3385
 *