Last active
September 28, 2019 18:50
-
-
Save vanessaaleung/f5fd36f653da594fbddb3ed7a1ef9a22 to your computer and use it in GitHub Desktop.
main
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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