diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/auth.cpp | 2 | ||||
-rw-r--r-- | src/client.cpp | 311 | ||||
-rw-r--r-- | src/client.h | 15 | ||||
-rw-r--r-- | src/codes.cpp | 24 | ||||
-rw-r--r-- | src/codes.h | 31 | ||||
-rw-r--r-- | src/tweet.cpp | 2 | ||||
-rw-r--r-- | src/tweet.h | 4 | ||||
-rw-r--r-- | src/twitter.h | 24 | ||||
-rw-r--r-- | src/util.h | 29 |
9 files changed, 402 insertions, 40 deletions
diff --git a/src/auth.cpp b/src/auth.cpp index 325c521..f0f17e0 100644 --- a/src/auth.cpp +++ b/src/auth.cpp | |||
@@ -1,4 +1,4 @@ | |||
1 | #include "twitter.h" | 1 | #include "auth.h" |
2 | 2 | ||
3 | namespace twitter { | 3 | namespace twitter { |
4 | 4 | ||
diff --git a/src/client.cpp b/src/client.cpp index b71ff70..39d6b5d 100644 --- a/src/client.cpp +++ b/src/client.cpp | |||
@@ -1,10 +1,81 @@ | |||
1 | #include "client.h" | 1 | #include "client.h" |
2 | #include <curl_easy.h> | ||
3 | #include <curl_header.h> | ||
4 | #include <sstream> | 2 | #include <sstream> |
5 | #include <set> | 3 | #include <set> |
6 | #include <algorithm> | 4 | #include <algorithm> |
7 | #include <liboauthcpp/liboauthcpp.h> | 5 | #include <liboauthcpp/liboauthcpp.h> |
6 | #include "util.h" | ||
7 | |||
8 | // These are here for debugging curl stuff | ||
9 | |||
10 | static | ||
11 | void dump(const char *text, | ||
12 | FILE *stream, unsigned char *ptr, size_t size) | ||
13 | { | ||
14 | size_t i; | ||
15 | size_t c; | ||
16 | unsigned int width=80; | ||
17 | |||
18 | fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n", | ||
19 | text, (long)size, (long)size); | ||
20 | |||
21 | for(i=0; i<size; i+= width) { | ||
22 | fprintf(stream, "%4.4lx: ", (long)i); | ||
23 | |||
24 | /* show hex to the left | ||
25 | for(c = 0; c < width; c++) { | ||
26 | if(i+c < size) | ||
27 | fprintf(stream, "%02x ", ptr[i+c]); | ||
28 | else | ||
29 | fputs(" ", stream); | ||
30 | }*/ | ||
31 | |||
32 | /* show data on the right */ | ||
33 | for(c = 0; (c < width) && (i+c < size); c++) { | ||
34 | char x = (ptr[i+c] >= 0x20 && ptr[i+c] < 0x80) ? ptr[i+c] : '.'; | ||
35 | fputc(x, stream); | ||
36 | } | ||
37 | |||
38 | fputc('\n', stream); /* newline */ | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static | ||
43 | int my_trace(CURL *handle, curl_infotype type, | ||
44 | char *data, size_t size, | ||
45 | void *userp) | ||
46 | { | ||
47 | const char *text; | ||
48 | (void)handle; /* prevent compiler warning */ | ||
49 | |||
50 | switch (type) { | ||
51 | case CURLINFO_TEXT: | ||
52 | fprintf(stderr, "== Info: %s", data); | ||
53 | default: /* in case a new one is introduced to shock us */ | ||
54 | return 0; | ||
55 | |||
56 | case CURLINFO_HEADER_OUT: | ||
57 | text = "=> Send header"; | ||
58 | break; | ||
59 | case CURLINFO_DATA_OUT: | ||
60 | text = "=> Send data"; | ||
61 | break; | ||
62 | case CURLINFO_SSL_DATA_OUT: | ||
63 | text = "=> Send SSL data"; | ||
64 | break; | ||
65 | case CURLINFO_HEADER_IN: | ||
66 | text = "<= Recv header"; | ||
67 | break; | ||
68 | case CURLINFO_DATA_IN: | ||
69 | text = "<= Recv data"; | ||
70 | break; | ||
71 | case CURLINFO_SSL_DATA_IN: | ||
72 | text = "<= Recv SSL data"; | ||
73 | break; | ||
74 | } | ||
75 | |||
76 | dump(text, stderr, (unsigned char *)data, size); | ||
77 | return 0; | ||
78 | } | ||
8 | 79 | ||
9 | namespace twitter { | 80 | namespace twitter { |
10 | 81 | ||
@@ -22,18 +93,181 @@ namespace twitter { | |||
22 | delete _oauth_consumer; | 93 | delete _oauth_consumer; |
23 | } | 94 | } |
24 | 95 | ||
25 | response client::updateStatus(std::string msg, tweet& result) | 96 | response client::updateStatus(std::string msg, tweet& result, std::list<long> media_ids) |
26 | { | 97 | { |
27 | std::ostringstream output; | ||
28 | curl::curl_ios<std::ostringstream> ios(output); | ||
29 | curl::curl_easy conn(ios); | ||
30 | |||
31 | std::stringstream datastrstream; | 98 | std::stringstream datastrstream; |
32 | datastrstream << "status=" << OAuth::PercentEncode(msg); | 99 | datastrstream << "status=" << OAuth::PercentEncode(msg); |
33 | 100 | ||
101 | if (!media_ids.empty()) | ||
102 | { | ||
103 | datastrstream << "&media_ids="; | ||
104 | datastrstream << twitter::implode(std::begin(media_ids), std::end(media_ids), ","); | ||
105 | } | ||
106 | |||
34 | std::string datastr = datastrstream.str(); | 107 | std::string datastr = datastrstream.str(); |
35 | std::string url = "https://api.twitter.com/1.1/statuses/update.json"; | 108 | std::string url = "https://api.twitter.com/1.1/statuses/update.json"; |
36 | 109 | ||
110 | long response_code; | ||
111 | json response_data; | ||
112 | if (!performPost(url, datastr, response_code, response_data)) | ||
113 | { | ||
114 | return response::curl_error; | ||
115 | } | ||
116 | |||
117 | if (response_code == 200) | ||
118 | { | ||
119 | result = tweet(response_data); | ||
120 | return response::ok; | ||
121 | } else { | ||
122 | return codeForError(response_code, response_data); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | response client::uploadMedia(std::string media_type, const char* data, long data_length, long& media_id) | ||
127 | { | ||
128 | curl::curl_form form; | ||
129 | |||
130 | curl::curl_pair<CURLformoption, std::string> command_name(CURLFORM_COPYNAME, "command"); | ||
131 | curl::curl_pair<CURLformoption, std::string> command_cont(CURLFORM_COPYCONTENTS, "INIT"); | ||
132 | curl::curl_pair<CURLformoption, std::string> bytes_name(CURLFORM_COPYNAME, "total_bytes"); | ||
133 | curl::curl_pair<CURLformoption, std::string> bytes_cont(CURLFORM_COPYCONTENTS, std::to_string(data_length)); | ||
134 | curl::curl_pair<CURLformoption, std::string> type_name(CURLFORM_COPYNAME, "media_type"); | ||
135 | curl::curl_pair<CURLformoption, std::string> type_cont(CURLFORM_COPYCONTENTS, media_type); | ||
136 | form.add(command_name, command_cont); | ||
137 | form.add(bytes_name, bytes_cont); | ||
138 | form.add(type_name, type_cont); | ||
139 | |||
140 | if (media_type == "image/gif") | ||
141 | { | ||
142 | curl::curl_pair<CURLformoption, std::string> category_name(CURLFORM_COPYNAME, "media_category"); | ||
143 | curl::curl_pair<CURLformoption, std::string> category_cont(CURLFORM_COPYCONTENTS, "tweet_gif"); | ||
144 | form.add(category_name, category_cont); | ||
145 | } | ||
146 | |||
147 | long response_code; | ||
148 | json response_data; | ||
149 | if (!performMultiPost("https://upload.twitter.com/1.1/media/upload.json", form.get(), response_code, response_data)) | ||
150 | { | ||
151 | return response::curl_error; | ||
152 | } | ||
153 | |||
154 | if (response_code / 100 != 2) | ||
155 | { | ||
156 | return codeForError(response_code, response_data); | ||
157 | } | ||
158 | |||
159 | media_id = response_data["media_id"].get<long>(); | ||
160 | |||
161 | curl_httppost* append_form_post = nullptr; | ||
162 | curl_httppost* append_form_last = nullptr; | ||
163 | curl_formadd(&append_form_post, &append_form_last, CURLFORM_COPYNAME, "command", CURLFORM_COPYCONTENTS, "APPEND", CURLFORM_END); | ||
164 | curl_formadd(&append_form_post, &append_form_last, CURLFORM_COPYNAME, "media_id", CURLFORM_COPYCONTENTS, std::to_string(media_id).c_str(), CURLFORM_END); | ||
165 | curl_formadd(&append_form_post, &append_form_last, CURLFORM_COPYNAME, "media", CURLFORM_BUFFER, "media", CURLFORM_BUFFERPTR, data, CURLFORM_BUFFERLENGTH, data_length, CURLFORM_CONTENTTYPE, "application/octet-stream", CURLFORM_END); | ||
166 | curl_formadd(&append_form_post, &append_form_last, CURLFORM_COPYNAME, "segment_index", CURLFORM_COPYCONTENTS, std::to_string(0).c_str(), CURLFORM_END); | ||
167 | if (!performMultiPost("https://upload.twitter.com/1.1/media/upload.json", append_form_post, response_code, response_data)) | ||
168 | { | ||
169 | return response::curl_error; | ||
170 | } | ||
171 | |||
172 | curl_formfree(append_form_post); | ||
173 | |||
174 | if (response_code / 100 != 2) | ||
175 | { | ||
176 | return codeForError(response_code, response_data); | ||
177 | } | ||
178 | |||
179 | curl::curl_form finalize_form; | ||
180 | curl::curl_pair<CURLformoption, std::string> command3_name(CURLFORM_COPYNAME, "command"); | ||
181 | curl::curl_pair<CURLformoption, std::string> command3_cont(CURLFORM_COPYCONTENTS, "FINALIZE"); | ||
182 | curl::curl_pair<CURLformoption, std::string> media_id_name(CURLFORM_COPYNAME, "media_id"); | ||
183 | curl::curl_pair<CURLformoption, std::string> media_id_cont(CURLFORM_COPYCONTENTS, std::to_string(media_id)); | ||
184 | finalize_form.add(command3_name, command3_cont); | ||
185 | finalize_form.add(media_id_name, media_id_cont); | ||
186 | |||
187 | if (!performMultiPost("https://upload.twitter.com/1.1/media/upload.json", finalize_form.get(), response_code, response_data)) | ||
188 | { | ||
189 | return response::curl_error; | ||
190 | } | ||
191 | |||
192 | if (response_code / 100 != 2) | ||
193 | { | ||
194 | return codeForError(response_code, response_data); | ||
195 | } | ||
196 | |||
197 | if (response_data.find("processing_info") != response_data.end()) | ||
198 | { | ||
199 | std::stringstream datastr; | ||
200 | datastr << "https://upload.twitter.com/1.1/media/upload.json?command=STATUS&media_id=" << media_id; | ||
201 | |||
202 | for (;;) | ||
203 | { | ||
204 | if (!performGet(datastr.str(), response_code, response_data)) | ||
205 | { | ||
206 | return response::curl_error; | ||
207 | } | ||
208 | |||
209 | if (response_code / 100 != 2) | ||
210 | { | ||
211 | return codeForError(response_code, response_data); | ||
212 | } | ||
213 | |||
214 | if (response_data["processing_info"]["state"] == "succeeded") | ||
215 | { | ||
216 | break; | ||
217 | } | ||
218 | |||
219 | int ttw = response_data["processing_info"]["check_after_secs"].get<int>(); | ||
220 | sleep(ttw); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | return response::ok; | ||
225 | } | ||
226 | |||
227 | bool client::performGet(std::string url, long& response_code, json& result) | ||
228 | { | ||
229 | std::ostringstream output; | ||
230 | curl::curl_ios<std::ostringstream> ios(output); | ||
231 | curl::curl_easy conn(ios); | ||
232 | |||
233 | curl::curl_header headers; | ||
234 | std::string oauth_header = _oauth_client->getFormattedHttpHeader(OAuth::Http::Get, url, ""); | ||
235 | if (!oauth_header.empty()) | ||
236 | { | ||
237 | headers.add(oauth_header); | ||
238 | } | ||
239 | |||
240 | try { | ||
241 | //conn.add<CURLOPT_VERBOSE>(1); | ||
242 | //conn.add<CURLOPT_DEBUGFUNCTION>(my_trace); | ||
243 | conn.add<CURLOPT_URL>(url.c_str()); | ||
244 | conn.add<CURLOPT_HTTPHEADER>(headers.get()); | ||
245 | |||
246 | conn.perform(); | ||
247 | } catch (curl::curl_easy_exception error) | ||
248 | { | ||
249 | error.print_traceback(); | ||
250 | |||
251 | return false; | ||
252 | } | ||
253 | |||
254 | response_code = conn.get_info<CURLINFO_RESPONSE_CODE>().get(); | ||
255 | if (output.str().empty()) | ||
256 | { | ||
257 | result = json(); | ||
258 | } else { | ||
259 | result = json::parse(output.str()); | ||
260 | } | ||
261 | |||
262 | return true; | ||
263 | } | ||
264 | |||
265 | bool client::performPost(std::string url, std::string datastr, long& response_code, json& result) | ||
266 | { | ||
267 | std::ostringstream output; | ||
268 | curl::curl_ios<std::ostringstream> ios(output); | ||
269 | curl::curl_easy conn(ios); | ||
270 | |||
37 | curl::curl_header headers; | 271 | curl::curl_header headers; |
38 | std::string oauth_header = _oauth_client->getFormattedHttpHeader(OAuth::Http::Post, url, datastr); | 272 | std::string oauth_header = _oauth_client->getFormattedHttpHeader(OAuth::Http::Post, url, datastr); |
39 | if (!oauth_header.empty()) | 273 | if (!oauth_header.empty()) |
@@ -42,9 +276,10 @@ namespace twitter { | |||
42 | } | 276 | } |
43 | 277 | ||
44 | try { | 278 | try { |
279 | //conn.add<CURLOPT_VERBOSE>(1); | ||
280 | //conn.add<CURLOPT_DEBUGFUNCTION>(my_trace); | ||
45 | conn.add<CURLOPT_URL>(url.c_str()); | 281 | conn.add<CURLOPT_URL>(url.c_str()); |
46 | conn.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str()); | 282 | conn.add<CURLOPT_COPYPOSTFIELDS>(datastr.c_str()); |
47 | conn.add<CURLOPT_POST>(1); | ||
48 | conn.add<CURLOPT_HTTPHEADER>(headers.get()); | 283 | conn.add<CURLOPT_HTTPHEADER>(headers.get()); |
49 | 284 | ||
50 | conn.perform(); | 285 | conn.perform(); |
@@ -52,17 +287,62 @@ namespace twitter { | |||
52 | { | 287 | { |
53 | error.print_traceback(); | 288 | error.print_traceback(); |
54 | 289 | ||
55 | return response::curl_error; | 290 | return false; |
56 | } | 291 | } |
57 | 292 | ||
58 | long response_code = conn.get_info<CURLINFO_RESPONSE_CODE>().get(); | 293 | response_code = conn.get_info<CURLINFO_RESPONSE_CODE>().get(); |
59 | json response_data = json::parse(output.str()); | 294 | if (output.str().empty()) |
60 | if (response_code == 200) | ||
61 | { | 295 | { |
62 | result = tweet(response_data); | 296 | result = json(); |
63 | return response::ok; | 297 | } else { |
298 | result = json::parse(output.str()); | ||
64 | } | 299 | } |
65 | 300 | ||
301 | return true; | ||
302 | } | ||
303 | |||
304 | bool client::performMultiPost(std::string url, const curl_httppost* fields, long& response_code, json& result) | ||
305 | { | ||
306 | std::ostringstream output; | ||
307 | curl::curl_ios<std::ostringstream> ios(output); | ||
308 | curl::curl_easy conn(ios); | ||
309 | |||
310 | curl::curl_header headers; | ||
311 | std::string oauth_header = _oauth_client->getFormattedHttpHeader(OAuth::Http::Post, url, ""); | ||
312 | if (!oauth_header.empty()) | ||
313 | { | ||
314 | headers.add(oauth_header); | ||
315 | } | ||
316 | |||
317 | try { | ||
318 | //conn.add<CURLOPT_VERBOSE>(1); | ||
319 | //conn.add<CURLOPT_DEBUGFUNCTION>(my_trace); | ||
320 | conn.add<CURLOPT_HTTPHEADER>(headers.get()); | ||
321 | conn.add<CURLOPT_URL>(url.c_str()); | ||
322 | conn.add<CURLOPT_HTTPPOST>(fields); | ||
323 | |||
324 | conn.perform(); | ||
325 | } catch (curl::curl_easy_exception error) | ||
326 | { | ||
327 | error.print_traceback(); | ||
328 | |||
329 | return false; | ||
330 | } | ||
331 | |||
332 | response_code = conn.get_info<CURLINFO_RESPONSE_CODE>().get(); | ||
333 | |||
334 | if (output.str().empty()) | ||
335 | { | ||
336 | result = json(); | ||
337 | } else { | ||
338 | result = json::parse(output.str()); | ||
339 | } | ||
340 | |||
341 | return true; | ||
342 | } | ||
343 | |||
344 | response client::codeForError(int response_code, json response_data) const | ||
345 | { | ||
66 | std::set<int> error_codes; | 346 | std::set<int> error_codes; |
67 | if (response_data.find("errors") != response_data.end()) | 347 | if (response_data.find("errors") != response_data.end()) |
68 | { | 348 | { |
@@ -101,6 +381,9 @@ namespace twitter { | |||
101 | } else if (error_codes.count(261) == 1) | 381 | } else if (error_codes.count(261) == 1) |
102 | { | 382 | { |
103 | return response::write_restricted; | 383 | return response::write_restricted; |
384 | } else if (error_codes.count(44) == 1) | ||
385 | { | ||
386 | return response::invalid_media; | ||
104 | } else if (response_code == 429) | 387 | } else if (response_code == 429) |
105 | { | 388 | { |
106 | return response::limited; | 389 | return response::limited; |
diff --git a/src/client.h b/src/client.h index 1ab5c70..3a133e4 100644 --- a/src/client.h +++ b/src/client.h | |||
@@ -1,7 +1,12 @@ | |||
1 | #ifndef TWITTER_H_ABFF6A12 | 1 | #ifndef TWITTER_H_ABFF6A12 |
2 | #define TWITTER_H_ABFF6A12 | 2 | #define TWITTER_H_ABFF6A12 |
3 | 3 | ||
4 | #include "twitter.h" | 4 | #include "codes.h" |
5 | #include "tweet.h" | ||
6 | #include "auth.h" | ||
7 | #include <list> | ||
8 | #include <curl_easy.h> | ||
9 | #include <curl_header.h> | ||
5 | 10 | ||
6 | namespace OAuth { | 11 | namespace OAuth { |
7 | class Consumer; | 12 | class Consumer; |
@@ -16,12 +21,18 @@ namespace twitter { | |||
16 | client(const auth& _auth); | 21 | client(const auth& _auth); |
17 | ~client(); | 22 | ~client(); |
18 | 23 | ||
19 | response updateStatus(std::string msg, tweet& result); | 24 | response updateStatus(std::string msg, tweet& result, std::list<long> media_ids = {}); |
25 | response uploadMedia(std::string media_type, const char* data, long data_length, long& media_id); | ||
20 | 26 | ||
21 | private: | 27 | private: |
22 | OAuth::Consumer* _oauth_consumer; | 28 | OAuth::Consumer* _oauth_consumer; |
23 | OAuth::Token* _oauth_token; | 29 | OAuth::Token* _oauth_token; |
24 | OAuth::Client* _oauth_client; | 30 | OAuth::Client* _oauth_client; |
31 | |||
32 | bool performGet(std::string url, long& response_code, json& result); | ||
33 | bool performPost(std::string url, std::string dataStr, long& response_code, json& result); | ||
34 | bool performMultiPost(std::string url, const curl_httppost* fields, long& response_code, json& result); | ||
35 | response codeForError(int httpcode, json errors) const; | ||
25 | }; | 36 | }; |
26 | 37 | ||
27 | }; | 38 | }; |
diff --git a/src/codes.cpp b/src/codes.cpp new file mode 100644 index 0000000..9639d5d --- /dev/null +++ b/src/codes.cpp | |||
@@ -0,0 +1,24 @@ | |||
1 | #include "codes.h" | ||
2 | |||
3 | std::ostream& operator<<(std::ostream& os, twitter::response r) | ||
4 | { | ||
5 | switch (r) | ||
6 | { | ||
7 | case twitter::response::ok: return os << "OK"; | ||
8 | case twitter::response::curl_error: return os << "Curl Error"; | ||
9 | case twitter::response::bad_auth: return os << "Bad Auth"; | ||
10 | case twitter::response::limited: return os << "Rate Limit Exceeded"; | ||
11 | case twitter::response::server_error: return os << "Twitter Server Error"; | ||
12 | case twitter::response::server_unavailable: return os << "Twitter Is Down"; | ||
13 | case twitter::response::server_overloaded: return os << "Twitter Is Over Capacity"; | ||
14 | case twitter::response::server_timeout: return os << "Twitter Connection Timed Out"; | ||
15 | case twitter::response::suspended: return os << "Authenticated User Is Suspended"; | ||
16 | case twitter::response::bad_token: return os << "Invalid Or Expired Access Token"; | ||
17 | case twitter::response::duplicate_status: return os << "Duplicate Status"; | ||
18 | case twitter::response::suspected_spam: return os << "Request Looks Automated"; | ||
19 | case twitter::response::write_restricted: return os << "Cannot Perform Write"; | ||
20 | case twitter::response::bad_length: return os << "Message Body Too Long"; | ||
21 | case twitter::response::unknown_error: return os << "Unknown Error"; | ||
22 | case twitter::response::invalid_media: return os << "Invalid Media"; | ||
23 | } | ||
24 | } | ||
diff --git a/src/codes.h b/src/codes.h new file mode 100644 index 0000000..334f0ce --- /dev/null +++ b/src/codes.h | |||
@@ -0,0 +1,31 @@ | |||
1 | #ifndef CODES_H_05838D39 | ||
2 | #define CODES_H_05838D39 | ||
3 | |||
4 | #include <ostream> | ||
5 | |||
6 | namespace twitter { | ||
7 | |||
8 | enum class response { | ||
9 | ok, | ||
10 | curl_error, | ||
11 | bad_auth, | ||
12 | limited, | ||
13 | server_error, | ||
14 | server_unavailable, | ||
15 | server_overloaded, | ||
16 | server_timeout, | ||
17 | suspended, | ||
18 | bad_token, | ||
19 | duplicate_status, | ||
20 | suspected_spam, | ||
21 | write_restricted, | ||
22 | bad_length, | ||
23 | unknown_error, | ||
24 | invalid_media | ||
25 | }; | ||
26 | |||
27 | }; | ||
28 | |||
29 | std::ostream& operator<<(std::ostream& os, twitter::response r); | ||
30 | |||
31 | #endif /* end of include guard: CODES_H_05838D39 */ | ||
diff --git a/src/tweet.cpp b/src/tweet.cpp index 165187e..3ba3aa3 100644 --- a/src/tweet.cpp +++ b/src/tweet.cpp | |||
@@ -1,4 +1,4 @@ | |||
1 | #include "twitter.h" | 1 | #include "tweet.h" |
2 | 2 | ||
3 | namespace twitter { | 3 | namespace twitter { |
4 | 4 | ||
diff --git a/src/tweet.h b/src/tweet.h index 1d83aae..e099579 100644 --- a/src/tweet.h +++ b/src/tweet.h | |||
@@ -1,6 +1,10 @@ | |||
1 | #ifndef TWEET_H_CE980721 | 1 | #ifndef TWEET_H_CE980721 |
2 | #define TWEET_H_CE980721 | 2 | #define TWEET_H_CE980721 |
3 | 3 | ||
4 | #include <json.hpp> | ||
5 | |||
6 | using nlohmann::json; | ||
7 | |||
4 | namespace twitter { | 8 | namespace twitter { |
5 | 9 | ||
6 | class tweet { | 10 | class tweet { |
diff --git a/src/twitter.h b/src/twitter.h index 39618c9..f9534c6 100644 --- a/src/twitter.h +++ b/src/twitter.h | |||
@@ -3,32 +3,12 @@ | |||
3 | 3 | ||
4 | namespace twitter { | 4 | namespace twitter { |
5 | 5 | ||
6 | enum class response { | ||
7 | ok, | ||
8 | curl_error, | ||
9 | bad_auth, | ||
10 | limited, | ||
11 | server_error, | ||
12 | server_unavailable, | ||
13 | server_overloaded, | ||
14 | server_timeout, | ||
15 | suspended, | ||
16 | bad_token, | ||
17 | duplicate_status, | ||
18 | suspected_spam, | ||
19 | write_restricted, | ||
20 | bad_length, | ||
21 | unknown_error | ||
22 | }; | ||
23 | |||
24 | class tweet; | 6 | class tweet; |
25 | 7 | ||
26 | }; | 8 | }; |
27 | 9 | ||
28 | #include <json.hpp> | 10 | #include "codes.h" |
29 | 11 | #include "util.h" | |
30 | using nlohmann::json; | ||
31 | |||
32 | #include "auth.h" | 12 | #include "auth.h" |
33 | #include "client.h" | 13 | #include "client.h" |
34 | #include "tweet.h" | 14 | #include "tweet.h" |
diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..e1c9370 --- /dev/null +++ b/src/util.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef UTIL_H_440DEAA0 | ||
2 | #define UTIL_H_440DEAA0 | ||
3 | |||
4 | #include <string> | ||
5 | #include <sstream> | ||
6 | |||
7 | namespace twitter { | ||
8 | |||
9 | template <class InputIterator> | ||
10 | std::string implode(InputIterator first, InputIterator last, std::string delimiter) | ||
11 | { | ||
12 | std::stringstream result; | ||
13 | |||
14 | for (InputIterator it = first; it != last; it++) | ||
15 | { | ||
16 | if (it != first) | ||
17 | { | ||
18 | result << delimiter; | ||
19 | } | ||
20 | |||
21 | result << *it; | ||
22 | } | ||
23 | |||
24 | return result.str(); | ||
25 | } | ||
26 | |||
27 | }; | ||
28 | |||
29 | #endif /* end of include guard: UTIL_H_440DEAA0 */ | ||