Skip to content

Instantly share code, notes, and snippets.

@vanessaaleung
Last active September 28, 2019 18:50
Show Gist options
  • Save vanessaaleung/f5fd36f653da594fbddb3ed7a1ef9a22 to your computer and use it in GitHub Desktop.
Save vanessaaleung/f5fd36f653da594fbddb3ed7a1ef9a22 to your computer and use it in GitHub Desktop.
main
//
// main.c
// Created by Vanessa on 2019/4/8.
// Copyright © 2019 Vanessa JC Liang. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct MemoryStruct { /* struct in C is similar to class */
char *memory;
size_t size; /* size_t is an unsigned integer type of at least 16 bit */
};
/* Callback is any executable code that is passed as an argument, which is expected to execute the argument at a given time */
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
//mem->memory: gets the member called memory from struct mem points to
char *ptr = realloc(mem->memory, mem->size + realsize + 1); /* realloc(pointer to data, new size in bytes) */
if(ptr == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize); /* memcpy(destination, source, number of bytes) */
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
int main(void)
{
CURL *curl_handle, *curl_handle2;
CURLcode res;
struct MemoryStruct chunk;
/* malloc(size of memory blocks in bytes): allocates requested memory and returns pointer to it */
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
char user_code[255];
char device_code[255];
char access_token[255];
char * client_id = "YOUR_CLIENT_ID";
char * client_secret = "YOUR_CLIENT_SECRET";
/* sets up the program environment libcurl needs, like extension of library loader */
curl_global_init(CURL_GLOBAL_ALL);
/* curl_easy_init: returns a CURL easy handle as input to other functions
* must have a corresponding call to curl_easy_cleanup when operation completes */
curl_handle = curl_easy_init();
/* curl_easy_setopt(handle,option,parameter) tells libcurl how to behave
CURLOPT_URL: pass in a pointer to URL to work with */
curl_easy_setopt(curl_handle, CURLOPT_URL, "https://accounts.google.com/o/oauth2/device/code");
/* Step 1: Request device and user codes */
/* curl -d "client_id=client_id&scope=https://www.googleapis.com/auth/drive.file */
char data[255];
strcat(data, "client_id=");
strcat(data, client_id);
strcat(data, "&scope=https://www.googleapis.com/auth/drive.file");
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data); /* CURLOPT_POSTFIELDS: specify data to POST to server */
/* CURLOPT_WRITEFUNCTION: set callback for writing received data */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* CURLOPT_WRITEDATA: custom pointer passed to the write callback */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk); /* chunck: a data pointer to pass to the write callback, pointer get from above */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); /* set HTTP user-agent header */
/* curl_easy_perform: perform entire request in a blocking manner and returns when done
* invoke this function after curl_easy_init and all the curl_easy_setopt calls are made */
res = curl_easy_perform(curl_handle);
/* Step 2: Handle the authorization server response */
if(res != CURLE_OK) {
/* fprintf(pointer to FILE object, format, ...) */
fprintf(stderr, "curl_easy_perform() failed: %s\n", /* stderr: default destination for error messages */
curl_easy_strerror(res)); /*curl_easy_strerror: returns a string describing the error code */
}
else {
char *expiresin_result = strstr(chunk.memory, "\"expires_in"); /* strstr: finds the first occurrence, (scanned, searched) */
int expiresin_position = (int)(expiresin_result - chunk.memory);
char *usercode_result = strstr(chunk.memory, "\"user_code");
int usercode_position = (int)(usercode_result - chunk.memory);
int uc_length = expiresin_position - usercode_position - 19;
memcpy(user_code, &chunk.memory[usercode_position] + 14, uc_length);
user_code[uc_length] = '\0';
char *devicecode_result = strstr(chunk.memory, "device_code");
int devicecode_position = (int)(devicecode_result - chunk.memory);
int dc_length = usercode_position - devicecode_position - 20;
memcpy(device_code, &chunk.memory[devicecode_position] + 15, dc_length);
device_code[dc_length] = '\0';
}
free(chunk.memory);
/* Step 3: Display the user code & Step 5: User responds to access request */
printf("Enter below code on 'https://www.google.com/device' :\n");
printf("%s\n", user_code);
printf("Press enter when finish\n");
while( getchar() != '\n' );
/* Step 4: Poll Google's authorization server */
/* curl -d "client_id=<client_id>&client_secret=<client_secret>&code=<device_code>&grant_type=http://oauth.net/grant_type/device/1.0" \
-H "Content-Type: application/x-www-form-urlencoded"\ http://www.googleapis.com/oauth2/v4/token */
chunk.memory = malloc(1);
chunk.size = 0;
curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.googleapis.com/oauth2/v4/token");
char url[300];
strcat(url, "client_id=");
strcat(url, client_id);
strcat(url, "&client_secret=");
strcat(url, client_secret);
strcat(url, "&code=");
strcat(url, device_code);
strcat(url, "&grant_type=http://oauth.net/grant_type/device/1.0");
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, url);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
res = curl_easy_perform(curl_handle);
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
else {
/* Step 6: Handle responses to polling requests */
char *expiresin_result2 = strstr(chunk.memory, "\"expires_in");
int expiresin_position2 = (int)(expiresin_result2 - chunk.memory);
char *accesstoken_result = strstr(chunk.memory, "\"access_token");
int accesstoken_position = (int)(accesstoken_result - chunk.memory);
int at_length = expiresin_position2 - accesstoken_position - 22;
memcpy(access_token, &chunk.memory[accesstoken_position] + 17, at_length);
access_token[at_length] = '\0';
free(chunk.memory);
/* Step 7: Calling Google Drive API */
chunk.memory = malloc(1);
chunk.size = 0;
curl_handle2 = curl_easy_init();
char token[255];
strcat(token, "https://www.googleapis.com/drive/v2/files?access_token=");
strcat(token, access_token);
curl_easy_setopt(curl_handle2, CURLOPT_URL, token);
curl_easy_setopt(curl_handle2, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle2, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle2, CURLOPT_USERAGENT, "libcurl-agent/1.0");
res = curl_easy_perform(curl_handle2);
if(res != CURLE_OK){
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
printf("%s", chunk.memory);
}
/* end a libcurl easy handle */
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment