/****************************************************************************** * TinTin++ * * Copyright (C) 2004 (See CREDITS file) * * * * This program is protected under the GNU GPL (See COPYING) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *******************************************************************************/ /****************************************************************************** * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t * * * * coded by Igor van den Hoven 1996 * ******************************************************************************/ #include "tintin.h" #include <sys/types.h> #include <sys/time.h> #include <termios.h> #include <errno.h> void mainloop(void) { static struct timeval curr_time, wait_time, last_time; int usec_loop, usec_wait; short int pulse_poll_input = 0 + PULSE_POLL_INPUT; short int pulse_poll_sessions = 0 + PULSE_POLL_SESSIONS; short int pulse_poll_chat = 0 + PULSE_POLL_CHAT; short int pulse_update_ticks = 0 + PULSE_UPDATE_TICKS; short int pulse_update_delays = 0 + PULSE_UPDATE_DELAYS; short int pulse_update_packets = 0 + PULSE_UPDATE_PACKETS; short int pulse_update_chat = 0 + PULSE_UPDATE_CHAT; short int pulse_update_terminal = 0 + PULSE_UPDATE_TERMINAL; short int pulse_update_memory = 0 + PULSE_UPDATE_MEMORY; short int pulse_update_time = 1 + PULSE_UPDATE_TIME; wait_time.tv_sec = 0; while (TRUE) { gettimeofday(&last_time, NULL); if (--pulse_poll_input == 0) { open_timer(TIMER_POLL_INPUT); pulse_poll_input = PULSE_POLL_INPUT; poll_input(); close_timer(TIMER_POLL_INPUT); } if (--pulse_poll_sessions == 0) { pulse_poll_sessions = PULSE_POLL_SESSIONS; poll_sessions(); } if (--pulse_poll_chat == 0) { pulse_poll_chat = PULSE_POLL_CHAT; poll_chat(); } if (--pulse_update_ticks == 0) { pulse_update_ticks = PULSE_UPDATE_TICKS; tick_update(); } if (--pulse_update_delays == 0) { pulse_update_delays = PULSE_UPDATE_DELAYS; delay_update(); } if (--pulse_update_packets == 0) { pulse_update_packets = PULSE_UPDATE_PACKETS; packet_update(); } if (--pulse_update_chat == 0) { pulse_update_chat = PULSE_UPDATE_CHAT; chat_update(); } if (--pulse_update_terminal == 0) { pulse_update_terminal = PULSE_UPDATE_TERMINAL; terminal_update(); } if (--pulse_update_memory == 0) { pulse_update_memory = PULSE_UPDATE_MEMORY; memory_update(); } if (--pulse_update_time == 0) { pulse_update_time = PULSE_UPDATE_TIME; time_update(); } gettimeofday(&curr_time, NULL); if (curr_time.tv_sec == last_time.tv_sec) { usec_loop = curr_time.tv_usec - last_time.tv_usec; } else { usec_loop = 1000000 - last_time.tv_usec + curr_time.tv_usec; } usec_wait = 1000000 / PULSE_PER_SECOND - usec_loop; wait_time.tv_usec = usec_wait; gtd->total_io_exec += usec_loop; gtd->total_io_delay += usec_wait; if (usec_wait > 0) { select(0, NULL, NULL, NULL, &wait_time); } } } void poll_input(void) { fd_set readfds; static struct timeval to; while (TRUE) { FD_ZERO(&readfds); FD_SET(0, &readfds); if (select(FD_SETSIZE, &readfds, NULL, NULL, &to) <= 0) { return; } if (FD_ISSET(0, &readfds)) { process_input(); } else { return; } } } void poll_sessions(void) { fd_set readfds, excfds; static struct timeval to; struct session *ses; int rv; open_timer(TIMER_POLL_SESSIONS); if (gts->next) { FD_ZERO(&readfds); FD_ZERO(&excfds); for (ses = gts->next ; ses ; ses = gtd->update) { gtd->update = ses->next; if (HAS_BIT(ses->flags, SES_FLAG_CONNECTED)) { while (TRUE) { FD_SET(ses->socket, &readfds); FD_SET(ses->socket, &excfds); rv = select(FD_SETSIZE, &readfds, NULL, &excfds, &to); if (rv <= 0) { break; } if (FD_ISSET(ses->socket, &readfds)) { if (read_buffer_mud(ses) == FALSE) { readmud(ses); cleanup_session(ses); gtd->mud_output_len = 0; break; } } if (FD_ISSET(ses->socket, &excfds)) { FD_CLR(ses->socket, &readfds); cleanup_session(ses); gtd->mud_output_len = 0; break; } } if (gtd->mud_output_len) { readmud(ses); } } } } close_timer(TIMER_POLL_SESSIONS); } void poll_chat(void) { fd_set readfds, writefds, excfds; static struct timeval to; struct chat_data *buddy; int rv; open_timer(TIMER_POLL_CHAT); if (gtd->chat) { FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&excfds); FD_SET(gtd->chat->fd, &readfds); for (buddy = gtd->chat->next ; buddy ; buddy = buddy->next) { FD_SET(buddy->fd, &readfds); FD_SET(buddy->fd, &writefds); FD_SET(buddy->fd, &excfds); } rv = select(FD_SETSIZE, &readfds, &writefds, &excfds, &to); if (rv <= 0) { if (rv == 0 || errno == EINTR) { return; } syserr("select"); } process_chat_connections(&readfds, &writefds, &excfds); } close_timer(TIMER_POLL_CHAT); } void tick_update(void) { struct session *ses; struct listnode *node; struct listroot *root; open_timer(TIMER_UPDATE_TICKS); utime(); for (ses = gts->next ; ses ; ses = gtd->update) { gtd->update = ses->next; root = ses->list[LIST_TICKER]; for (root->update = 0 ; root->update < root->used ; root->update++) { node = root->list[root->update]; if (node->data == 0) { node->data = gtd->time + (long long) (get_number(ses, node->pr) * 1000000LL); } if (node->data <= gtd->time) { node->data += (long long) (get_number(ses, node->pr) * 1000000LL); show_debug(ses, LIST_TICKER, "#DEBUG TICKER {%s}", node->right); script_driver(ses, LIST_TICKER, node->right); } } } close_timer(TIMER_UPDATE_TICKS); } void delay_update(void) { struct session *ses; struct listnode *node; struct listroot *root; char buf[BUFFER_SIZE]; open_timer(TIMER_UPDATE_DELAYS); for (ses = gts ; ses ; ses = gtd->update) { gtd->update = ses->next; root = ses->list[LIST_DELAY]; for (root->update = 0 ; root->update < root->used ; root->update++) { node = root->list[root->update]; if (node->data == 0) { node->data = gtd->time + (long long) (get_number(ses, node->pr) * 1000000LL); } if (node->data <= gtd->time) { strcpy(buf, node->right); show_debug(ses, LIST_DELAY, "#DEBUG DELAY {%s}", buf); delete_node_list(ses, LIST_DELAY, node); script_driver(ses, LIST_DELAY, buf); } } } close_timer(TIMER_UPDATE_DELAYS); } void packet_update(void) { char result[STRING_SIZE]; struct session *ses; open_timer(TIMER_UPDATE_PACKETS); for (ses = gts->next ; ses ; ses = gtd->update) { gtd->update = ses->next; if (ses->check_output && gtd->time > ses->check_output) { if (HAS_BIT(ses->flags, SES_FLAG_SPLIT)) { save_pos(ses); goto_rowcol(ses, ses->bot_row, 1); } SET_BIT(ses->flags, SES_FLAG_READMUD); strcpy(result, ses->more_output); ses->more_output[0] = 0; process_mud_output(ses, result, TRUE); DEL_BIT(ses->flags, SES_FLAG_READMUD); if (HAS_BIT(ses->flags, SES_FLAG_SPLIT)) { restore_pos(ses); } } } close_timer(TIMER_UPDATE_PACKETS); } void chat_update(void) { struct chat_data *buddy, *buddy_next; open_timer(TIMER_UPDATE_CHAT); if (gtd->chat) { for (buddy = gtd->chat->next ; buddy ; buddy = buddy_next) { buddy_next = buddy->next; if (buddy->timeout && buddy->timeout < time(NULL)) { chat_socket_printf(buddy, "<CHAT> Connection timed out."); close_chat(buddy, TRUE); } } if (gtd->chat->paste_time && gtd->chat->paste_time < utime()) { chat_paste(NULL, NULL); } } close_timer(TIMER_UPDATE_CHAT); } void terminal_update(void) { struct session *ses; open_timer(TIMER_UPDATE_TERMINAL); for (ses = gts ; ses ; ses = ses->next) { if (HAS_BIT(ses->flags, SES_FLAG_UPDATEVTMAP)) { DEL_BIT(ses->flags, SES_FLAG_UPDATEVTMAP); show_vtmap(ses); } } fflush(stdout); close_timer(TIMER_UPDATE_TERMINAL); } void memory_update(void) { open_timer(TIMER_UPDATE_MEMORY); while (gtd->dispose_next) { dispose_session(gtd->dispose_next); } close_timer(TIMER_UPDATE_MEMORY); } void time_update(void) { static char sec[3], min[3], hrs[3], day[3], wks[3], mon[3], yrs[5]; static char old_sec[3], old_min[3], old_hrs[3], old_day[3], old_wks[3], old_mon[3], old_yrs[5]; time_t timeval_t = (time_t) time(NULL); struct tm timeval_tm = *localtime(&timeval_t); open_timer(TIMER_UPDATE_TIME); // Initialize on the first call. if (old_sec[0] == 0) { strftime(old_sec, 3, "%S", &timeval_tm); strftime(old_min, 3, "%M", &timeval_tm); strftime(old_hrs, 3, "%H", &timeval_tm); strftime(old_day, 3, "%d", &timeval_tm); strftime(old_wks, 3, "%W", &timeval_tm); strftime(old_mon, 3, "%m", &timeval_tm); strftime(old_yrs, 5, "%Y", &timeval_tm); strftime(sec, 3, "%S", &timeval_tm); strftime(min, 3, "%M", &timeval_tm); strftime(hrs, 3, "%H", &timeval_tm); strftime(day, 3, "%d", &timeval_tm); strftime(wks, 3, "%W", &timeval_tm); strftime(mon, 3, "%m", &timeval_tm); strftime(yrs, 5, "%Y", &timeval_tm); } strftime(sec, 3, "%S", &timeval_tm); strftime(min, 3, "%M", &timeval_tm); if (min[0] == old_min[0] && min[1] == old_min[1]) { goto time_event_sec; } strcpy(old_min, min); strftime(hrs, 3, "%H", &timeval_tm); if (hrs[0] == old_hrs[0] && hrs[1] == old_hrs[1]) { goto time_event_min; } strcpy(old_hrs, hrs); strftime(day, 3, "%d", &timeval_tm); strftime(wks, 3, "%W", &timeval_tm); if (day[0] == old_day[0] && day[1] == old_day[1]) { goto time_event_hrs; } strcpy(old_day, day); strftime(mon, 3, "%m", &timeval_tm); if (mon[0] == old_mon[0] && mon[1] == old_mon[1]) { goto time_event_day; } strcpy(old_mon, mon); strftime(yrs, 5, "%Y", &timeval_tm); if (yrs[0] == old_yrs[0] && yrs[1] == old_yrs[1] && yrs[2] == old_yrs[2] && yrs[3] == old_yrs[3]) { goto time_event_mon; } strcpy(old_yrs, yrs); check_all_events(NULL, 0, 7, "YEAR", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "YEAR %s", yrs, yrs, mon, wks, day, hrs, min, sec); time_event_mon: check_all_events(NULL, 0, 7, "MONTH", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "MONTH %s", mon, yrs, mon, wks, day, hrs, min, sec); time_event_day: if (wks[0] != old_wks[0] || wks[1] != old_wks[1]) { strcpy(old_wks, wks); check_all_events(NULL, 0, 7, "WEEK", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "WEEK %s", wks, yrs, mon, wks, day, hrs, min, sec); } check_all_events(NULL, 2, 7, "DATE %s-%s", mon, day, yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 0, 7, "DAY", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "DAY %s", day, yrs, mon, wks, day, hrs, min, sec); time_event_hrs: check_all_events(NULL, 0, 7, "HOUR", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "HOUR %s", hrs, yrs, mon, wks, day, hrs, min, sec); time_event_min: check_all_events(NULL, 4, 7, "DATE %s-%s %s:%s", mon, day, hrs, min, yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 2, 7, "TIME %s:%s", hrs, min, yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 0, 7, "MINUTE", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "MINUTE %s", min, yrs, mon, wks, day, hrs, min, sec); time_event_sec: check_all_events(NULL, 3, 7, "TIME %s:%s:%s", hrs, min, sec, yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 0, 7, "SECOND", yrs, mon, wks, day, hrs, min, sec); check_all_events(NULL, 1, 7, "SECOND %s", sec, yrs, mon, wks, day, hrs, min, sec); close_timer(TIMER_UPDATE_TIME); }