📄 xchat.c
字号:
/* X-Chat * Copyright (C) 1998 Peter Zelezny. * * 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 */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <time.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#define WANTSOCKET#include "inet.h"#ifndef WIN32#include <sys/wait.h>#include <signal.h>#endif#include "xchat.h"#include "fe.h"#include "util.h"#include "cfgfiles.h"#include "ignore.h"#include "plugin.h"#include "notify.h"#include "server.h"#include "pythonc.h"#include "outbound.h"#include "text.h"#include "perlc.h"#include "xchatc.h"#ifdef USE_OPENSSL#include <openssl/ssl.h> /* SSL_() */#include "ssl.h"#endif#ifdef USE_JCODE#include "jcode.h"#endifGSList *popup_list = 0;GSList *button_list = 0;GSList *dlgbutton_list = 0;GSList *command_list = 0;GSList *ctcp_list = 0;GSList *replace_list = 0;GSList *sess_list = 0;GSList *serv_list = 0;GSList *dcc_list = 0;GSList *ignore_list = 0;GSList *usermenu_list = 0;GSList *urlhandler_list = 0;static GSList *away_list = 0;static int in_xchat_exit = FALSE;int xchat_is_quitting = FALSE;int auto_connect = TRUE;struct session *current_tab;struct session *menu_sess = 0;struct xchatprefs prefs;#ifdef USE_OPENSSLSSL_CTX *ctx = NULL;void ssl_cb_info (SSL * s, int where, int ret);#endifstatic void free_away_messages (server *serv);/* actually send to the socket. This might do a character translation or send via SSL */static inttcp_send_real (struct server *serv, char *buf, int len){ int ret = 1; unsigned char *tbuf = buf;#ifdef USE_TRANS#define TRANS_STAT_BUF_LEN 1024 static unsigned char sbuf[TRANS_STAT_BUF_LEN]; if (prefs.use_trans) { if (len >= TRANS_STAT_BUF_LEN) tbuf = malloc (len + 1); else tbuf = sbuf; if (!tbuf) return -1; strcpy (tbuf, buf); user2serv (tbuf); }#endif fe_add_rawlog (serv, tbuf, TRUE); if (!EMIT_SIGNAL (XP_IF_SEND, (void *) serv->sok, tbuf, (void *)len, NULL, NULL, 0)) {#ifdef USE_OPENSSL if (!serv->ssl) ret = send (serv->sok, tbuf, len, 0); else ret = _SSL_send (serv->ssl, tbuf, len);#else ret = send (serv->sok, tbuf, len, 0);#endif }#ifdef USE_TRANS if (prefs.use_trans) { if (tbuf != sbuf) free (tbuf); }#endif return ret;}/* new throttling system, uses the same method as the Undernet ircu2.10 server; under test, a 200-line paste didn't flood off the client */static inttcp_send_queue (struct server *serv){ char *buf, *p; int len, i; GSList *list; time_t now = time (0); /* did the server close since the timeout was added? */ if (!is_server (serv)) return 0; list = serv->outbound_queue; while (list) { buf = (char *) list->data; len = strlen (buf); if (serv->next_send < now) serv->next_send = now; if (serv->next_send - now >= 10) return 1; /* don't remove the timeout handler */ for (p = buf, i = len; i && *p != ' '; p++, i--); serv->next_send += (2 + i / 120); serv->sendq_len -= len; fe_set_throttle (serv); tcp_send_real (serv, buf, len); serv->outbound_queue = g_slist_remove (serv->outbound_queue, buf); free (buf); list = serv->outbound_queue; } return 0; /* remove the timeout handler */}#ifdef USE_JCODEstatic voidfe_add_ja_rawlog (struct server *serv, char *buf, int outbound){ char *jbuf = kanji_conv_to_locale(buf); if (jbuf) { fe_add_rawlog (serv, jbuf, TRUE); free(jbuf); } else fe_add_rawlog (serv, buf, TRUE);}#endifinttcp_send_len (struct server *serv, char *buf, int len){ char *dbuf; int noqueue = !serv->outbound_queue;#ifdef USE_JCODE unsigned char *jbuf = NULL; if ( prefs.kanji_conv ) { jbuf = kanji_conv_auto(buf, "ISO-2022-JP"); if (!jbuf) return 0; else { buf = strdup(jbuf); free(jbuf); len = strlen(buf); } } else buf = strdup(buf); /* freed after all */#endif if (!prefs.throttle) return tcp_send_real (serv, buf, len); dbuf = malloc (len + 1); memcpy (dbuf, buf, len); dbuf[len] = 0; /* only privmsg and notice go to the back of the queue */ if (strncasecmp (dbuf, "PRIVMSG", 7) == 0 || strncasecmp (dbuf, "NOTICE", 6) == 0) serv->outbound_queue = g_slist_append (serv->outbound_queue, dbuf); else serv->outbound_queue = g_slist_prepend (serv->outbound_queue, dbuf); serv->sendq_len += len; /* tcp_send_queue uses strlen */ if (tcp_send_queue (serv) && noqueue) fe_timeout_add (500, tcp_send_queue, serv); return 1;}inttcp_send (struct server *serv, char *buf){ return tcp_send_len (serv, buf, strlen (buf));}static intis_in_list (GSList *list, void *data){ while (list) { if (list->data == data) return TRUE; list = list->next; } return FALSE;}intis_server (server * serv){ return is_in_list (serv_list, serv);}intis_session (session * sess){ return is_in_list (sess_list, sess);}struct session *find_dialog (struct server *serv, char *nick){ GSList *list = sess_list; struct session *sess; while (list) { sess = (struct session *) list->data; if (sess->server == serv && sess->type == SESS_DIALOG) { if (!strcasecmp (nick, sess->channel)) return (sess); } list = list->next; } return 0;}session *find_session_from_channel (char *chan, server *serv){ session *sess; GSList *list = sess_list; while (list) { sess = list->data; if (sess->type != SESS_SHELL && !strcasecmp (chan, sess->channel)) { if (!serv || serv == sess->server) return sess; } list = list->next; } return 0;}#ifndef WIN32static intmail_items (char *file){ FILE *fp; int items; char buf[512]; fp = fopen (file, "r"); if (!fp) return 1; items = 0; while (fgets (buf, sizeof buf, fp)) { if (!strncmp (buf, "From ", 5)) items++; } fclose (fp); return items;}static voidxchat_mail_check (void){ static int last_size = -1; int size; struct stat st; char buf[512]; char *maildir; maildir = getenv ("MAIL"); if (!maildir) { snprintf (buf, sizeof (buf), "/var/spool/mail/%s", g_get_user_name ()); maildir = buf; } if (stat (maildir, &st) < 0) return; size = st.st_size; if (last_size == -1) { last_size = size; return; } if (size > last_size) { sprintf (buf, "%d", mail_items (maildir)); sprintf (buf + 16, "%d", size); if (menu_sess && menu_sess->type != SESS_SHELL) EMIT_SIGNAL (XP_TE_NEWMAIL, menu_sess, buf, buf + 16, NULL, NULL, 0); } last_size = size;}#endifstatic intlagcheck_update (void){ server *serv; GSList *list = serv_list; if (!prefs.lagometer) return 1; while (list) { serv = list->data; if (serv->lag_sent) fe_set_lag (serv, -1); list = list->next; } return 1;}voidlag_check (void){ server *serv; GSList *list = serv_list; unsigned long tim; char tbuf[256]; time_t now = time (0); int lag; tim = make_ping_time (); while (list) { serv = list->data; if (serv->connected && serv->end_of_motd) { lag = now - serv->ping_recv; if (prefs.pingtimeout && lag > prefs.pingtimeout && lag > 0) { sprintf (tbuf, "%d", lag); EMIT_SIGNAL (XP_TE_PINGTIMEOUT, serv->front_session, tbuf, NULL, NULL, NULL, 0); auto_reconnect (serv, FALSE, -1); } else { /*sprintf (tbuf, "PING LAG%lu :%s\r\n", tim, serv->servername);*/ sprintf (tbuf, "PING LAG%lu\r\n", tim); tcp_send (serv, tbuf); serv->lag_sent = tim; fe_set_lag (serv, -1); } } list = list->next; }}static intxchat_misc_checks (void) /* this gets called every 2 seconds */{ static int count = 0; dcc_check_timeouts (); count++; if (count == 7 && prefs.lagometer) /* every 30 seconds */ lag_check (); if (count == 15) /* every 30 seconds */ { count = 0;#ifndef WIN32 if (prefs.mail_check) xchat_mail_check ();#endif } return 1;}/* executed when the first irc window opens */static voidirc_init (session *sess){ static int done_init = FALSE; if (done_init) return; done_init = TRUE;#ifdef USE_PYTHON pys_init ();#endif#ifdef USE_PLUGIN module_setup ();#endif#ifdef USE_PERL perl_auto_load (sess);#endif if (prefs.notify_timeout) notify_tag = fe_timeout_add (prefs.notify_timeout * 1000, notify_checklist, 0); fe_timeout_add (2000, xchat_misc_checks, 0); fe_timeout_add (500, lagcheck_update, 0);}static session *new_session (server *serv, char *from, int type){ session *sess; sess = malloc (sizeof (struct session)); memset (sess, 0, sizeof (struct session)); sess->server = serv; sess->logfd = -1; sess->type = type; sess->current_modes = strdup (""); if (from != NULL) safe_strcpy (sess->channel, from, CHANLEN); sess_list = g_slist_prepend (sess_list, sess); fe_new_window (sess); return sess;}voidset_server_defaults (server *serv){ if (serv->chantypes) free (serv->chantypes); if (serv->chanmodes) free (serv->chanmodes); if (serv->nick_prefixes) free (serv->nick_prefixes); if (serv->nick_modes) free (serv->nick_modes); serv->chantypes = strdup ("#&!+"); serv->chanmodes = strdup ("beI,k,l"); serv->nick_prefixes = strdup ("@%+"); serv->nick_modes = strdup ("ohv"); serv->nickcount = 1; serv->end_of_motd = FALSE; serv->is_away = FALSE; serv->supports_watch = FALSE; serv->bad_prefix = FALSE;}static server *new_server (void){ server *serv; serv = malloc (sizeof (struct server)); memset (serv, 0, sizeof (struct server)); serv->sok = -1; strcpy (serv->nick, prefs.nick1); set_server_defaults (serv); serv_list = g_slist_prepend (serv_list, serv); fe_new_server (serv); return serv;}session *new_ircwindow (server *serv, char *name, int type){ session *sess; switch (type) { case SESS_SHELL: sess = new_session (new_server (), name, SESS_SHELL); break; case SESS_SERVER: serv = new_server (); if (prefs.use_server_tab) { register unsigned int oldh = prefs.hideuserlist; prefs.hideuserlist = 1; sess = new_session (serv, name, SESS_SERVER); prefs.hideuserlist = oldh; serv->front_session = sess; } else { sess = new_session (serv, name, SESS_CHANNEL); } break; default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -