cmd.c
changeset 5 1b3263c96cbe
parent 4 e305d7e562c4
child 6 8e64b6d3302e
equal deleted inserted replaced
4:e305d7e562c4 5:1b3263c96cbe
    34 #include "roster.h"
    34 #include "roster.h"
    35 
    35 
    36 typedef struct {
    36 typedef struct {
    37 	gchar      *jid;
    37 	gchar      *jid;
    38 	GString    *input;
    38 	GString    *input;
       
    39 	gchar      *subject;
       
    40 	guint       seq;
    39 	guint       source;
    41 	guint       source;
    40 	GIOChannel *channel;
    42 	GIOChannel *channel;
    41 } cmd_cb_t;
    43 } cmd_cb_t;
    42 
    44 
    43 static GSList  *cmd_channels = NULL;
    45 static GSList *cmd_channels = NULL;
       
    46 
       
    47 static gboolean is_room (const gchar *jid)
       
    48 {
       
    49 	return roster_find (jid, jidsearch, ROSTER_TYPE_ROOM) ? TRUE : FALSE;
       
    50 }
       
    51 
       
    52 static gboolean cmd_send_msg (const gchar *to, const gchar *subject, const gchar *body)
       
    53 {
       
    54 	gboolean room    = is_room (to);
       
    55 	gpointer xep184  = NULL;
       
    56 	gint     crypted;
       
    57 
       
    58 	xmpp_send_msg (to, body, room ? ROSTER_TYPE_ROOM : ROSTER_TYPE_USER, room ? NULL : subject, FALSE /* ? */, &crypted, LM_MESSAGE_SUB_TYPE_NOT_SET, &xep184);
       
    59 
       
    60 	if (crypted == -1) {
       
    61 		scr_LogPrint (LPRINT_LOGNORM, "cmd: Encryption error. Message not sent.");
       
    62 		return FALSE;
       
    63 	}
       
    64 
       
    65 	if (!room)
       
    66 		hk_message_out (to, subject, 0, body, crypted, xep184);
       
    67 
       
    68 	return TRUE;
       
    69 }
    44 
    70 
    45 static gboolean cmd_reader (GIOChannel *channel, GIOCondition condition, gpointer data)
    71 static gboolean cmd_reader (GIOChannel *channel, GIOCondition condition, gpointer data)
    46 {
    72 {
    47 	cmd_cb_t *cb = (cmd_cb_t *) data;
    73 	cmd_cb_t *cb = (cmd_cb_t *) data;
    48 
    74 
    49 	if (condition & (G_IO_IN|G_IO_PRI)) {
    75 	if (condition & (G_IO_IN|G_IO_PRI)) {
    50 		GIOStatus    chstat;
    76 		GIOStatus     chstat;
    51 		static gchar buf[HBB_BLOCKSIZE];
    77 		static gchar  buf[HBB_BLOCKSIZE];
    52 		gsize        endpos;
    78 		gsize         endpos;
    53 
    79 		GError       *error              = NULL;
    54 		chstat = g_io_channel_read_chars (channel, buf, HBB_BLOCKSIZE, &endpos, NULL);
    80 
       
    81 		chstat = g_io_channel_read_chars (channel, buf, HBB_BLOCKSIZE, &endpos, &error);
       
    82 
       
    83 		if (error) {
       
    84 			scr_LogPrint (LPRINT_DEBUG, "cmd: Reading error: %s.", error -> message);
       
    85 			g_clear_error (&error);
       
    86 		}
    55 
    87 
    56 		if (chstat == G_IO_STATUS_ERROR || chstat == G_IO_STATUS_EOF) {
    88 		if (chstat == G_IO_STATUS_ERROR || chstat == G_IO_STATUS_EOF) {
    57 			cb->source = 0;
    89 			cb->source = 0;
    58 			return FALSE; // XXX
    90 			return FALSE; // XXX
    59 		}
    91 		}
    60 		
    92 		
    61 		if (endpos) {
    93 		if (endpos) {
    62 			GString *input = cb->input;
    94 			GString *input = cb->input;
    63 			gsize    bread   = 0;
    95 			gsize    bread   = 0;
    64 			gsize    written = 0;
    96 			gsize    written = 0;
    65 			GError  *err     = NULL;
       
    66 			gchar   *utf8    = NULL;
    97 			gchar   *utf8    = NULL;
    67 
    98 
    68 			g_string_append_len (input, buf, endpos);
    99 			g_string_append_len (input, buf, endpos);
    69 
   100 
    70 			if (!lm_connection_is_authenticated (lconnection)) {
   101 			if (!lm_connection_is_authenticated (lconnection)) {
    73 			}
   104 			}
    74 
   105 
    75 			// usual g_locale_to_utf8 seem to be unable to detect locale charset
   106 			// usual g_locale_to_utf8 seem to be unable to detect locale charset
    76 			// maybe, proper solution will be to call setlocale on module loading,
   107 			// maybe, proper solution will be to call setlocale on module loading,
    77 			// but mcabber already does this, and I do not want to mess with it
   108 			// but mcabber already does this, and I do not want to mess with it
    78 			utf8 = g_convert (input->str, input->len, LocaleCharSet, "UTF-8", &bread, &written, &err);
   109 			utf8 = g_convert (input->str, input->len, LocaleCharSet, "UTF-8", &bread, &written, &error);
    79 
   110 
    80 			if (err && err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE && bread) {
   111 			if (error && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE && bread) {
    81 				err     = NULL;
       
    82 				written = 0;
   112 				written = 0;
    83 				utf8 = g_convert (input->str, bread, LocaleCharSet, "UTF-8", &bread, &written, &err);
   113 				g_clear_error (&error);
       
   114 				utf8 = g_convert (input->str, bread, LocaleCharSet, "UTF-8", &bread, &written, &error);
    84 			}
   115 			}
    85 			
   116 			
    86 			if (written) {
   117 			if (written) {
    87 				gsize sent = 0;
   118 				gsize sent = 0;
    88 
   119 
    89 				while (sent < written) {
   120 				while (sent < written) {
    90 					gint      crypted;
       
    91 					gpointer  xep184  = NULL;
       
    92 					gsize     len     = 0;
   121 					gsize     len     = 0;
    93 					gchar    *bbuf    = NULL;
   122 					gchar    *bbuf    = NULL;
    94 					int       type    = roster_find (cb->jid, jidsearch, ROSTER_TYPE_ROOM) ? ROSTER_TYPE_ROOM : ROSTER_TYPE_USER;
   123 					gchar    *subject = NULL;
       
   124 					gboolean  ret;
    95 
   125 
    96 					if (written - sent > HBB_BLOCKSIZE) {
   126 					if (written - sent > HBB_BLOCKSIZE) {
    97 						gchar *c = utf8 + sent + HBB_BLOCKSIZE;
   127 						gchar *c = utf8 + sent + HBB_BLOCKSIZE;
    98 						c = g_utf8_find_prev_char (utf8 + sent, c);
   128 						c = g_utf8_find_prev_char (utf8 + sent, c);
    99 
   129 
   104 
   134 
   105 						len  = c - utf8 - sent;
   135 						len  = c - utf8 - sent;
   106 						bbuf = g_strndup (utf8 + sent, len);
   136 						bbuf = g_strndup (utf8 + sent, len);
   107 					}
   137 					}
   108 
   138 
   109 					// XXX add command/sequence number as title?
   139 					cb -> seq += 1;
   110 					xmpp_send_msg (cb->jid, len ? bbuf : (utf8 + sent), type, NULL, FALSE /* ? */, &crypted, LM_MESSAGE_SUB_TYPE_NOT_SET, &xep184);
   140 
   111 
   141 					if (cb -> subject)
   112 					if (crypted == -1) {
   142 						subject = g_strdup_printf (cb -> subject, cb -> seq);
   113 
   143 
       
   144 					if (!cmd_send_msg (cb->jid, subject, len ? bbuf : (utf8 + sent)))
   114 						scr_LogPrint (LPRINT_LOGNORM, "cmd: Encryption error. Message not sent.");
   145 						scr_LogPrint (LPRINT_LOGNORM, "cmd: Encryption error. Message not sent.");
   115 
   146 
   116 						if (!len)
   147 					if (subject)
   117 							break;
   148 						g_free (subject);
   118 
       
   119 						g_free (bbuf);
       
   120 
       
   121 						continue;
       
   122 					}
       
   123 
       
   124 					if (type != ROSTER_TYPE_ROOM)
       
   125 						hk_message_out (cb->jid, NULL, 0, len ? bbuf : (utf8 + sent), crypted, xep184);
       
   126 
   149 
   127 					if (!len)
   150 					if (!len)
   128 						break;
   151 						break;
   129 
   152 
   130 					g_free (bbuf);
   153 					g_free (bbuf);
   136 
   159 
   137 				g_string_erase (input, 0, bread);
   160 				g_string_erase (input, 0, bread);
   138 
   161 
   139 			} else {
   162 			} else {
   140 
   163 
   141 				scr_LogPrint (LPRINT_LOGNORM, "cmd: Character conversion error: %s", err->message);
   164 				scr_LogPrint (LPRINT_LOGNORM, "cmd: Character conversion error: %s", error->message);
       
   165 				g_error_free (error);
   142 				cb->source = 0;
   166 				cb->source = 0;
   143 				return FALSE;
   167 				return FALSE;
   144 			}
   168 			}
   145 		}
   169 		}
   146 
   170 
   156 {
   180 {
   157 	cmd_cb_t *cb = (cmd_cb_t *) data;
   181 	cmd_cb_t *cb = (cmd_cb_t *) data;
   158 
   182 
   159 	cmd_channels = g_slist_remove (cmd_channels, data);
   183 	cmd_channels = g_slist_remove (cmd_channels, data);
   160 
   184 
   161 	// May conflict - will be called during source removal?
   185 	if (cb->source)
   162 //	if (cb->source)
   186 		g_source_remove (cb->source);
   163 //		g_source_remove (cb->source);
       
   164 	if (cb->channel)
   187 	if (cb->channel)
   165 		g_io_channel_unref (cb->channel);
   188 		g_io_channel_unref (cb->channel);
       
   189 	if (cb -> subject)
       
   190 		g_free (cb -> subject);
   166 	g_free (cb->jid);
   191 	g_free (cb->jid);
   167 	g_free (cb);
   192 	g_free (cb);
   168 }
   193 }
   169 
   194 
   170 static void do_cmd (char *arg)
   195 static void do_cmd (char *arg)
   174 
   199 
   175 	if (!*arg)
   200 	if (!*arg)
   176 		return;
   201 		return;
   177 	
   202 	
   178 	if (!jid) {
   203 	if (!jid) {
   179 		scr_LogPrint (LPRINT_LOGNORM, "Unsuitable buddy selected");
   204 		scr_LogPrint (LPRINT_LOGNORM, "Unsuitable buddy selected.");
   180 		return;
   205 		return;
   181 	}
   206 	}
   182 	
   207 	
   183 	if (pipe (fd)) {
   208 	if (pipe (fd)) {
   184 		scr_LogPrint (LPRINT_LOGNORM, "Cannot create pipe: %s", strerror (errno));
   209 		scr_LogPrint (LPRINT_LOGNORM, "Cannot create pipe: %s.", strerror (errno));
   185 		return;
   210 		return;
   186 	}
   211 	}
   187 
   212 
   188 	{
   213 	{
   189 		int res = fork ();
   214 		GIOChannel *channel;
       
   215 		int         res     = fork ();
   190 
   216 
   191 		if (!res) {
   217 		if (!res) {
   192 			
   218 			
   193 			close (fd[0]);
   219 			close (fd[0]);
   194 			dup2 (fd[1], STDOUT_FILENO);
   220 			dup2 (fd[1], STDOUT_FILENO);
   208 				execl (shell, shell, "-c", arg, NULL);
   234 				execl (shell, shell, "-c", arg, NULL);
   209 			}
   235 			}
   210 		}
   236 		}
   211 
   237 
   212 		if (res == -1) {
   238 		if (res == -1) {
   213 			scr_LogPrint (LPRINT_NORMAL, "Cannot fork child: %s", strerror (errno));
   239 			scr_LogPrint (LPRINT_NORMAL, "Cannot fork child: %s.", strerror (errno));
   214 			close (fd[0]);
   240 			close (fd[0]);
   215 			close (fd[1]);
   241 			close (fd[1]);
   216 			return;
   242 			return;
   217 		}
   243 		}
   218 
   244 
   219 		close (fd[1]);
   245 		close (fd[1]);
   220 
   246 
   221 		GIOChannel *channel = g_io_channel_unix_new (fd[0]);
   247 		{
   222 
   248 			GError *error = NULL;
   223 		g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL);
   249 
   224 		g_io_channel_set_encoding (channel, NULL, NULL);
   250 			channel = g_io_channel_unix_new (fd[0]);
   225 		g_io_channel_set_close_on_unref (channel, TRUE);
   251 
   226 		g_io_channel_set_buffered (channel, FALSE);
   252 			g_io_channel_set_encoding (channel, NULL, &error);
       
   253 			if (error) {
       
   254 				scr_LogPrint (LPRINT_DEBUG, "cmd: Cannot unset channel encoding: %s.", error -> message);
       
   255 				g_clear_error (&error);
       
   256 			}
       
   257 			g_io_channel_set_buffered (channel, FALSE);
       
   258 			g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, &error);
       
   259 			if (error) {
       
   260 				scr_LogPrint (LPRINT_DEBUG, "cmd: Cannot set nonblocking flag on channel: %s.", error -> message);
       
   261 				g_error_free (error);
       
   262 			}
       
   263 			g_io_channel_set_close_on_unref (channel, TRUE);
       
   264 		}
   227 
   265 
   228 		{
   266 		{
   229 			cmd_cb_t *cb = g_new (cmd_cb_t, 1);
   267 			cmd_cb_t *cb = g_new (cmd_cb_t, 1);
   230 
   268 
   231 			cb->jid     = g_strdup (jid);
   269 			if (settings_opt_get_int ("cmd_header")) {
   232 			cb->input   = g_string_new (NULL);
   270 				if (is_room (jid)) {
   233 			cb->channel = channel;
   271 					gchar *mesg = g_strdup_printf ("$ %s", arg);
   234 			cb->source  = g_io_add_watch_full (channel, 0, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
   272 					gchar *utf  = to_utf8 (mesg);
   235 		                                   cmd_reader, (gpointer) cb, cmd_destroy_data);
   273 					g_free (mesg);
       
   274 					cmd_send_msg (jid, NULL, utf);
       
   275 					g_free (utf);
       
   276 					cb -> subject = NULL;
       
   277 				} else {
       
   278 					gchar *header = g_strdup_printf ("[%%02d] $ %s", arg);
       
   279 					cb -> subject = to_utf8 (header);
       
   280 					g_free (header);
       
   281 				}
       
   282 			}
       
   283 
       
   284 			cb -> jid     = g_strdup (jid);
       
   285 			cb -> input   = g_string_new (NULL);
       
   286 			cb -> seq     = 0;
       
   287 			cb -> channel = channel;
       
   288 			cb -> source  = g_io_add_watch_full (channel, 0, G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
       
   289 			                                     cmd_reader, (gpointer) cb, cmd_destroy_data);
   236 
   290 
   237 			cmd_channels = g_slist_append (cmd_channels, cb);
   291 			cmd_channels = g_slist_append (cmd_channels, cb);
   238 		}
   292 		}
   239 	}
   293 	}
   240 }
   294 }