implement message sending to channels
This commit is contained in:
		
							parent
							
								
									0c9432c269
								
							
						
					
					
						commit
						b8fa202ce3
					
				| @ -90,6 +90,12 @@ bool dc_api_create_channel(dc_api_t api, dc_account_t login, | ||||
|  */ | ||||
| bool dc_api_get_messages(dc_api_t api, dc_account_t login, dc_channel_t c); | ||||
| 
 | ||||
| /**
 | ||||
|  * post a message to the given channel | ||||
|  */ | ||||
| bool dc_api_post_message(dc_api_t api, dc_account_t login, | ||||
|                          dc_channel_t c, dc_message_t m); | ||||
| 
 | ||||
| /**
 | ||||
|  * Fetch a list of friends of the login account "login". The friends are stored | ||||
|  * within the login object. | ||||
|  | ||||
| @ -10,6 +10,7 @@ struct dc_message_; | ||||
| typedef struct dc_message_ *dc_message_t; | ||||
| 
 | ||||
| dc_message_t dc_message_new(void); | ||||
| dc_message_t dc_message_new_content(char const *s, int len); | ||||
| dc_message_t dc_message_from_json(json_t *j); | ||||
| json_t *dc_message_to_json(dc_message_t m); | ||||
| 
 | ||||
|  | ||||
| @ -52,6 +52,12 @@ bool dc_session_has_token(dc_session_t s); | ||||
|  */ | ||||
| dc_account_t dc_session_me(dc_session_t s); | ||||
| 
 | ||||
| /**
 | ||||
|  * Return the API handle in use by the session. Do not unref the reference | ||||
|  * and if you need it for something else, dc_ref() it yourself. | ||||
|  */ | ||||
| dc_api_t dc_session_api(dc_session_t s); | ||||
| 
 | ||||
| /**
 | ||||
|  * access to the internal account cache | ||||
|  */ | ||||
|  | ||||
| @ -2,6 +2,36 @@ | ||||
| 
 | ||||
| #include "internal.h" | ||||
| 
 | ||||
| bool dc_api_post_message(dc_api_t api, dc_account_t login, | ||||
|                          dc_channel_t c, dc_message_t m) | ||||
| { | ||||
|     bool ret = false; | ||||
|     char *url = NULL; | ||||
|     json_t *j = NULL, *reply = NULL; | ||||
| 
 | ||||
|     return_if_true(api == NULL || login == NULL || m == NULL, false); | ||||
|     return_if_true(dc_message_content(m) == NULL, false); | ||||
| 
 | ||||
|     asprintf(&url, "channels/%s/messages", dc_channel_id(c)); | ||||
|     goto_if_true(url == NULL, cleanup); | ||||
| 
 | ||||
|     j = dc_message_to_json(m); | ||||
|     goto_if_true(j == NULL, cleanup); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "POST", TOKEN(login), url, j); | ||||
|     goto_if_true(reply != NULL, cleanup); | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     free(url); | ||||
|     json_decref(j); | ||||
|     json_decref(reply); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_get_messages(dc_api_t api, dc_account_t login, dc_channel_t c) | ||||
| { | ||||
|     bool ret = false; | ||||
|  | ||||
| @ -40,6 +40,24 @@ dc_message_t dc_message_new(void) | ||||
|     return dc_ref(m); | ||||
| } | ||||
| 
 | ||||
| dc_message_t dc_message_new_content(char const *s, int len) | ||||
| { | ||||
|     dc_message_t m = dc_message_new(); | ||||
|     return_if_true(m == NULL, NULL); | ||||
| 
 | ||||
|     if (len < 0) { | ||||
|         len = strlen(s); | ||||
|     } | ||||
| 
 | ||||
|     m->content = strndup(s, len); | ||||
|     if (m->content == NULL) { | ||||
|         dc_unref(m); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return m; | ||||
| } | ||||
| 
 | ||||
| dc_message_t dc_message_from_json(json_t *j) | ||||
| { | ||||
|     dc_message_t m = NULL; | ||||
|  | ||||
| @ -227,6 +227,12 @@ bool dc_session_has_token(dc_session_t s) | ||||
|     return dc_account_has_token(s->login); | ||||
| } | ||||
| 
 | ||||
| dc_api_t dc_session_api(dc_session_t s) | ||||
| { | ||||
|     return_if_true(s == NULL, NULL); | ||||
|     return s->api; | ||||
| } | ||||
| 
 | ||||
| dc_account_t dc_session_me(dc_session_t s) | ||||
| { | ||||
|     return_if_true(s == NULL, NULL); | ||||
|  | ||||
| @ -23,6 +23,7 @@ SET(SOURCES | ||||
|   "src/mainwindow.c" | ||||
|   "src/msg.c" | ||||
|   "src/ncdc.c" | ||||
|   "src/post.c" | ||||
|   "src/textview.c" | ||||
|   "src/util.c" | ||||
|   ) | ||||
|  | ||||
| @ -4,8 +4,14 @@ | ||||
| #include <ncdc/ncdc.h> | ||||
| #include <ncdc/mainwindow.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * n      .. the main window handle | ||||
|  * ac,av  .. the full string parsed up along white spaces | ||||
|  * f      .. the full string, without the /command bit | ||||
|  */ | ||||
| typedef bool (*ncdc_command_t)(ncdc_mainwindow_t n, | ||||
|                                size_t argc, wchar_t **argv); | ||||
|                                size_t argc, wchar_t **argv, | ||||
|                                wchar_t const *f); | ||||
| 
 | ||||
| typedef struct { | ||||
|     wchar_t const *name; | ||||
| @ -24,10 +30,11 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s); | ||||
|  */ | ||||
| ncdc_commands_t *ncdc_find_cmd(ncdc_commands_t *cmds, wchar_t const *name); | ||||
| 
 | ||||
| bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); | ||||
| bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); | ||||
| bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); | ||||
| bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); | ||||
| bool ncdc_cmd_post(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); | ||||
| bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -15,6 +15,7 @@ ncdc_mainwindow_t ncdc_mainwindow_new(void); | ||||
| void ncdc_mainwindow_log(ncdc_mainwindow_t w, wchar_t const *fmt, ...); | ||||
| 
 | ||||
| GPtrArray *ncdc_mainwindow_views(ncdc_mainwindow_t n); | ||||
| dc_channel_t ncdc_mainwindow_current_channel(ncdc_mainwindow_t n); | ||||
| void ncdc_mainwindow_switchview(ncdc_mainwindow_t n, int idx); | ||||
| 
 | ||||
| void ncdc_mainwindow_refresh(ncdc_mainwindow_t n); | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include <wctype.h> | ||||
| #include <ctype.h> | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| @ -6,6 +6,7 @@ ncdc_commands_t cmds[] = { | ||||
|     { L"/login",   ncdc_cmd_login }, | ||||
|     { L"/logout",  ncdc_cmd_logout }, | ||||
|     { L"/msg",     ncdc_cmd_msg }, | ||||
|     { L"/post",    ncdc_cmd_post }, | ||||
|     { L"/quit",    ncdc_cmd_quit }, | ||||
|     { NULL, NULL } | ||||
| }; | ||||
| @ -17,6 +18,7 @@ static pthread_cond_t cnd; | ||||
| 
 | ||||
| typedef struct { | ||||
|     ncdc_commands_t *cmd; | ||||
|     wchar_t *f; | ||||
|     size_t ac; | ||||
|     wchar_t **av; | ||||
|     ncdc_mainwindow_t mainwindow; | ||||
| @ -43,9 +45,12 @@ static void *async_dispatcher(void *arg) | ||||
|             } else { | ||||
|                 /* call the handler
 | ||||
|                  */ | ||||
|                 item->cmd->handler(item->mainwindow, item->ac, item->av); | ||||
|                 item->cmd->handler(item->mainwindow, item->ac, | ||||
|                                    item->av, item->f | ||||
|                     ); | ||||
| 
 | ||||
|                 w_strfreev(item->av); | ||||
|                 free(item->f); | ||||
|                 free(item); | ||||
|             } | ||||
|         } | ||||
| @ -109,6 +114,8 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s) | ||||
|     wchar_t **tokens = NULL; | ||||
|     ncdc_commands_t *it = NULL; | ||||
|     queue_item *item = NULL; | ||||
|     wchar_t *f = NULL; | ||||
|     size_t len = 0, cmdlen = 0; | ||||
| 
 | ||||
|     tokens = w_tokenise(s); | ||||
|     return_if_true(tokens == NULL, false); | ||||
| @ -121,12 +128,21 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s) | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /* make a complete string without the /command part
 | ||||
|      */ | ||||
|     len = wcslen(s); | ||||
|     cmdlen = wcslen(it->name); | ||||
|     f = wcsdup(s); | ||||
|     return_if_true(f == NULL, false); | ||||
|     memmove(f, f+cmdlen, len-cmdlen); | ||||
| 
 | ||||
|     item = calloc(1, sizeof(queue_item)); | ||||
| 
 | ||||
|     item->ac = w_strlenv(tokens); | ||||
|     item->av = tokens; | ||||
|     item->cmd = it; | ||||
|     item->mainwindow = n; | ||||
|     item->f = f; | ||||
| 
 | ||||
|     pthread_mutex_lock(&mtx); | ||||
|     g_queue_push_tail(queue, item); | ||||
| @ -136,7 +152,8 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s) | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, | ||||
|                    wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     exit_main(); | ||||
|     return true; | ||||
|  | ||||
| @ -2,7 +2,8 @@ | ||||
| #include <ncdc/ncdc.h> | ||||
| 
 | ||||
| static bool | ||||
| ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, | ||||
|                       wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     size_t i = 0; | ||||
|     char c = ' '; | ||||
| @ -23,7 +24,8 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac, | ||||
|                      wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     char *name = NULL; | ||||
|     dc_account_t friend = NULL; | ||||
| @ -60,7 +62,8 @@ cleanup: | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| ncdc_cmd_friends_remove(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| ncdc_cmd_friends_remove(ncdc_mainwindow_t n, size_t ac, | ||||
|                         wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     char *name = NULL; | ||||
|     dc_account_t friend = NULL; | ||||
| @ -104,7 +107,8 @@ cleanup: | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| ncdc_cmd_friends_accept(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| ncdc_cmd_friends_accept(ncdc_mainwindow_t n, size_t ac, | ||||
|                         wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     char *name = NULL; | ||||
|     dc_account_t friend = NULL; | ||||
| @ -156,7 +160,8 @@ static ncdc_commands_t subcmds[] = { | ||||
|     { NULL,     NULL } | ||||
| }; | ||||
| 
 | ||||
| bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, | ||||
|                       wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     wchar_t *subcmd = NULL; | ||||
|     ncdc_commands_t *it = NULL; | ||||
| @ -167,7 +172,7 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|     } | ||||
| 
 | ||||
|     if (ac <= 1) { | ||||
|         return ncdc_cmd_friends_list(n, ac, av); | ||||
|         return ncdc_cmd_friends_list(n, ac, av, f); | ||||
|     } | ||||
| 
 | ||||
|     subcmd = av[1]; | ||||
| @ -180,5 +185,5 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return it->handler(n, ac, av); | ||||
|     return it->handler(n, ac, av, f); | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,8 @@ | ||||
| #include <ncdc/ncdc.h> | ||||
| #include <ncdc/config.h> | ||||
| 
 | ||||
| bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, | ||||
|                     wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     char *arg = NULL; | ||||
|     bool ret = false; | ||||
|  | ||||
| @ -2,7 +2,8 @@ | ||||
| #include <ncdc/ncdc.h> | ||||
| #include <ncdc/config.h> | ||||
| 
 | ||||
| bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac, | ||||
|                      wchar_t **av, wchar_t const *f) | ||||
| { | ||||
|     bool ret = false; | ||||
| 
 | ||||
|  | ||||
| @ -110,16 +110,25 @@ ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s, | ||||
|                          size_t len, void *arg) | ||||
| { | ||||
|     ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg; | ||||
|     bool ret = false; | ||||
| 
 | ||||
|     if (s != NULL && s[0] == '/') { | ||||
|         if (s[1] == '\0') { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return ncdc_dispatch(mainwin, s); | ||||
|     if (s == NULL || s[0] == '\0') { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
|     if (s[0] == '/') { | ||||
|         ret = ncdc_dispatch(mainwin, s); | ||||
|     } else { | ||||
|         wchar_t *post = calloc(wcslen(s)+6, sizeof(wchar_t)); | ||||
| 
 | ||||
|         wcscat(post, L"/post "); | ||||
|         wcscat(post, s); | ||||
| 
 | ||||
|         ret = ncdc_dispatch(mainwin, post); | ||||
|         free(post); | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static void ncdc_mainwindow_resize(ncdc_mainwindow_t n) | ||||
| @ -331,3 +340,13 @@ void ncdc_mainwindow_leftview(ncdc_mainwindow_t n) | ||||
|     return_if_true(n == NULL,); | ||||
|     n->curview = (n->curview - 1) % n->views->len; | ||||
| } | ||||
| 
 | ||||
| dc_channel_t ncdc_mainwindow_current_channel(ncdc_mainwindow_t n) | ||||
| { | ||||
|     return_if_true(n == NULL, NULL); | ||||
|     ncdc_textview_t view = g_ptr_array_index(n->views, n->curview); | ||||
|     /* can't post to the log channel, that's for internal use only
 | ||||
|      */ | ||||
|     return_if_true(view == n->log, NULL); | ||||
|     return ncdc_textview_channel(view); | ||||
| } | ||||
|  | ||||
| @ -2,13 +2,15 @@ | ||||
| #include <ncdc/ncdc.h> | ||||
| #include <ncdc/textview.h> | ||||
| 
 | ||||
| bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, | ||||
|                   wchar_t **av, wchar_t const *fullmsg) | ||||
| { | ||||
|     return_if_true(ac <= 1, false); | ||||
| 
 | ||||
|     char * target = NULL; | ||||
|     wchar_t *full_message = NULL; | ||||
|     char * message = NULL; | ||||
|     dc_message_t m = NULL; | ||||
|     bool ret = false; | ||||
|     dc_channel_t c = NULL; | ||||
|     ncdc_textview_t v = NULL; | ||||
| @ -64,15 +66,34 @@ bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|         ncdc_mainwindow_switchview(n, ncdc_mainwindow_views(n)->len-1); | ||||
|     } | ||||
| 
 | ||||
|     if (ac > 2) { | ||||
|         /* also post the rest of the content as a message to the channel
 | ||||
|          */ | ||||
|         full_message = wcsstr(fullmsg, av[2]); | ||||
|         goto_if_true(full_message == NULL, cleanup); | ||||
| 
 | ||||
|         message = w_convert(full_message); | ||||
|         goto_if_true(message == NULL, cleanup); | ||||
| 
 | ||||
|         m = dc_message_new_content(message, -1); | ||||
|         goto_if_true(m == NULL, cleanup); | ||||
| 
 | ||||
|         ret = dc_api_post_message( | ||||
|             dc_session_api(current_session), | ||||
|             dc_session_me(current_session), | ||||
|             c, m | ||||
|             ); | ||||
|     } | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     dc_unref(c); | ||||
|     dc_unref(v); | ||||
|     dc_unref(m); | ||||
| 
 | ||||
|     free(target); | ||||
|     free(full_message); | ||||
|     free(message); | ||||
| 
 | ||||
|     return ret; | ||||
|  | ||||
							
								
								
									
										50
									
								
								ncdc/src/post.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								ncdc/src/post.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| #include <ncdc/cmds.h> | ||||
| #include <ncdc/ncdc.h> | ||||
| 
 | ||||
| bool ncdc_cmd_post(ncdc_mainwindow_t n, size_t ac, wchar_t **av, | ||||
|                    wchar_t const *f) | ||||
| { | ||||
|     char *str = NULL; | ||||
|     bool ret = false; | ||||
|     dc_message_t m = NULL; | ||||
|     dc_channel_t chan = NULL; | ||||
|     size_t i = 0; | ||||
| 
 | ||||
|     if (!is_logged_in()) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     chan = ncdc_mainwindow_current_channel(n); | ||||
|     goto_if_true(chan == NULL, cleanup); | ||||
| 
 | ||||
|     /* the API only uses multi-byte strings, so convert from wchar_t
 | ||||
|      */ | ||||
|     str = w_convert(f); | ||||
|     goto_if_true(str == NULL, cleanup); | ||||
| 
 | ||||
|     /* trim string at least on the left
 | ||||
|      */ | ||||
|     for (i = 0; isspace(str[i]) && str[i] != '\0'; i++) | ||||
|         ; | ||||
|     goto_if_true (str[i] == '\0', cleanup); | ||||
|     memmove(str, str+i, strlen(str)+1-i); | ||||
| 
 | ||||
|     m = dc_message_new_content(str, -1); | ||||
|     goto_if_true(m == NULL, cleanup); | ||||
| 
 | ||||
|     ret = dc_api_post_message( | ||||
|         dc_session_api(current_session), | ||||
|         dc_session_me(current_session), | ||||
|         chan, m | ||||
|         ); | ||||
|     goto_if_true(ret == false, cleanup); | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     dc_unref(m); | ||||
|     free(str); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
							
								
								
									
										4
									
								
								todo.org
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								todo.org
									
									
									
									
									
								
							| @ -1,8 +1,8 @@ | ||||
| * Channels [0/4] | ||||
| * Channels [1/4] | ||||
| ** TODO Automatically open window for 1:1 and 1:N | ||||
| ** TODO send v6/api/channels/$ID/ack for "I read that shit" | ||||
| ** TODO add timestamps from messages | ||||
| ** TODO add message sending | ||||
| ** DONE add message sending | ||||
| * Guilds [0/3] | ||||
| ** TODO Guild support code | ||||
| ** TODO Guild view on the left pane | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user