about summary refs log blame commit diff stats
path: root/manual_tests
blob: 8ca289317ead03ea6cddf28611085553cdecb5b5 (plain) (tree)
1
2
3
4
5
6
7
8
9


                                            
                             
                                                                     

                                                                   
                                       
                                  



                                                                                                      
 


                                                 
                            
 

                                                         







                                                                                              
                                                                        
                                                                                         
                                                                    
file load:
  cursor_line = 1
  first line is a drawing -> cursor_line = 2
click on text -> cursor moves
click on first character of text -> cursor on first character of text
click to right of text -> cursor past end of line
click to right of wrapped text -> cursor on final character of line
click on drawing -> cursor doesn't move
cursor past end of line -> renders
create drawing -> cursor bumps down below drawing
backspace
  cursor_pos == 0, previous line is a drawing -> delete drawing, cursor still visible at start of line
  cursor_pos == 0, previous line is text -> join lines, cursor still at same character

drawing
  draw a line, circle, rectangle, square, polygon
  select a point and move it
  select a point and name it

enter
  cursor_pos == 0 -> insert empty line above current line

scrolling:
  given moby dick, a file containing all text:
  page up moves top line on screen to bottom
  page down moves bottom line on screen to top
  cursor remains on screen
  cursor remains on text line
  'up' arrow with cursor at top of screen scrolls up one line (drawings still fully in or out)
    if cursor line wrapped before, it scrolls up by only one screen line
    if previous line (above top of screen) wrapped, it scrolls up by only one screen line
  'down' arrow with cursor at bottom of screen scrolls down one line (drawings still fully in or out)
    if cursor line wrapped before, it scrolls down by only one screen line

persistence:
  draw a line, circle, rectangle, square, polygon, quit, restart. All the shapes you drew should still be visible.
  select a point and name it, quit, restart. Name is still visible.

clipboard:
  cut/copy without making a selection

resize:
  create a file containing a long line of characters without spaces. try
  resizing the window vertically and horizontally, as far as possible.
s="cp">#include <sys/types.h> #include <curl/curl.h> #include <gio/gio.h> #include <pthread.h> #include <assert.h> #include "profanity.h" #include "event/client_events.h" #include "tools/http_upload.h" #include "config/preferences.h" #include "ui/ui.h" #include "ui/window.h" #include "common.h" #define FALLBACK_MIMETYPE "application/octet-stream" #define FALLBACK_CONTENTTYPE_HEADER "Content-Type: application/octet-stream" #define FALLBACK_MSG "" #define FILE_HEADER_BYTES 512 struct curl_data_t { char* buffer; size_t size; }; GSList* upload_processes = NULL; static int _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { HTTPUpload* upload = (HTTPUpload*)userdata; pthread_mutex_lock(&lock); if (upload->cancel) { pthread_mutex_unlock(&lock); return 1; } if (upload->bytes_sent == ulnow) { pthread_mutex_unlock(&lock); return 0; } else { upload->bytes_sent = ulnow; } unsigned int ulperc = 0; if (ultotal != 0) { ulperc = (100 * ulnow) / ultotal; } gchar* msg = g_strdup_printf("Uploading '%s': %d%%", upload->filename, ulperc); if (!msg) { msg = g_strdup(FALLBACK_MSG); } win_update_entry_message(upload->window, upload->put_url, msg); g_free(msg); pthread_mutex_unlock(&lock); return 0; } #if LIBCURL_VERSION_NUM < 0x072000 static int _older_progress(void* p, double dltotal, double dlnow, double ultotal, double ulnow) { return _xferinfo(p, (curl_off_t)dltotal, (curl_off_t)dlnow, (curl_off_t)ultotal, (curl_off_t)ulnow); } #endif static size_t _data_callback(void* ptr, size_t size, size_t nmemb, void* data) { size_t realsize = size * nmemb; struct curl_data_t* mem = (struct curl_data_t*)data; mem->buffer = realloc(mem->buffer, mem->size + realsize + 1); if (mem->buffer) { memcpy(&(mem->buffer[mem->size]), ptr, realsize); mem->size += realsize; mem->buffer[mem->size] = 0; } return realsize; } int format_alt_url(char* original_url, char* new_scheme, char* new_fragment, char** new_url) { int ret = 0; CURLU* h = curl_url(); if ((ret = curl_url_set(h, CURLUPART_URL, original_url, 0)) != 0) { goto out; } if (new_scheme != NULL) { if ((ret = curl_url_set(h, CURLUPART_SCHEME, new_scheme, CURLU_NON_SUPPORT_SCHEME)) != 0) { goto out; } } if (new_fragment != NULL) { if ((ret = curl_url_set(h, CURLUPART_FRAGMENT, new_fragment, 0)) != 0) { goto out; } } ret = curl_url_get(h, CURLUPART_URL, new_url, 0); out: curl_url_cleanup(h); return ret; } void* http_file_put(void* userdata) { HTTPUpload* upload = (HTTPUpload*)userdata; FILE* fh = NULL; char* err = NULL; gchar* content_type_header; // Optional headers gchar* auth_header = NULL; gchar* cookie_header = NULL; gchar* expires_header = NULL; CURL* curl; CURLcode res; upload->cancel = 0; upload->bytes_sent = 0; pthread_mutex_lock(&lock); gchar* msg = g_strdup_printf("Uploading '%s': 0%%", upload->filename); if (!msg) { msg = g_strdup(FALLBACK_MSG); } win_print_http_transfer(upload->window, msg, upload->put_url); g_free(msg); char* cert_path = prefs_get_string(PREF_TLS_CERTPATH); pthread_mutex_unlock(&lock); curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, upload->put_url); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); struct curl_slist* headers = NULL; content_type_header = g_strdup_printf("Content-Type: %s", upload->mime_type); if (!content_type_header) { content_type_header = g_strdup(FALLBACK_CONTENTTYPE_HEADER); } headers = curl_slist_append(headers, content_type_header); headers = curl_slist_append(headers, "Expect:"); // Optional headers if (upload->authorization) { auth_header = g_strdup_printf("Authorization: %s", upload->authorization); if (!auth_header) { auth_header = g_strdup(FALLBACK_MSG); } headers = curl_slist_append(headers, auth_header); } if (upload->cookie) { cookie_header = g_strdup_printf("Cookie: %s", upload->cookie); if (!cookie_header) { cookie_header = g_strdup(FALLBACK_MSG); } headers = curl_slist_append(headers, cookie_header); } if (upload->expires) { expires_header = g_strdup_printf("Expires: %s", upload->expires); if (!expires_header) { expires_header = g_strdup(FALLBACK_MSG); } headers = curl_slist_append(headers, expires_header); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); #if LIBCURL_VERSION_NUM >= 0x072000 curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, _xferinfo); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, upload); #else curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, _older_progress); curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, upload); #endif curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); struct curl_data_t output; output.buffer = NULL; output.size = 0; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _data_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&output); curl_easy_setopt(curl, CURLOPT_USERAGENT, "profanity"); fh = upload->filehandle; if (cert_path) { curl_easy_setopt(curl, CURLOPT_CAPATH, cert_path); } curl_easy_setopt(curl, CURLOPT_READDATA, fh); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)(upload->filesize)); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); if ((res = curl_easy_perform(curl)) != CURLE_OK) { err = strdup(curl_easy_strerror(res)); } else { long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if (output.buffer) { output.buffer[output.size++] = '\0'; } // XEP-0363 specifies 201 but prosody returns 200 if (http_code != 200 && http_code != 201) { err = g_strdup_printf("Server returned %lu", http_code); } #if 0 printf("HTTP Status: %lu\n", http_code); printf("%s\n", output.buffer); printf("%lu bytes retrieved\n", (long)output.size); #endif } curl_easy_cleanup(curl); curl_global_cleanup(); curl_slist_free_all(headers); if (fh) { fclose(fh); } free(output.buffer); g_free(content_type_header); g_free(auth_header); g_free(cookie_header); g_free(expires_header); pthread_mutex_lock(&lock); g_free(cert_path); if (err) { gchar* msg; if (upload->cancel) { msg = g_strdup_printf("Uploading '%s' failed: Upload was canceled", upload->filename); if (!msg) { msg = g_strdup(FALLBACK_MSG); } } else { msg = g_strdup_printf("Uploading '%s' failed: %s", upload->filename, err); if (!msg) { msg = g_strdup(FALLBACK_MSG); } win_update_entry_message(upload->window, upload->put_url, msg); } cons_show_error(msg); g_free(msg); free(err); } else { if (!upload->cancel) { msg = g_strdup_printf("Uploading '%s': 100%%", upload->filename); if (!msg) { msg = g_strdup(FALLBACK_MSG); } win_update_entry_message(upload->window, upload->put_url, msg); win_mark_received(upload->window, upload->put_url); g_free(msg); char* url = NULL; if (format_alt_url(upload->get_url, upload->alt_scheme, upload->alt_fragment, &url) != 0) { gchar* msg = g_strdup_printf("Uploading '%s' failed: Bad URL ('%s')", upload->filename, upload->get_url); if (!msg) { msg = g_strdup(FALLBACK_MSG); } cons_show_error(msg); g_free(msg); } else { switch (upload->window->type) { case WIN_CHAT: { ProfChatWin* chatwin = (ProfChatWin*)(upload->window); assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); cl_ev_send_msg(chatwin, url, url); break; } case WIN_PRIVATE: { ProfPrivateWin* privatewin = (ProfPrivateWin*)(upload->window); assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK); cl_ev_send_priv_msg(privatewin, url, url); break; } case WIN_MUC: { ProfMucWin* mucwin = (ProfMucWin*)(upload->window); assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); cl_ev_send_muc_msg(mucwin, url, url); break; } default: break; } curl_free(url); } } } upload_processes = g_slist_remove(upload_processes, upload); pthread_mutex_unlock(&lock); free(upload->filename); free(upload->mime_type); free(upload->get_url); free(upload->put_url); free(upload->alt_scheme); free(upload->alt_fragment); free(upload->authorization); free(upload->cookie); free(upload->expires); free(upload); return NULL; } char* file_mime_type(const char* const filename) { char* out_mime_type; char file_header[FILE_HEADER_BYTES]; FILE* fh; if (!(fh = fopen(filename, "rb"))) { return strdup(FALLBACK_MIMETYPE); } size_t file_header_size = fread(file_header, 1, FILE_HEADER_BYTES, fh); fclose(fh); char* content_type = g_content_type_guess(filename, (unsigned char*)file_header, file_header_size, NULL); if (content_type != NULL) { char* mime_type = g_content_type_get_mime_type(content_type); out_mime_type = strdup(mime_type); g_free(mime_type); } else { return strdup(FALLBACK_MIMETYPE); } g_free(content_type); return out_mime_type; } off_t file_size(int filedes) { struct stat st; fstat(filedes, &st); return st.st_size; } void http_upload_cancel_processes(ProfWin* window) { GSList* upload_process = upload_processes; while (upload_process) { HTTPUpload* upload = upload_process->data; if (upload->window == window) { upload->cancel = 1; break; } upload_process = g_slist_next(upload_process); } } void http_upload_add_upload(HTTPUpload* upload) { upload_processes = g_slist_append(upload_processes, upload); }