Code

screen_interface: make cols/rows unsigned
[ncmpc.git] / src / screen_chat.c
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2017 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
20 #include "screen_chat.h"
22 #include "screen_interface.h"
23 #include "screen_utils.h"
24 #include "screen_status.h"
25 #include "screen_text.h"
26 #include "mpdclient.h"
27 #include "i18n.h"
28 #include "charset.h"
29 #include "options.h"
31 #include <glib.h>
32 #include <mpd/idle.h>
34 static struct screen_text text; /* rename? */
35 static const char chat_channel[] = "chat";
37 static bool
38 check_chat_support(struct mpdclient *c)
39 {
40         static unsigned last_connection_id = 0;
41         static bool was_supported = false;
43         /* if we're using the same connection as the last time
44            check_chat_support was called, we can use the cached information
45            about whether chat is supported */
46         if (c->connection_id == last_connection_id)
47                 return was_supported;
49         last_connection_id = c->connection_id;
51         if (c->connection == NULL)
52                 return (was_supported = false);
54         if (mpd_connection_cmp_server_version(c->connection, 0, 17, 0) == -1) {
55                 const unsigned *version = mpd_connection_get_server_version(c->connection);
56                 char *str;
58                 str = g_strdup_printf(
59                         _("connected to MPD %u.%u.%u (you need at least \n"
60                           "version 0.17.0 to use the chat feature)"),
61                         version[0], version[1], version[2]);
62                 screen_text_append(&text, str);
63                 g_free(str);
65                 return (was_supported = false);
66         }
68         /* mpdclient_get_connection? */
69         if (!mpdclient_cmd_subscribe(c, chat_channel))
70                 return (was_supported = false);
71         /* mpdclient_put_connection? */
73         return (was_supported = true);
74 }
76 static void
77 screen_chat_init(WINDOW *w, unsigned cols, unsigned rows)
78 {
79         screen_text_init(&text, w, cols, rows);
80 }
82 static void
83 screen_chat_exit(void)
84 {
85         screen_text_deinit(&text);
86 }
88 static void
89 screen_chat_open(struct mpdclient *c)
90 {
91         (void) check_chat_support(c);
92 }
94 static void
95 screen_chat_resize(unsigned cols, unsigned rows)
96 {
97         screen_text_resize(&text, cols, rows);
98 }
100 static void
101 screen_chat_paint(void)
103         screen_text_paint(&text);
106 static void
107 process_message(struct mpd_message *message)
109         assert(message != NULL);
110         /* You'll have to move this out of screen_chat, if you want to use
111            client-to-client messages anywhere else */
112         assert(g_strcmp0(mpd_message_get_channel(message), chat_channel) == 0);
114         char *message_text = utf8_to_locale(mpd_message_get_text(message));
115         screen_text_append(&text, message_text);
116         g_free(message_text);
118         screen_chat_paint();
121 static void
122 screen_chat_update(struct mpdclient *c)
124         if (check_chat_support(c) && (c->events & MPD_IDLE_MESSAGE)) {
125                 if (!mpdclient_send_read_messages(c))
126                         return;
128                 struct mpd_message *message;
129                 while ((message = mpdclient_recv_message(c)) != NULL) {
130                         process_message(message);
131                         mpd_message_free(message);
132                 }
134                 mpdclient_finish_command(c);
136                 c->events &= ~MPD_IDLE_MESSAGE;
137         }
140 static char *
141 screen_chat_get_prefix(void)
143         static char *prefix = NULL;
145         if (prefix)
146                 return prefix;
148         if (options.chat_prefix) {
149                 /* Options are encoded in the "locale" charset */
150                 prefix = locale_to_utf8(options.chat_prefix);
151                 return prefix;
152         }
154         prefix = g_strconcat("<", g_get_user_name(), "> ", NULL);
155         return prefix;
158 static void
159 screen_chat_send_message(struct mpdclient *c, char *msg)
161         char *utf8 = locale_to_utf8(msg);
162         char *prefix = screen_chat_get_prefix();
163         char *full_msg = g_strconcat(prefix, utf8, NULL);
164         g_free(utf8);
166         (void) mpdclient_cmd_send_message(c, chat_channel, full_msg);
167         g_free(full_msg);
170 static bool
171 screen_chat_cmd(struct mpdclient *c, command_t cmd)
173         if (screen_text_cmd(&text, c, cmd))
174                 return true;
176         if (cmd == CMD_PLAY) {
177                 char *message = screen_readln(_("Your message"), NULL, NULL, NULL);
179                 /* the user entered an empty line */
180                 if (message == NULL)
181                         return true;
183                 if (check_chat_support(c))
184                         screen_chat_send_message(c, message);
185                 else
186                         screen_status_message(_("Message could not be sent"));
188                 g_free(message);
190                 return true;
191         }
193         return false;
196 static const char *
197 screen_chat_title(gcc_unused char *s, gcc_unused size_t size)
199         return _("Chat");
202 const struct screen_functions screen_chat = {
203         .init = screen_chat_init,
204         .exit = screen_chat_exit,
205         .open = screen_chat_open,
206         /* close */
207         .resize = screen_chat_resize,
208         .paint = screen_chat_paint,
209         .update = screen_chat_update,
210         .cmd = screen_chat_cmd,
211         .get_title = screen_chat_title,
212 };