/* Monolith chat window. * - by Richard W.M. Jones * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ml_chat_window.c,v 1.9 2003/02/22 15:34:28 rich Exp $ */ #include "config.h" #include #include #ifdef HAVE_ASSERT_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_ALLOCA_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "messages_pane.h" #include "users_pane.h" #include "chatroom.h" #include "ml_chat_window.h" #define MAX_POSTING_LENGTH 320 struct data { pool pool; /* Pool for allocations. */ ml_session session; /* Session. */ const char *conninfo; /* Database connection. */ int resid; /* Resource ID of the chatroom. */ const char *resname; /* Name of the chatroom. */ chatroom room; /* Chatroom object. */ ml_form_text posted; /* Current posted message. */ }; static void create_top_frameset (ml_session session, void *vdata); static void create_messages_frame (ml_session session, void *vdata); static void create_users_frame (ml_session session, void *vdata); static void create_input_frame (ml_session session, void *vdata); static void post_message (ml_session session, void *vdata); void ml_chat_window (ml_session session, void *vargs) { struct ml_chat_window_args *args = (struct ml_chat_window_args *) vargs; pool pool = ml_session_pool (session); struct data *data; db_handle dbh; st_handle sth; ml_window win; vector frames; struct ml_frame_description frame; /* Initialise our own data structure. */ data = pmalloc (pool, sizeof *data); data->pool = pool; data->session = session; data->conninfo = args->conninfo; data->resname = pstrdup (pool, args->resname); /* Fetch the resource ID from the database. */ dbh = get_db_handle (args->conninfo, DBI_THROW_ERRORS); sth = st_prepare_cached (dbh, "select resid from ml_resources where name = ?", DBI_STRING); st_execute (sth, args->resname); st_bind (sth, 0, data->resid, DBI_INT); if (!st_fetch (sth)) { ml_error_window (pool, session, "That chat room could not be found.", ML_DIALOG_CLOSE_BUTTON); } /* Get the corresponding chatroom object. */ data->room = get_chatroom (dbh, data->resid); put_db_handle (dbh); /* Create the top-level frameset. */ frames = new_vector (pool, struct ml_frame_description); frame.data = data; frame.fn = create_top_frameset; vector_push_back (frames, frame); frame.fn = create_input_frame; vector_push_back (frames, frame); win = new_ml_frameset (session, pool, "92%,8%", "*", frames); } static void create_top_frameset (ml_session session, void *vdata) { struct data *data = (struct data *) vdata; pool pool = data->pool; ml_window win; vector frames; struct ml_frame_description frame; /* Create the top frameset, showing the messages on the left and the * users on the right. */ frames = new_vector (pool, struct ml_frame_description); frame.data = vdata; frame.fn = create_messages_frame; vector_push_back (frames, frame); frame.fn = create_users_frame; vector_push_back (frames, frame); win = new_ml_frameset (session, pool, "*", "80%,20%", frames); } static void create_messages_frame (ml_session session, void *vdata) { struct data *data = (struct data *) vdata; pool pool = data->pool; ml_window win; messages_pane messages_pane; win = new_ml_window (session, pool); messages_pane = new_messages_pane (pool, session, data->conninfo, data->room); ml_window_pack (win, messages_pane); } static void create_users_frame (ml_session session, void *vdata) { struct data *data = (struct data *) vdata; pool pool = data->pool; ml_window win; users_pane users_pane; const char *ua; int ie_bug_workaround; win = new_ml_window (session, pool); /* IE 4 and above has a serious bug: it cannot handle two or more * frames in the same frameset which are continuously loading. Sniff * for IE here and invoke the bug workaround instead. */ ua = ml_session_user_agent (session); ie_bug_workaround = ua && strstr (ua, "MSIE") != 0; ml_window_set_refresh (win, ie_bug_workaround ? 60 : 600); users_pane = new_users_pane (pool, session, data->conninfo, data->room, ie_bug_workaround); ml_window_pack (win, users_pane); } static void create_input_frame (ml_session session, void *vdata) { struct data *data = (struct data *) vdata; pool pool = data->pool; ml_window win; ml_form form; win = new_ml_window (session, pool); /* Create the simple form which users will use to post. There's just * an input widget, which browsers will submit when the user presses * the [Return] key. */ form = new_ml_form (pool); ml_form_set_callback (form, post_message, session, data); ml_widget_set_property (form, "method", "GET"); data->posted = new_ml_form_text (pool, form); ml_form_text_focus (data->posted); ml_widget_set_property (data->posted, "form.text.size", 55); ml_widget_set_property (data->posted, "form.text.maxlength", MAX_POSTING_LENGTH); ml_form_pack (form, data->posted); ml_window_pack (win, form); } static void post_message (ml_session session, void *vdata) { struct data *data = (struct data *) vdata; //pool pool = data->pool; const char *_posted_text; char *text; _posted_text = ml_form_input_get_value (data->posted); /* Clear message box. */ ml_form_input_set_value (data->posted, ""); /* Ignore empty strings. */ if (!_posted_text || strlen (_posted_text) == 0) return; /* Copy the string onto the stack, since we are going to trim it * and so on. This is also good discipline, because we *must* * duplicate the string into a safer pool for long-term storage. * By copying it onto the stack, we'll catch mistakes easily. */ text = alloca (strlen (_posted_text) + 1); strcpy (text, _posted_text); /* Ignore empty strings (#2). */ ptrim (text); if (strlen (text) == 0) return; /* Truncate the posted text at the maximum posting length. */ if (strlen (text) > MAX_POSTING_LENGTH) text[MAX_POSTING_LENGTH] = '\0'; /* Insert it into the chatroom & database. */ chatroom_post (data->room, session, data->conninfo, text); }