Exemple #1
0
CURLcode
memfile_from_url(const memfile_from_url_info info) {
  CURL* curl = curl_easy_init();
  if (!curl) return CURLE_FAILED_INIT;

  MEMFILE* body = memfopen();
  MEMFILE* header = memfopen();

  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(curl, CURLOPT_URL, info.url);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, info.body_writer);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, body);
  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, info.header_writer);
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, header);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
  const CURLcode res = curl_easy_perform(curl);
  curl_easy_cleanup(curl);

  if (res == CURLE_OK) {
    if (info.body)   *info.body   = memfrelease(&body);
    if (info.header) *info.header = memfrelease(&header);
  }
  memfclose(body);
  memfclose(header);

  return res;
}
Exemple #2
0
static gboolean
fetch_tweets(gpointer data) {
  if (!enable) return FALSE;

  CURL* curl = NULL;
  CURLcode res = CURLE_OK;
  long http_status = 0;

  MEMFILE* mbody = NULL;
  char* body = NULL;

  xmlDocPtr doc = NULL;
  xmlNodeSetPtr nodes = NULL;
  xmlXPathContextPtr ctx = NULL;
  xmlXPathObjectPtr path = NULL;

  mbody = memfopen();
  curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(curl, CURLOPT_URL, "https://api.twitter.com/1/statuses/public_timeline.xml");
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, mbody);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
  res = curl_easy_perform(curl);
  if (res == CURLE_OK)
    curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &http_status);
  curl_easy_cleanup(curl);

  body = memfstrdup(mbody);
  memfclose(mbody);

  if (res != CURLE_OK) {
    goto leave;
  }
  if (http_status == 304) {
    goto leave;
  }
  if (http_status != 200) {
    goto leave;
  }

  doc = body ? xmlParseDoc((xmlChar*) body) : NULL;
  if (!doc) goto leave;
  ctx = xmlXPathNewContext(doc);
  if (!ctx) goto leave;
  path = xmlXPathEvalExpression((xmlChar*)"/statuses/status", ctx);
  if (!path || xmlXPathNodeSetIsEmpty(path->nodesetval)) goto leave;
  nodes = path->nodesetval;
  int n, length = xmlXPathNodeSetGetLength(nodes);
  gchar* first_id = NULL;
  for(n = 0; n < length; n++) {
    char* id = NULL;
    char* user_id = NULL;
    char* icon = NULL;
    char* real = NULL;
    char* user_name = NULL;
    char* text = NULL;
    char* date = NULL;

    xmlNodePtr status = nodes->nodeTab[n];
    if (status->type != XML_ATTRIBUTE_NODE && status->type != XML_ELEMENT_NODE && status->type != XML_CDATA_SECTION_NODE) continue;
    status = status->children;
    while(status) {
      if (!strcmp("id", (char*) status->name)) id = (char*) status->children->content;
      if (!strcmp("created_at", (char*) status->name)) date = (char*) status->children->content;
      if (!strcmp("text", (char*) status->name)) {
        if (status->children) text = (char*) status->children->content;
      }
      /* user nodes */
      if (!strcmp("user", (char*) status->name)) {
        xmlNodePtr user = status->children;
        while(user) {
          if (!strcmp("id", (char*) user->name)) user_id = XML_CONTENT(user);
          if (!strcmp("name", (char*) user->name)) real = XML_CONTENT(user);
          if (!strcmp("screen_name", (char*) user->name)) user_name = XML_CONTENT(user);
          if (!strcmp("profile_image_url", (char*) user->name)) {
            icon = XML_CONTENT(user);
            icon = (char*) g_strchomp((gchar*) icon);
            icon = (char*) g_strchug((gchar*) icon);
          }
          user = user->next;
        }
      }
      status = status->next;
    }
    if (!first_id) first_id = id;
    if (id && last_id && !strcmp(id, last_id)) break;

    if (text && user_id) {
      NOTIFICATION_INFO* ni = g_new0(NOTIFICATION_INFO, 1);
      ni->title = g_strdup(user_name);
      ni->text = g_strdup(text);
      ni->icon = g_strdup(icon);
      g_timeout_add(1000 * (n+1), delay_show, ni);
    }
  }
  if (last_id) g_free(last_id);
  if (first_id) last_id = g_strdup(first_id);

leave:
  if (body) free(body);
  if (path) xmlXPathFreeObject(path);
  if (ctx) xmlXPathFreeContext(ctx);
  if (doc) xmlFreeDoc(doc);
   
  g_timeout_add(1000 * length, fetch_tweets, NULL);
  return FALSE;
}
Exemple #3
0
int
main(int argc, char* argv[]) {
    CURL* curl = NULL;
    CURLcode res;
    int status = 0;
    char error[CURL_ERROR_SIZE];
    char fname[256];
    char line[256];
    char cookie[2048];
    char query[2048];
    char* buf = NULL;
    char* ptr = NULL;
    char* tmp = NULL;
    char* id;
    FILE* fp = NULL;
    MEMFILE* mf; // mem file
    MEMFILE* hf; // mem file for header

    // usage
    if (argc != 2) {
        fputs("usage: nicodown [video_id]\n", stderr);
        goto leave;
    }

    if (!(ptr = getenv("HOME"))) {
#ifdef _WIN32
        if (!(ptr = getenv("USERPROFILE"))) {
            fprintf(stderr, "failed to get HOME directory\n");
            goto leave;
        }
#else
        fprintf(stderr, "failed to get HOME directory\n");
        goto leave;
#endif
    }

    sprintf(fname, "%s/.nicodownrc", ptr);
    fp = fopen(fname, "r");
    if (!fp || !fgets(line, sizeof(line), fp)) {
        if (fp) fclose(fp);
        fprintf(stderr, "failed to read ~/.nicodownrc\n");
        goto leave;
    }
    fclose(fp);
    tmp = strpbrk(line, "\r\n");
    if (tmp) *tmp = 0;
    ptr = strchr(line, ':');
    if (!ptr) {
        fprintf(stderr, "failed to parse ~/.nicodownrc\n");
        goto leave;
    }
    *ptr++ = 0;

    id = argv[1];
    if (!strncmp(id, WATCH_URL_BASE, strlen(WATCH_URL_BASE))) {
        id += strlen(WATCH_URL_BASE);
    }
    sprintf(query, "mail_tel=%s&password=%s&next_url=/watch/%s", line, ptr, id);

    // default filename
    sprintf(fname, "%s.flv", id);

    curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);

    // login
    mf = memfopen();
    hf = memfopen();
    curl_easy_setopt(curl, CURLOPT_URL, "https://secure.nicovideo.jp/secure/login?site=niconico");
    curl_easy_setopt(curl, CURLOPT_POST, 1);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, query);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, hf);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, memfwrite);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fputs(error, stderr);
        memfclose(mf);
        memfclose(hf);
        goto leave;
    }

    // parse cookie
    memset(cookie, 0, sizeof(cookie));
    buf = memfstrdup(hf);
    tmp = buf;
    while (tmp = strstr(tmp, "Set-Cookie: ")) {
        ptr = tmp;
        tmp = strpbrk(ptr, "\r\n;");
        if (tmp) *tmp = 0;
        strcpy(cookie, ptr + 12);
        if (strncmp(cookie, "user_session=user", 17) == 0) {
            curl_easy_setopt(curl, CURLOPT_COOKIE, cookie);
            break;
        }
        tmp++;
    }
    free(buf);

    memfclose(mf);
    memfclose(hf);
    mf = memfopen();
    hf = memfopen();
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, hf);

    // redirect
    sprintf(query, "http://www.nicovideo.jp/watch/%s", id);
    curl_easy_setopt(curl, CURLOPT_URL, query);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fputs(error, stderr);
        memfclose(mf);
        memfclose(hf);
        goto leave;
    }

    // parse cookie
    buf = memfstrdup(hf);
    ptr = NULL;
    tmp = buf;
    while (tmp = strstr(tmp, "Set-Cookie: ")) {
        ptr = tmp + 12;
        tmp = strpbrk(ptr, "\r\n;");
        if (tmp) *tmp = 0;
        strcat(cookie, ";");
        strcat(cookie, ptr);
        tmp++;
    }
    curl_easy_setopt(curl, CURLOPT_COOKIE, cookie);
    free(buf);

    // parse response body
    buf = memfstrdup(mf);
    if (buf && strstr(buf, "id=\"login_bar\"")) {
        free(buf);
        fprintf(stderr, "failed to login\n");
        memfclose(mf);
        memfclose(hf);
        goto leave;
    }
    free(buf);
    memfclose(hf);
    memfclose(mf);

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, NULL);
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, NULL);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);

    // get video query, and get filename
    sprintf(query, "http://www.nicovideo.jp/api/getthumbinfo?v=%s", id);
    mf = memfopen();
    curl_easy_setopt(curl, CURLOPT_URL, query);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fputs(error, stderr);
        memfclose(mf);
        goto leave;
    }

#ifdef USE_LIBXML
    // parse title node
    {
        xmlDocPtr doc = NULL;
        xmlXPathContextPtr xpathctx;
        xmlXPathObjectPtr xpathobj;

        doc = xmlParseMemory(mf->data, mf->size);
        xpathctx = doc ? xmlXPathNewContext(doc) : NULL;
        xpathobj = xpathctx ? xmlXPathEvalExpression((xmlChar*) "//title", xpathctx) : NULL;
        if (xpathobj) {
            int n;
            xmlNodeSetPtr nodes = xpathobj->nodesetval;
            for(n = 0; nodes && n < xmlXPathNodeSetGetLength(nodes); n++) {
                xmlNodePtr node = nodes->nodeTab[n];
                if(node->type != XML_ATTRIBUTE_NODE && node->type != XML_ELEMENT_NODE && node->type != XML_CDATA_SECTION_NODE) continue;
                if (node->type == XML_CDATA_SECTION_NODE)
                    sprintf(fname, "%s.flv", (char*) node->content);
                else
                    if (node->children)
                        sprintf(fname, "%s.flv", (char*) node->children->content);
                break;
            }
        }
        if (xpathobj ) xmlXPathFreeObject(xpathobj);
        if (xpathctx) xmlXPathFreeContext(xpathctx);
        if (doc) xmlFreeDoc(doc);
    }
#else
    buf = memfstrdup(mf);
    ptr = buf ? strstr(buf, "<title>") : NULL;
    if (ptr) {
        ptr += 7;
        tmp = strstr(ptr, "</title>");
        if (*tmp) {
            *tmp = 0;
            sprintf(fname, "%s.flv", ptr);
        }
    }
    if (buf) free(buf);
#endif

    memfclose(mf);

#ifdef _WIN32
    {
        UINT codePage;
        size_t wcssize;
        wchar_t* wcsstr;
        size_t mbssize;
        char* mbsstr;

        codePage = CP_UTF8;
        wcssize = MultiByteToWideChar(codePage, 0, fname, -1,  NULL, 0);
        wcsstr = (wchar_t*) malloc(sizeof(wchar_t) * (wcssize + 1));
        wcssize = MultiByteToWideChar(codePage, 0, fname, -1, wcsstr, wcssize + 1);
        wcsstr[wcssize] = 0;
        codePage = GetACP();
        mbssize = WideCharToMultiByte(codePage, 0, (LPCWSTR) wcsstr,-1,NULL,0,NULL,NULL);
        mbsstr = (char*) malloc(mbssize+1);
        mbssize = WideCharToMultiByte(codePage, 0, (LPCWSTR) wcsstr, -1, mbsstr, mbssize, NULL, NULL);
        mbsstr[mbssize] = 0;
        strcpy(fname, mbsstr);
        free(mbsstr);
        free(wcsstr);
    }
#endif

    // get video query
    sprintf(query, "http://flapi.nicovideo.jp/api/getflv?v=%s", id);
    mf = memfopen();
    curl_easy_setopt(curl, CURLOPT_URL, query);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fputs(error, stderr);
        memfclose(mf);
        goto leave;
    }
    buf = memfstrdup(mf);
    ptr = strstr(buf, "url=");
    if (!ptr) {
        if (buf) free(buf);
        fprintf(stderr, "failed to get video info\n");
        memfclose(mf);
        goto leave;
    }
    tmp = strstr(ptr, "&");
    if (tmp) *tmp = 0;
    tmp = ptr;
    while(*tmp) {
        if (IS_QUOTED(tmp)) {
            unsigned int num = 0;
            sscanf(tmp+1, "%02x", &num);
            *tmp = (char)num;
            strcpy(tmp + 1, tmp + 3);
        }
        tmp++;
    }
    strcpy(query, ptr + 4);
    printf("URL: %s\n", query);
    free(buf);
    memfclose(mf);

    // sanitize filename
    ptr = fname;
    while (*ptr) {
        if (strchr("\\/|:<>\"?*", *ptr)) *ptr = '_';
        ptr++;
    }

    // download video
    fp = fopen(fname, "wb");
    if (!fp) {
        fprintf(stderr, "failed to open file: %s\n", fname);
        goto leave;
    }
    curl_easy_setopt(curl, CURLOPT_URL, query);
    curl_easy_setopt(curl, CURLOPT_POST, 0);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress);
    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void*)fname);
    curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, BUFSIZ);
    /* curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); */
    res = curl_easy_perform(curl);
    fclose(fp);
    if (res != CURLE_OK) {
        fputs(error, stderr);
        goto leave;
    }

leave:
    if (curl) curl_easy_cleanup(curl);
    printf("\n");

    return 0;
}
Exemple #4
0
static mrb_value
mrb_curl_get(mrb_state *mrb, mrb_value self)
{
  char error[CURL_ERROR_SIZE] = {0};
  CURL* curl;
  CURLcode res = CURLE_OK;
  MEMFILE* mf;
  struct RClass* _class_curl;
  int ssl_verifypeer;
  struct curl_slist* headerlist = NULL;
  mrb_value str;
  struct RClass* _class_http;
  struct RClass* _class_http_parser;
  mrb_value parser;
  mrb_value args[1];

  mrb_value url = mrb_nil_value();
  mrb_value headers = mrb_nil_value();
  mrb_value b = mrb_nil_value();
  mrb_get_args(mrb, "S|H&", &url, &headers, &b);

  if (!mrb_nil_p(headers) && mrb_type(headers) != MRB_TT_HASH) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument");
  }
  mf = memfopen();
  curl = curl_easy_init();
  _class_curl = mrb_class_get(mrb, "Curl");
  ssl_verifypeer = mrb_fixnum(mrb_const_get(mrb, mrb_obj_value(_class_curl), mrb_intern_cstr(mrb, "SSL_VERIFYPEER")));
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, ssl_verifypeer);
  curl_easy_setopt(curl, CURLOPT_URL, RSTRING_PTR(url));
  curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
  if (mrb_nil_p(b)) {
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
  } else {
    mf->mrb = mrb;
    mf->proc = b;
    mf->header = mrb_nil_value();
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite_callback);
  }
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, mf);
  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, memfwrite);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0);

  if (!mrb_nil_p(headers)) {
    mrb_value keys = mrb_hash_keys(mrb, headers);
    int i, l = RARRAY_LEN(keys);
    for (i = 0; i < l; i++) {
      mrb_value key = mrb_ary_entry(keys, i);
      mrb_value header = mrb_str_dup(mrb, key);
      mrb_str_cat2(mrb, header, ": ");
      mrb_str_concat(mrb, header, mrb_hash_get(mrb, headers, key));
      headerlist = curl_slist_append(headerlist, RSTRING_PTR(header));
    }
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
  }

  res = curl_easy_perform(curl);

  if (headerlist)
    curl_slist_free_all(headerlist);

  curl_easy_cleanup(curl);
  if (res != CURLE_OK) {
    mrb_raise(mrb, E_RUNTIME_ERROR, error);
  }
  if (!mrb_nil_p(b)) {
    return mrb_nil_value();
  }

  str = mrb_str_new(mrb, mf->data, mf->size);
  memfclose(mf);

  _class_http = mrb_class_get(mrb, "HTTP");
  _class_http_parser = mrb_class_ptr(mrb_const_get(mrb, mrb_obj_value(_class_http), mrb_intern_cstr(mrb, "Parser")));
  parser = mrb_obj_new(mrb, _class_http_parser, 0, NULL);
  args[0] = str;
  return mrb_funcall_argv(mrb, parser, mrb_intern_cstr(mrb, "parse_response"), 1, args);
}
Exemple #5
0
static gchar*
get_album_art(const char* artist, const char* album) {
  CURL* curl = NULL;
  CURLcode res = CURLE_OK;
  long http_status = 0;

  MEMFILE* mbody = NULL;
  char* body = NULL;

  xmlDocPtr doc = NULL;
  xmlNodeSetPtr nodes = NULL;
  xmlXPathContextPtr ctx = NULL;
  xmlXPathObjectPtr path = NULL;

  char* info = g_strdup_printf("%s %s", artist, album);
  char* qinfo = urlencode_alloc(info);
  g_free(info);
  gchar* url = g_strdup_printf(
    "http://api.search.yahoo.com/ImageSearchService/V1/imageSearch?"
    "appid=%s&query=%s&type=all&results=10&start=1&format=any&adult_ok=True",
    "YahooExample",
    qinfo);

  mbody = memfopen();
  curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(curl, CURLOPT_URL, url);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, mbody);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
  res = curl_easy_perform(curl);
  if (res == CURLE_OK)
    curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &http_status);
  curl_easy_cleanup(curl);

  body = memfstrdup(mbody);
  memfclose(mbody);

  if (res != CURLE_OK) {
    goto leave;
  }
  if (http_status == 304) {
    goto leave;
  }
  if (http_status != 200) {
    goto leave;
  }

  doc = body ? xmlParseDoc((xmlChar*) body) : NULL;
  xmlNodePtr node = doc->children;
  gchar* image_url = NULL;
  if (strcmp((const char*) node->name, "ResultSet")) goto leave;
  for (node = node->children; node; node = node->next) {
    if (strcmp((const char*) node->name, "Result")) continue;
    for (node = node->children; node; node = node->next) {
      if (strcmp((const char*) node->name, "Thumbnail")) continue;
      for (node = node->children; node; node = node->next) {
        if (strcmp((const char*) node->name, "Url")) continue;
        image_url = g_strdup(XML_CONTENT(node));
        break;
      }
      if (image_url) break;
    }
    if (image_url) break;
  }

leave:
  if (body) free(body);
  if (path) xmlXPathFreeObject(path);
  if (ctx) xmlXPathFreeContext(ctx);
  if (doc) xmlFreeDoc(doc);
   
  return image_url;
}
Exemple #6
0
static GdkPixbuf*
url2pixbuf(const char* url, GError** error) {
  GdkPixbuf* pixbuf = NULL;
  GdkPixbufLoader* loader = NULL;
  GError* _error = NULL;

  CURL* curl = NULL;
  MEMFILE* mbody;
  MEMFILE* mhead;
  char* head;
  char* body;
  unsigned long size;
  CURLcode res = CURLE_FAILED_INIT;

  curl = curl_easy_init();
  if (!curl) return NULL;

  mbody = memfopen();
  mhead = memfopen();

  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(curl, CURLOPT_URL, url);
  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_TIMEOUT, REQUEST_TIMEOUT);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, mbody);
  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, memfwrite);
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, mhead);
  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
  res = curl_easy_perform(curl);
  curl_easy_cleanup(curl);

  head = memfstrdup(mhead);
  memfclose(mhead);
  body = memfstrdup(mbody);
  size = mbody->size;
  memfclose(mbody);

  if (res == CURLE_OK) {
    char* ctype;
    char* csize;
    ctype = get_http_header_alloc(head, "Content-Type");
    csize = get_http_header_alloc(head, "Content-Length");

#ifdef _WIN32
    if (ctype &&
        (!strcmp(ctype, "image/jpeg") || !strcmp(ctype, "image/gif"))) {
      char temp_path[MAX_PATH];
      char temp_filename[MAX_PATH];
      FILE* fp;
      GetTempPath(sizeof(temp_path), temp_path);
      GetTempFileName(temp_path, "growl-for-linux-", 0, temp_filename);
      fp = fopen(temp_filename, "wb");
      if (fp) {
        fwrite(body, size, 1, fp);
        fclose(fp);
      }
      pixbuf = gdk_pixbuf_new_from_file(temp_filename, NULL);
      DeleteFile(temp_filename);
    } else
#endif
    {
      if (ctype)
        loader =
          (GdkPixbufLoader*) gdk_pixbuf_loader_new_with_mime_type(ctype,
              error);
      if (csize)
        size = atol(csize);
      if (!loader) loader = gdk_pixbuf_loader_new();
      if (body && gdk_pixbuf_loader_write(loader, (const guchar*) body,
            size, &_error)) {
        pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
      }
    }
    if (ctype) free(ctype);
    if (csize) free(csize);
    if (loader) gdk_pixbuf_loader_close(loader, NULL);
  } else {
    _error = g_error_new_literal(G_FILE_ERROR, res,
    curl_easy_strerror(res));
  }

  free(head);
  free(body);

  /* cleanup callback data */
  if (error && _error) *error = _error;
  return pixbuf;
}