Use this library to upload images to twitpic.com. The library creates and uses its own TCPSocket. Requires EthernetNetIf and DNSResolver. (this library actually designed by a friend of mine, novachild, with no mbed license of his own.)
TwitPic.cpp
- Committer:
- treebykooba
- Date:
- 2011-02-26
- Revision:
- 0:e8e33b39c3cc
File content as of revision 0:e8e33b39c3cc:
/* TwitPic.cpp - TwitPic Image Uploader for mbed Copyright (c) novachild 2011. All right reserved. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include "TwitPic.h" #include "string.h" #define MIN(a, b) (a < b ? a : b) #define MAX(a, b) (a > b ? a : b) #define SENDING_BUFFER_SIZE 4096 //must be large enough to hold all parameters: I wouldn't go under 2 KB. #define RECEIVING_BUFFER_SIZE 1024 //for holding respones (early ones will be discared, 1KB should do) #define SENDING_CHUNK_SIZE 1024 //amount to send over the socket at once. #define TWITPIC_URL "api.twitpic.com" #define TWITPIC_UPLOAD_API_URL "/1/upload.xml" #define TWITPIC_UPLOAD_AND_POST_API_URL "/1/uploadAndPost.xml" #define BOUNDARY "----------0dcb31395642" #define HEADER "--" BOUNDARY #define FOOTER "--" BOUNDARY "--" #define DEBUG 1 #define TRACE 1 const char* m_twitpic_api_key; //twitpic API key const char* m_consumer_key; //Consumer key const char* m_consumer_secret; //Consumer secret const char* m_access_token; //Access Token const char* m_access_token_secret; //Access Token secret const char* twitterMessage; bool post = false; bool sentHeaders = false; bool sentParameters = false; bool sentImageData = false; bool sentFooter = false; bool finishedSending = false; bool positiveResponse = false; bool readyToReturn = false; bool stillPolling = false; char sendBuf[SENDING_BUFFER_SIZE]; char recvBuf[RECEIVING_BUFFER_SIZE]; int imgSize=0; int writing_position = 0; int errorCode = 0; int preCalcedContentLength=0; int totalSentData=0; FILE *imgFile; TwitPic::TwitPic(const char *twitpic_api_key, const char *consumer_key, const char *consumer_secret, const char *access_token, const char *access_token_secret) { m_twitpic_api_key = twitpic_api_key; m_consumer_key = consumer_key; m_consumer_secret = consumer_secret; m_access_token = access_token; m_access_token_secret = access_token_secret; socket.setOnEvent(this, &TwitPic::handleTCPSocketEvents); preCalcedContentLength = 7 * (sizeof(HEADER)-1) + 24* (sizeof("\r\n")-1) + 6 * (sizeof("Content-Disposition: form-data; name=\"") - 1) + sizeof("key") + sizeof("consumer_token") + sizeof("consumer_secret") + sizeof("oauth_token") + sizeof("oauth_secret") + sizeof("message") + strlen(m_twitpic_api_key) + strlen(m_consumer_key) + strlen(m_consumer_secret) + strlen(m_access_token) + strlen(m_access_token_secret) + sizeof("\r\nContent-Disposition: form-data; name=\"media\"; filename=\"image.jpg\"\r\n")-1 + sizeof("Content-Type: image/jpeg\r\n")-1 + sizeof("Content-Transfer-Encoding: binary\r\n\r\n")-1 + sizeof("\r\n")-1 + sizeof(FOOTER) - 1 + sizeof("\r\n") - 1; } int TwitPic::upload(const char *message, FILE *img, bool toPost) { if (TRACE) printf("-----------------------TRACE: upload\n"); post = toPost; imgFile = img; twitterMessage = message; DNSResolver resolver; server.setIp(resolver.resolveName("api.twitpic.com")); server.setPort(80); //Calculate image size fseek (imgFile , 0 , SEEK_END); imgSize = ftell (img); rewind (imgFile); sentHeaders = false; sentParameters = false; sentImageData = false; sentFooter = false; positiveResponse = false; finishedSending = false; readyToReturn = false; writing_position = 0; if (DEBUG) printf("Opening connection to api.twitpic.com\n"); TCPSocketErr err = socket.connect(server); if (err < 0) { if (DEBUG) printf("Error connecting socket: %i",err); return err; } if (DEBUG) printf("Beginning network polling cycle.\n"); int countAfterSent = 0; while (! readyToReturn) { if (TRACE && !stillPolling) printf("-----------------------TRACE: Net::poll()\n"); stillPolling = true; Net::poll(); if (finishedSending) countAfterSent++; if (countAfterSent > 1000000) { if (DEBUG) printf("Polled 1000000 times and got no response. Quitting.\n"); positiveResponse = false; readyToReturn = true; } } if (positiveResponse) { printf("Image uploaded.\n"); return 0; } else { printf("Image not successfully uploaded\n"); return errorCode; } } int TwitPic::uploadAndPost(const char *message, FILE *imgFile) { return upload(message, imgFile, true); } void TwitPic::handleTCPSocketEvents(TCPSocketEvent ev) { stillPolling = false; if (TRACE) printf("-----------------------TRACE: handleTCPSocketEvent\n"); switch (ev) { case TCPSOCKET_ERROR: printf("-----TCPSocket: Unknown Error\n"); goto error; case TCPSOCKET_CONABRT: printf("-----TCPSocket: Connection aborted.\n"); goto error; case TCPSOCKET_CONRST: printf("-----TCPSocket: Connection reset.\n"); goto error; case TCPSOCKET_CONTIMEOUT: printf("-----TCPSocket: Connection timed out.\n"); goto error; case TCPSOCKET_DISCONNECTED: printf("-----TCPSocket: Connection disconnected.\n"); error: readyToReturn = true; errorCode = ev; positiveResponse = false; break; case TCPSOCKET_CONNECTED: if (DEBUG) printf("-----TCPSocket: Connected.\r\n"); sendNextChunk(); break; case TCPSOCKET_READABLE: if (DEBUG) printf("-----TCPSocket: Readable.\r\n"); getResponse(); break; case TCPSOCKET_WRITEABLE: if (DEBUG) printf("-----TCPSOCKET: Writeable.\r\n"); if (writing_position < SENDING_BUFFER_SIZE) { if (!sentHeaders) { sendHeaders(); } else if (!sentParameters) { sendParameters(); } else if (!sentImageData) { sendImageData(); } else if (!sentFooter) { sendFooter(); } } if (writing_position > 0) sendNextChunk(); } } void TwitPic::sendHeaders() { char* positionPointer; char imgSizeAsString[25]; int neededSize = 0; int availableSize = 0; if (TRACE) printf("-----------------------TRACE: sendHeaders\n"); sprintf(imgSizeAsString,"%i",preCalcedContentLength + +strlen(twitterMessage) + imgSize); if (post) { neededSize = sizeof(TWITPIC_UPLOAD_AND_POST_API_URL) -1; } else { neededSize = sizeof(TWITPIC_UPLOAD_API_URL)-1; } neededSize += sizeof("POST ") -1 + sizeof(" HTTP/1.0\r\n")-1 + sizeof("Content-Type: multipart/form-data; boundary=")-1 + sizeof(BOUNDARY)-1 + sizeof("\r\nContent-Length: ") - 1 + strlen(imgSizeAsString) + sizeof("\r\nExpect: 100-continue") -1 + sizeof("\r\nHost: api.twitpic.com") - 1 + sizeof("\r\n\r\n") - 1; availableSize = SENDING_BUFFER_SIZE - writing_position; //for this guy, only add to sendBuf if you can add everything if (availableSize < neededSize) return; positionPointer = sendBuf; positionPointer += writing_position; strcpy(positionPointer, "POST "); positionPointer += 5; if (post) { strcpy(positionPointer, TWITPIC_UPLOAD_AND_POST_API_URL); positionPointer += sizeof(TWITPIC_UPLOAD_AND_POST_API_URL)-1; } else { strcpy(positionPointer, TWITPIC_UPLOAD_API_URL); positionPointer += sizeof(TWITPIC_UPLOAD_API_URL)-1; } strcpy(positionPointer, " HTTP/1.1\r\n"); positionPointer += 11; strcpy(positionPointer, "Host: api.twitpic.com\r\n"); positionPointer+= sizeof("Host: api.twitpic.com\r\n")-1; strcpy(positionPointer, "Content-Length: "); positionPointer += sizeof("Content-Length: ") - 1; strcpy(positionPointer, imgSizeAsString); positionPointer += strlen(imgSizeAsString); strcpy(positionPointer,"\r\nExpect: 100-continue"); positionPointer+=sizeof("\r\nExpect: 100-continue")-1; strcpy(positionPointer, "\r\nContent-Type: multipart/form-data; boundary="); positionPointer += sizeof("\r\nContent-Type: multipart/form-data; boundary=")-1; strcpy(positionPointer, BOUNDARY); positionPointer += sizeof(BOUNDARY)-1; strcpy(positionPointer, "\r\n\r\n"); positionPointer += 4; writing_position += neededSize; if (DEBUG) printf("Wrote headers to buffer. Size = %i\n. Image size reported: %s\n",neededSize, imgSizeAsString); sentHeaders = true; } void TwitPic::sendParameters() { char* positionPointer; int neededSize = 0; int availableSize = 0; int actualsize = 0; char headerline[] = "Content-Disposition: form-data; name=\""; if (TRACE) printf("-----------------------TRACE: sendParameters\n"); neededSize = 7 * (sizeof(HEADER)-1) + 24* (sizeof("\r\n")-1) + 6 * (sizeof(headerline) - 1) + sizeof("key") + sizeof("consumer_token") + sizeof("consumer_secret") + sizeof("oauth_token") + sizeof("oauth_secret") + sizeof("message") + strlen(m_twitpic_api_key) + strlen(m_consumer_key) + strlen(m_consumer_secret) + strlen(m_access_token) + strlen(m_access_token_secret) + strlen(twitterMessage) + sizeof("\r\nContent-Disposition: form-data; name=\"media\"; filename=\"image.jpg\"\r\n")-1 + sizeof("Content-Type: image/jpeg\r\n")-1 + sizeof("Content-Transfer-Encoding: binary\r\n\r\n")-1; availableSize = SENDING_BUFFER_SIZE - writing_position; //for this guy, only add to sendBuf if you can add everything if (availableSize < neededSize) return; positionPointer = sendBuf; positionPointer+=writing_position; //API Key strcpy(positionPointer, HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER) -1; strcpy(positionPointer, "\r\n"); positionPointer += 2; actualsize += 2; strcpy(positionPointer, headerline); positionPointer += strlen(headerline); actualsize += strlen(headerline); strcpy(positionPointer, "key\"\r\n\r\n"); positionPointer += sizeof("key\"\r\n\r\n")-1; actualsize += sizeof("key\"\r\n\r\n")-1; strcpy(positionPointer, m_twitpic_api_key); positionPointer += strlen(m_twitpic_api_key); actualsize +=strlen(m_twitpic_api_key); strcpy(positionPointer, "\r\n"); positionPointer+=2; actualsize +=2; //Consumer Key strcpy(positionPointer, HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER) -1; strcpy(positionPointer, "\r\n"); positionPointer += 2; actualsize += 2; strcpy(positionPointer, headerline); positionPointer += strlen(headerline); actualsize += strlen(headerline); strcpy(positionPointer, "consumer_token\"\r\n\r\n"); positionPointer += sizeof("consumer_token\"\r\n\r\n")-1; actualsize += sizeof("consumer_token\"\r\n\r\n")-1; strcpy(positionPointer, m_consumer_key); positionPointer += strlen(m_consumer_key); actualsize += strlen(m_consumer_key); strcpy(positionPointer, "\r\n"); positionPointer+=2; actualsize+=2; //Consumer Secret strcpy(positionPointer, HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER) -1; strcpy(positionPointer, "\r\n"); positionPointer += 2; actualsize += 2; strcpy(positionPointer, headerline); positionPointer += strlen(headerline); actualsize += strlen(headerline); strcpy(positionPointer, "consumer_secret\"\r\n\r\n"); positionPointer += sizeof("consumer_secret\"\r\n\r\n")-1; actualsize +=sizeof("consumer_secret\"\r\n\r\n")-1; strcpy(positionPointer, m_consumer_secret); positionPointer += strlen(m_consumer_secret); actualsize += strlen(m_consumer_secret); strcpy(positionPointer, "\r\n"); positionPointer+=2; actualsize +=2; //OAuth Token strcpy(positionPointer, HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER) -1; strcpy(positionPointer, "\r\n"); positionPointer += 2; actualsize += 2; strcpy(positionPointer, headerline); positionPointer += strlen(headerline); actualsize += strlen(headerline); strcpy(positionPointer, "oauth_token\"\r\n\r\n"); positionPointer += sizeof("oauth_token\"\r\n\r\n")-1; actualsize += sizeof("oauth_token\"\r\n\r\n")-1; strcpy(positionPointer, m_access_token); positionPointer += strlen(m_access_token); actualsize += strlen(m_access_token); strcpy(positionPointer, "\r\n"); positionPointer+=2; actualsize += 2; //OAuth Secret strcpy(positionPointer, HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER) -1; strcpy(positionPointer, "\r\n"); positionPointer += 2; actualsize += 2; strcpy(positionPointer, headerline); positionPointer += strlen(headerline); actualsize += strlen(headerline); strcpy(positionPointer, "oauth_secret\"\r\n\r\n"); positionPointer += sizeof("oauth_secret\"\r\n\r\n")-1; actualsize += sizeof("oauth_secret\"\r\n\r\n")-1; strcpy(positionPointer, m_access_token_secret); positionPointer += strlen(m_access_token_secret); actualsize += strlen(m_access_token_secret); strcpy(positionPointer, "\r\n"); positionPointer+=2; actualsize +=2; //Twitter Message strcpy(positionPointer, HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER) -1; strcpy(positionPointer, "\r\n"); positionPointer += 2; actualsize += 2; strcpy(positionPointer, headerline); positionPointer += strlen(headerline); actualsize += strlen(headerline); strcpy(positionPointer, "message\"\r\n\r\n"); positionPointer += sizeof("message\"\r\n\r\n")-1; actualsize += sizeof("message\"\r\n\r\n")-1; strcpy(positionPointer, twitterMessage); positionPointer += strlen(twitterMessage); actualsize += strlen(twitterMessage); strcpy(positionPointer, "\r\n"); positionPointer+=2; actualsize += 2; strcpy(positionPointer,HEADER); positionPointer += sizeof(HEADER)-1; actualsize += sizeof(HEADER)-1; strcpy(positionPointer,"\r\nContent-Disposition: form-data; name=\"media\"; filename=\"image.jpg\"\r\n"); positionPointer += sizeof("\r\nContent-Disposition: form-data; name=\"media\"; filename=\"image.jpg\"\r\n")-1; actualsize += sizeof("\r\nContent-Disposition: form-data; name=\"media\"; filename=\"image.jpg\"\r\n")-1; strcpy(positionPointer,"Content-Type: image/jpeg\r\n"); positionPointer += sizeof("Content-Type: image/jpeg\r\n")-1; actualsize += sizeof("Content-Type: image/jpeg\r\n")-1; strcpy(positionPointer,"Content-Transfer-Encoding: binary\r\n\r\n"); positionPointer += sizeof("Content-Transfer-Encoding: binary\r\n\r\n")-1; actualsize+= sizeof("Content-Transfer-Encoding: binary\r\n\r\n")-1; if (actualsize != neededSize) printf("ERROR in parameters: Calculated size: %i. Actual size: %i.\n", neededSize,actualsize); writing_position += actualsize; if (DEBUG) printf("Wrote parameters to buffer.\n"); sentParameters = true; } void TwitPic::sendImageData() { int availableSize; int amountRead=0; char* positionPointer; if (TRACE) printf("-----------------------TRACE: sendImageData\n"); if (writing_position > 0) return; //fseek(imgFile,-2000,SEEK_END); positionPointer = sendBuf; positionPointer += writing_position; availableSize = SENDING_BUFFER_SIZE - writing_position; amountRead = fread(positionPointer, 1, availableSize, imgFile); writing_position += amountRead; if (DEBUG) printf("Wrote %i bytes of image to buffer.\n",amountRead); if (feof(imgFile)) { if (DEBUG) printf("Finished writing file to buffer.\n"); sentImageData = true; } } void TwitPic::sendFooter() { int availableSize; int neededSize; char* positionPointer; if (TRACE) printf("-----------------------TRACE: sendFooter\n"); availableSize = SENDING_BUFFER_SIZE - writing_position; neededSize = sizeof("\r\n")-1 + sizeof(FOOTER) - 1 + sizeof("\r\n") - 1; if (availableSize < neededSize) return; positionPointer = sendBuf; positionPointer += writing_position; strcpy(positionPointer,"\r\n"); positionPointer+=2; strcpy(positionPointer, FOOTER); positionPointer+=sizeof(FOOTER)-1; strcpy(positionPointer,"\r\n"); positionPointer+=2; writing_position+=neededSize; if (DEBUG) printf("Wrote footer to buffer.\n"); sentFooter=true; } void TwitPic::sendNextChunk() { int amountToSend; int amountSent; char* bufPointer; if (TRACE) printf("-----------------------TRACE: sendNextChunk\n"); //TODO: try both ways of doint this: looped and not. do { if (writing_position == 0) { if (!sentHeaders) { sendHeaders(); } else if (!sentParameters) { sendParameters(); } else if (!sentImageData) { sendImageData(); } else if (!sentFooter) { sendFooter(); } } amountToSend = MIN(writing_position,SENDING_CHUNK_SIZE); if (sentFooter && amountToSend == 0) { finishedSending = true; //getResponse(); } amountSent = socket.send(sendBuf, amountToSend); totalSentData += amountSent; if (DEBUG) printf("---Total sent data: %i bytes\n",totalSentData); bufPointer = sendBuf + amountSent; memmove((void*)sendBuf, (void*)bufPointer, writing_position - amountSent); writing_position -= amountSent; } while (!finishedSending && amountSent == amountToSend); //if sent less than intended, stop sending until WRITEABLE. } void TwitPic::getResponse() { int amountReceived; char* okSpot; if (TRACE) printf("-----------------------TRACE: getResponse\n"); if (DEBUG) printf("Checking for response\n"); amountReceived = socket.recv(recvBuf, RECEIVING_BUFFER_SIZE-1); recvBuf[amountReceived]='\0'; if (amountReceived > 0 && DEBUG) printf("Received response: %s\n",recvBuf); okSpot = strstr(recvBuf,"200 OK"); if (okSpot != NULL) { positiveResponse = true; readyToReturn = true; } else if (finishedSending && amountReceived > 0) { positiveResponse = false; readyToReturn = true; } } void TwitPic::flushResponse() { //no longer needed }