/* This application is implemented in the C programming language. The application reads files of various formats from the file system and imports them to the Siets storage through HTTP POST interface using libcurl. The application receives file names as command line arguments. */ // include standard headers #include #include #include #include #include #include // libcurl #include // connection parameters const char *url = "http://127.0.0.1/cgi-bin/siets/api.cgi"; char *storage = "test"; char *user = "guest"; char *password = "guest"; // XML command format (conversion works with update command too) const char *cmd_fmt = "\n\ \n\ %s\n\ insert\n\ %d\n\ console\n\ %s\n\ %s\n\ utf-8\n\ \n\ \n\ %s\n\ %s\n\ 100\n\ \n\ \n\ %s\n\ %s\n\ \n\ \n\ \n\ \n\ \n\ \n"; typedef struct { int len, used; char *buf; } curl_reply; // may use any library routine available char *base64_encode(const char *data, int ldata) { static char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char *ret = malloc((ldata / 3 + 1) * 4 + 1), *p = ret; int i, x; for (i = 0; i < ldata; i += 3) { x = ((unsigned char) data[i] << 16) + (i + 1 < ldata ? ((unsigned char) data[i + 1] << 8) + (i + 2 < ldata ? (unsigned char) data[i + 2] : 0) : 0); *p++ = enc[x >> 18]; *p++ = enc[(x >> 12) & 63]; *p++ = enc[(x >> 6) & 63]; *p++ = enc[x & 63]; } *p = '\0'; if (ldata % 3) *--p = '='; if (ldata % 3 == 1) *--p = '='; return ret; } inline int entity_index(char c) { return (c == '<' ? 0 : (c == '>' ? 1 : (c == '"' ? 2 : (c == '\'' ? 3 : (c == '&' ? 4 : 5))))); } char *xml_escape(const char *str) { int i, j, k; char *ret; int lent[6] = {4, 4, 6, 6, 5, 1}; char *ent[5] = {"<", ">", """, "'", "&"}; for (i = j = 0; str[i]; i++) j += lent[entity_index(str[i])]; ret = (char *) malloc(j + 1); for (i = j = 0; str[i]; i++) { k = entity_index(str[i]); if (k < 5) memcpy(&ret[j], ent[k], lent[k]); else ret[j] = str[i]; j += lent[k]; } ret[j] = '\0'; return ret; } // callback for reading HTTP response size_t read_reply(void *buffer, size_t size, size_t nmemb, void *userp) { int new_len; curl_reply *r = (curl_reply *) userp; for (new_len = r->len; new_len < r->used + size * nmemb + 1; new_len *= 2); if (new_len > r->len) r->buf = realloc(r->buf, new_len); memcpy(r->buf + r->used, buffer, size * nmemb); r->len = new_len; r->used += size * nmemb; r->buf[r->used] = '\0'; return size * nmemb; } // returns file content or NULL in case of error char *read_file(char *fn, int *lret) { FILE *f; struct stat st; char *ret; int nread; printf("Reading file: '%s'\n", fn); // open file f = fopen(fn, "r"); if (f) { // retrieve file information if (fstat(fileno(f), &st) == 0) { if (S_ISREG(st.st_mode)) { printf("\tSize: %d bytes\n", st.st_size); // read all of it into memory // note: this sample program asumes all of file fits into memory // so if you need to work with larger files figure out something else ret = (char *) malloc(st.st_size + 1); nread = fread(ret, 1, st.st_size, f); if (nread == st.st_size) { ret[nread] = '\0'; if (lret) *lret = nread; } else { fprintf(stderr, "Error reading file '%s'\n", fn); free(ret); ret = NULL; } } else { fprintf(stderr, "File '%s' is not a regular file\n", fn); } } else { fprintf(stderr, "Filesystem error retrieving info on '%s'\n", fn); } fclose(f); } else { fprintf(stderr, "Couldn't open file '%s'\n", fn); } return ret; } int main(int argc, char *argv[]) { CURL *curl_handle; curl_reply reply; char *err_buf[CURL_ERROR_SIZE]; char *storage_esc, *user_esc, *password_esc; int i; if (argc == 1) { printf("Usage: [-r url] [-s storage] [-u user] [-p password] files\n"); return 0; } // read options for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (i + 1 >= argc) break; // no option value switch(argv[i][1]) { case 'r': url = argv[i+1]; break; case 's': storage = argv[i+1]; break; case 'u': user = argv[i+1]; break; case 'p': password = argv[i+1]; break; default: printf("Unknown option: %s\n", argv[i]); break; } i++; } } // initialization curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); curl_easy_setopt(curl_handle, CURLOPT_URL, url); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, read_reply); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &reply); curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, err_buf); storage_esc = xml_escape(storage); user_esc = xml_escape(user); password_esc = xml_escape(password); // names of files to be imported are passed as arguments // process each of them for (i = 1; i < argc; i++) { char *buf, *data, *title_esc, *ext_esc, *cmd; int lbuf; // check if argument is option if (argv[i][0] == '-') { if (i + 1 >= argc) break; // no option value i++; continue; } // process file if (buf = read_file(argv[i], &lbuf)) { data = base64_encode(buf, lbuf); free(buf); title_esc = xml_escape(argv[i]); // pass file extension as its type ext_esc = (char *) strrchr(argv[i], '.'); if (ext_esc) ext_esc = xml_escape(ext_esc + 1); else ext_esc = (char *) strdup(""); // format xml cmd = malloc(strlen(cmd_fmt) + strlen(storage_esc) + 16 + strlen(user_esc) + strlen(password_esc) + 2 * strlen(title_esc) + strlen(ext_esc) + strlen(data)); sprintf(cmd, cmd_fmt, storage_esc, i, user_esc, password_esc, title_esc, title_esc, ext_esc, data); curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, cmd); // execute Siets command reply.buf = malloc(reply.len = 1); reply.used = 0; if (curl_easy_perform(curl_handle) != CURLE_OK) { fprintf(stderr, "Error connecting to Siets Server: %s\n", err_buf); } else if (strstr(reply.buf, "")) { // simplified error check *((char *) strstr(reply.buf, "")) = '\0'; fprintf(stderr, "Error returned from Siets Server: %s\n", strstr(reply.buf, "") + 6); } else { *((char *) strstr(reply.buf, "")) = '\0'; printf("Document inserted with id %s\n", strstr(reply.buf, "") + 7); } free(reply.buf); free(cmd); free(ext_esc); free(title_esc); free(data); } } // cleanup free(storage_esc); free(user_esc); free(password_esc); curl_easy_cleanup(curl_handle); curl_global_cleanup(); return 0; }