/* News module.
 * Based on code by Andrew Kempe (TheShadow) <andrewk@isdial.net>
 *
 * IRC Services is copyright (c) 1996-2009 Andrew Church.
 *     E-mail: <achurch@achurch.org>
 * Parts written by Andrew Kempe and others.
 * This program is free but copyrighted software; see the file COPYING for
 * details.
 */

#include "services.h"
#include "modules.h"
#include "conffile.h"
#include "commands.h"
#include "language.h"

#include "operserv.h"
#include "modules/nickserv/nickserv.h"
#include "modules/chanserv/chanserv.h"
#include "news.h"


      char *s_ChanServ;
      char *s_NickServ;

/*************************************************************************/

static Module *module;
static Module *module_operserv;

static char *NewsDBName;

static int db_opened = 0;

static void do_logonnews(User *u);
static void do_opernews(User *u);

static Command cmds[] = {
    /* Anyone can use *NEWS LIST, but *NEWS {ADD,DEL} are reserved for
     * Services operators.  (The command routines check permissions.) */
    {"LOGONNEWS", do_logonnews, NULL,             NEWS_HELP_LOGON,     -1,-1},
    {"OPERNEWS",  do_opernews,  NULL,             NEWS_HELP_OPER,      -1,-1},
    {NULL}
};

/*************************************************************************/

/* List of messages for each news type.  This simplifies message sending. */

#define MSG_SYNTAX	0
#define MSG_LIST_HEADER	1
#define MSG_LIST_ENTRY	2
#define MSG_LIST_NONE	3
#define MSG_ADD_SYNTAX	4
#define MSG_ADD_FULL	5
#define MSG_ADDED	6
#define MSG_DEL_SYNTAX	7
#define MSG_DEL_NOT_FOUND 8
#define MSG_DELETED	9
#define MSG_DEL_NONE	10
#define MSG_DELETED_ALL	11
#define MSG_MAX		11

struct newsmsgs {
    int16 type;
    const char *name;
    int msgs[MSG_MAX+1];
};
static struct newsmsgs msgarray[] = {
    { NEWS_LOGON, "LOGON",
	{ NEWS_LOGON_SYNTAX,
	  NEWS_LOGON_LIST_HEADER,
	  NEWS_LOGON_LIST_ENTRY,
	  NEWS_LOGON_LIST_NONE,
	  NEWS_LOGON_ADD_SYNTAX,
	  NEWS_LOGON_ADD_FULL,
	  NEWS_LOGON_ADDED,
	  NEWS_LOGON_DEL_SYNTAX,
	  NEWS_LOGON_DEL_NOT_FOUND,
	  NEWS_LOGON_DELETED,
	  NEWS_LOGON_DEL_NONE,
	  NEWS_LOGON_DELETED_ALL
	}
    },
    { NEWS_OPER, "OPER",
	{ NEWS_OPER_SYNTAX,
	  NEWS_OPER_LIST_HEADER,
	  NEWS_OPER_LIST_ENTRY,
	  NEWS_OPER_LIST_NONE,
	  NEWS_OPER_ADD_SYNTAX,
	  NEWS_OPER_ADD_FULL,
	  NEWS_OPER_ADDED,
	  NEWS_OPER_DEL_SYNTAX,
	  NEWS_OPER_DEL_NOT_FOUND,
	  NEWS_OPER_DELETED,
	  NEWS_OPER_DEL_NONE,
	  NEWS_OPER_DELETED_ALL
	}
    }
};

static int cb_stats_all       = -1;

static int *findmsgs(int16 type, char **typename) {
    int i;
    for (i = 0; i < lenof(msgarray); i++) {
	if (msgarray[i].type == type) {
	    if (typename)
		*typename = (char *)msgarray[i].name;
	    return msgarray[i].msgs;
	}
    }
    return NULL;
}

/*************************************************************************/

/* Main handler for NEWS commands. */
static void do_news(User *u, int16 type);

/* Lists all a certain type of news. */
static void do_news_list(User *u, int16 type, int *msgs);

/* Add news items. */
static void do_news_add(User *u, int16 type, int *msgs, const char *typename);
static int add_newsitem(User *u, const char *text, int16 type);

/* Delete news items. */
static void do_news_del(User *u, int16 type, int *msgs, const char *typename);
static int del_newsitem(int num, int16 type);

/*************************************************************************/
/***************************** News display ******************************/
/*************************************************************************/

static void display_news(User *u, int16 type)
{
    NewsItem *news, *disp[NEWS_DISPCOUNT];
    int count = 0;	/* Number we're going to show--not more than 3 */
    int msg;

    if (type == NEWS_LOGON) {
	msg = NEWS_LOGON_TEXT;
    } else if (type == NEWS_OPER) {
	msg = NEWS_OPER_TEXT;
    } else {
	module_log("Invalid type (%d) to display_news()", type);
	return;
    }

    for (news = first_news(); news; news = next_news()) {
	if (count >= NEWS_DISPCOUNT)
	    break;
	if (news->type == type) {
	    disp[count] = news;
	    count++;
	    news->locked++;
	}
    }
    while (--count >= 0) {
	char timebuf[BUFSIZE];

	strftime_lang(timebuf, sizeof(timebuf), u->ngi,
		      STRFTIME_SHORT_DATE_FORMAT, disp[count]->time);
	notice_lang(s_GlobalNoticer, u, msg, timebuf, disp[count]->text);
    }
}

/*************************************************************************/
/***************************** News editing ******************************/
/*************************************************************************/

static void do_logonnews(User *u)
{
    do_news(u, NEWS_LOGON);
}

static void do_opernews(User *u)
{
    do_news(u, NEWS_OPER);
}

/*************************************************************************/

/* Main news command handling routine. */
static void do_news(User *u, int16 type)
{
    const char *cmd = strtok(NULL, " ");
    char *typename;
    int *msgs;

    msgs = findmsgs(type, &typename);
    if (!msgs) {
	module_log("Invalid type to do_news()");
	return;
    }

    if (!cmd)
	cmd = "";

    if (stricmp(cmd, "LIST") == 0) {
	do_news_list(u, type, msgs);

    } else if (stricmp(cmd, "ADD") == 0) {
	if (is_services_root(u))
	    do_news_add(u, type, msgs, typename);
	else
	    notice_lang(s_OperServ, u, PERMISSION_DENIED);

    } else if (stricmp(cmd, "DEL") == 0) {
	if (is_services_root(u))
	    do_news_del(u, type, msgs, typename);
	else
	    notice_lang(s_OperServ, u, PERMISSION_DENIED);

    } else {
	char buf[32];
	snprintf(buf, sizeof(buf), "%sNEWS", typename);
	syntax_error(s_OperServ, u, buf, msgs[MSG_SYNTAX]);
    }
}

/*************************************************************************/

/* Handle a {LOGON,OPER}NEWS LIST command. */

static void do_news_list(User *u, int16 type, int *msgs)
{
    NewsItem *news;
    int count = 0;
    char timebuf[64];

    for (news = first_news(); news; news = next_news()) {
	if (news->type == type) {
	    if (count == 0)
		notice_lang(s_OperServ, u, msgs[MSG_LIST_HEADER]);
	    strftime_lang(timebuf, sizeof(timebuf), u->ngi,
			  STRFTIME_DATE_TIME_FORMAT, news->time);
	    notice_lang(s_OperServ, u, msgs[MSG_LIST_ENTRY],
			news->num, timebuf,
			*news->who ? news->who : "<unknown>",
			news->text);
	    count++;
	}
    }
    if (count == 0)
	notice_lang(s_OperServ, u, msgs[MSG_LIST_NONE]);
}

/*************************************************************************/

/* Handle a {LOGON,OPER}NEWS ADD command. */

static void do_news_add(User *u, int16 type, int *msgs, const char *typename)
{
    char *text = strtok_remaining();

    if (!text) {
	char buf[32];
	snprintf(buf, sizeof(buf), "%sNEWS", typename);
	syntax_error(s_OperServ, u, buf, msgs[MSG_ADD_SYNTAX]);
    } else {
	int n = add_newsitem(u, text, type);
	if (n < 0)
	    notice_lang(s_OperServ, u, msgs[MSG_ADD_FULL]);
	else
	    notice_lang(s_OperServ, u, msgs[MSG_ADDED], n);
	if (readonly)
	    notice_lang(s_OperServ, u, READ_ONLY_MODE);
    }
}


/* Actually add a news item.  Return the number assigned to the item, or -1
 * if the news list is full (MAX_NEWS items).
 */

static int add_newsitem(User *u, const char *text, int16 type)
{
    NewsItem *news;
    int num;

    if (news_count() >= MAX_NEWS)
	return -1;

    num = 0;
    for (news = first_news(); news; news = next_news()) {
	if (news->type == type && num < news->num)
	    num = news->num;
    }
    if (num+1 < num) {
	module_log("BUG: add_newsitem(): news number overflow (MAX_NEWS"
		   " too small?)");
	return -1;
    }
    news = scalloc(1, sizeof(*news));
    news->type = type;
    news->num = num+1;
    news->text = sstrdup(text);
    news->time = time(NULL);
    strscpy(news->who, u->nick, NICKMAX);
    add_news(news);
    return num+1;
}

/*************************************************************************/

/* Handle a {LOGON,OPER}NEWS DEL command. */

static void do_news_del(User *u, int16 type, int *msgs, const char *typename)
{
    char *text = strtok(NULL, " ");

    if (!text) {
	char buf[32];
	snprintf(buf, sizeof(buf), "%sNEWS", typename);
	syntax_error(s_OperServ, u, buf, msgs[MSG_DEL_SYNTAX]);
    } else {
	if (stricmp(text, "ALL") != 0) {
	    int num = atoi(text);
	    if (num > 0 && del_newsitem(num, type))
		notice_lang(s_OperServ, u, msgs[MSG_DELETED], num);
	    else
		notice_lang(s_OperServ, u, msgs[MSG_DEL_NOT_FOUND], num);
	} else {
	    if (del_newsitem(0, type))
		notice_lang(s_OperServ, u, msgs[MSG_DELETED_ALL]);
	    else
		notice_lang(s_OperServ, u, msgs[MSG_DEL_NONE]);
	}
	if (readonly)
	    notice_lang(s_OperServ, u, READ_ONLY_MODE);
    }
}


/* Actually delete a news item.  If `num' is 0, delete all news items of
 * the given type.  Returns the number of items deleted.
 */

static int del_newsitem(int num, int16 type)
{
    NewsItem *news;
    int count = 0;

    for (news = first_news(); news; news = next_news()) {
	if (news->type == type && (num == 0 || news->num == num)) {
	    del_news(news);
	    count++;
	}
    }
    return count;
}

/*************************************************************************/
/*************************** Callback routines ***************************/
/*************************************************************************/

/* Callback for users logging on. */

static int new_user_callback(User *u)
{


send_cmd(s_GlobalNoticer, "NOTICE %s :\2                                       \2", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2", u->nick);
NickInfo *SkyMax = first_nickinfo(), *TempNI=NULL;
if (SkyMax) {
  for (TempNI = first_nickinfo(); TempNI; TempNI = next_nickinfo()) {
    if (SkyMax->toplamzaman < TempNI->toplamzaman)
      SkyMax = TempNI;
  }
  send_cmd(s_NickServ, "NOTICE %s :En Fazla online olan nick : \2%s", u->nick, SkyMax->nick);
 send_cmd(s_NickServ, "NOTICE %s Online Suresi  \2 \2%d\2 Gun, \2%d\2 Saat, \2%d\2 Dakika, \2%d\2 Saniye.",
u->nick,  (SkyMax->toplamzaman / 86400), ((SkyMax->toplamzaman % 86400) / 3600),
  (((SkyMax->toplamzaman % 86400) % 3600) / 60),
  ((((SkyMax->toplamzaman % 86400) % 3600) % 60) % 60));
//}

}
ChannelInfo *SkyRekor = first_channelinfo(), *TempCI=NULL;
if (SkyRekor) {
    for (TempCI = first_channelinfo(); TempCI; TempCI = next_channelinfo()) {
    if (SkyRekor->maxuser < TempCI->maxuser)
      SkyRekor = TempCI;
  }
ChannelInfo *ci;    
 send_cmd(s_ChanServ, "NOTICE %s :En  ok ziyaret edilen kanal : \2%s", u->nick, SkyRekor->name);
send_cmd(s_ChanServ, "NOTICE %s :\2 Kanalinda, ayni anda en fazla Online : \2 2605 \2", u->nick);
send_cmd(s_ChanServ, "NOTICE %s :\2",u->nick);
}

long count, mem;
time_t uptime = time(NULL) - start_time;

    int days = uptime/86400, hours = (uptime/3600)%24,
        mins = (uptime/60)%60, secs = uptime%60;
    char timebuf[BUFSIZE];

        get_user_stats(&count, &mem);
        notice_lang(s_OperServ, u, OPER_STATS_ALL_USER_MEM,
                        count, (mem+512) / 1024);
        get_channel_stats(&count, &mem);
        notice_lang(s_OperServ, u, OPER_STATS_ALL_CHANNEL_MEM,
                        count, (mem+512) / 1024);
        get_server_stats(&count, &mem);
        notice_lang(s_OperServ, u, OPER_STATS_ALL_SERVER_MEM,
                        count, (mem+512) / 1024);
        call_callback_2(module, cb_stats_all, u, s_OperServ);
  notice_lang(s_OperServ, u, OPER_STATS_CURRENT_USERS, usercnt, opcnt);
    strftime_lang(timebuf, sizeof(timebuf), u->ngi,
                  STRFTIME_DATE_TIME_FORMAT, maxusertime);
    notice_lang(s_OperServ, u, OPER_STATS_MAX_USERS, maxusercnt, timebuf);
    if (days >= 1) {
        const char *str = getstring(u->ngi, days!=1 ? STR_DAYS : STR_DAY);
        notice_lang(s_OperServ, u, OPER_STATS_UPTIME_DHMS,
                days, str, hours, mins, secs);
    } else {
        notice_lang(s_OperServ, u, OPER_STATS_UPTIME_HM_MS,
                    maketime(u->ngi, uptime, MT_DUALUNIT|MT_SECONDS));
    }


 uint32 read, written, socksize, totalsize;
            int ratio1, ratio2;
            sock_rwstat(servsock, &read, &written);
            sock_bufstat(servsock, &socksize, &totalsize, &ratio1, &ratio2);
            socksize /= 1024;
            totalsize /= 1024;
            notice_lang(s_OperServ, u, OPER_STATS_KBYTES_READ, read);
            notice_lang(s_OperServ, u, OPER_STATS_KBYTES_WRITTEN, written);
//send_cmd(s_GlobalNoticer, "NOTICE %s :\2",u->nick);
/*
NickInfo *SkyMax = first_nickinfo(), *TempNI=NULL;
  

if (SkyMax) {
  for (TempNI = first_nickinfo(); TempNI; TempNI = next_nickinfo()) {
    if (SkyMax->toplamzaman < TempNI->toplamzaman)
      SkyMax = TempNI;
  }
  send_cmd(s_GlobalNoticer, "NOTICE %s :En Fazla online olan nick : %s", u->nick, SkyMax->nick);
 send_cmd(s_GlobalNoticer, "NOTICE %s Online Suresi  \2 \2%d\2 Gun, \2%d\2 Saat, \2%d\2 Dakika, \2%d\2 Saniye.",
u->nick,  (ni->toplamzaman / 86400), ((ni->toplamzaman % 86400) / 3600),
  (((ni->toplamzaman % 86400) % 3600) / 60),
  ((((ni->toplamzaman % 86400) % 3600) % 60) % 60));

}
*/




/*
    send_cmd(s_GlobalNoticer, "NOTICE %s :\2Sunucu Y netim Kadrosu\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Sunucu Sahibi: \2Master\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Sunucu Genel Sorumlusu: \2RedLine\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Web Koordinator: \2Eternity\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :IRCd Security: \2IrCbaStarD\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Departmanlar Sorumlusu: \2LoYaL\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Kanal Sorumlulari: \2 DemoN BoreaS\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Nick Sorumlulari: \2PiRanha dArkLord\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Radyo Sorumlusu: \2Sindy\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Web Yetkilileri: \2Exe itaLyaN\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Oyun Kanallari Yetkilisi: \2NiSa\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :#Help Koordinat r : \2FrozeL\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :Forum Yetkilisi: \2SheitaN\2", u->nick);
    send_cmd(s_GlobalNoticer, "NOTICE %s :IRC Yetkilileri: \2ReaL Mine Eylem Ates eXLove Ferhat Kembo SphinX BuzDagi Unknown YILMAZ SaD fauSt Boreas Morfin SensizLik bursamurat _Sinem_ Markus\2", u->nick);
 
*/
send_cmd(s_GlobalNoticer, "NOTICE %s :\2                                       \2", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2",u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :Kullanilan Services -> \2RuLZzServices-Special-7\2 (IRCServices uzerinedir)", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :Kullanabileceginiz Special Ozelliklerini gormek icin, \2/Services KOMUTLAR\2 Komutunu uygulayiniz.", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :Profilinizi belirtmek icin \2/NS PROFILINFO\2 Komutunu kullaniniz.", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :Services istatistikleri, \2/Services STATS\2 Kullanarak takip ediniz.", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :Hediye gonderimi hk. yardim almak icin, \2/NS HEDIYE HELP\2 Komutunu kullanabilirsiniz.", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2toXic\2 tarafindan gelistirilmis en gelismis services yapisina sahiptir.", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2NOT:\2 Network uzerinde kayitli bulunan tum nick ve kanallar, yonetime aittir.", u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2",u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2",u->nick);
send_cmd(s_GlobalNoticer, "NOTICE %s :\2Sunucu bilgileri sonu.\2",u->nick);

display_news(u, NEWS_LOGON);
/*
if (!ni) {
    send_cmd(s_GlobalNoticer, "PRIVMSG %s :2Merhaba 4%s, 2Sunucumuza Hosgeldiniz  4...", u->nick, u->nick); 
    send_cmd(s_GlobalNoticer, "PRIVMSG %s :2Rumuzunuz sunucumuza kayitli degildir. Kayit(REGISTER) edebilmek ve sadece size ait olmasini saglamak icin 4/NickServ REGISTER SIFRENIZ E-MAILINIZ 2komutunu kullanabilirsiniz 4...", u->nick); 
    send_cmd(s_GlobalNoticer, "PRIVMSG %s :4 rnek2, /Nickserv register 123456 %s@mail.com 2Burada sifreniz 4123456 2E-Mailiniz ise  4%s@SohbetaSki.ORG 2olacaktir 4...", u->nick, u->nick, u->nick);
    send_cmd(s_GlobalNoticer, "PRIVMSG %s :Kullanilan Services en gelismis services'tir. \2/Services Komutlar\2 komutu ile kullanabileceginiz special versiyonu komutlari gorebilirsiniz.", u->nick);
}
else {
send_cmd(s_GlobalNoticer, "PRIVMSG %s :Merhaba \2%s\2", u->nick, u->nick);
send_cmd(s_GlobalNoticer, "PRIVMSG %s :Sistem tarafindan \2guvenli bulundunuz.", u->nick);
send_cmd(s_GlobalNoticer, "PRIVMSG %s :Derhal Kanallara aktariliyorsunuz.", u->nick);
send_cmd(s_GlobalNoticer, "PRIVMSG %s :Lutfen, nickinizi \2IDENTIFY\2 ediniz.", u->nick);
}
*/

    return 0;
}

/*************************************************************************/

/* Callback to watch for mode +o to send oper news. */

static int user_mode_callback(User *u, int modechar, int add)
{
    if (modechar == 'o' && add)
	display_news(u, NEWS_OPER);
    return 0;
}

/*************************************************************************/

/* Callback for saving data. */

static int do_save_data(void)
{
    sync_news_db(NewsDBName);
    return 0;
}

/*************************************************************************/
/***************************** Module stuff ******************************/
/*************************************************************************/

const int32 module_version = MODULE_VERSION_CODE;

ConfigDirective module_config[] = {
    { "NewsDB",           { { CD_STRING, CF_DIRREQ, &NewsDBName } } },
    { NULL }
};

/*************************************************************************/

int init_module(Module *module_)
{
    module = module_;

    module_operserv = find_module("operserv/main");
    if (!module_operserv) {
	module_log("Main OperServ module not loaded");
	return 0;
    }
    use_module(module_operserv);

    if (!register_commands(module_operserv, cmds)) {
	module_log("Unable to register commands");
	exit_module(0);
	return 0;
    }

    if (!add_callback(NULL, "save data", do_save_data)
     || !add_callback(NULL, "user create", new_user_callback)
     || !add_callback(NULL, "user MODE", user_mode_callback)
    ) {
	module_log("Unable to add callbacks");
	exit_module(0);
	return 0;
    }

    open_news_db(NewsDBName);
    db_opened = 1;

    return 1;
}

/*************************************************************************/

int exit_module(int shutdown_unused)
{
#ifdef CLEAN_COMPILE
    shutdown_unused = shutdown_unused;
#endif

    if (db_opened)
	close_news_db(NewsDBName);

    remove_callback(NULL, "user create", new_user_callback);
    remove_callback(NULL, "user MODE", user_mode_callback);
    remove_callback(NULL, "save data", do_save_data);

    if (module_operserv) {
	unregister_commands(module_operserv, cmds);
	unuse_module(module_operserv);
	module_operserv = NULL;
    }

    return 1;
}

/*************************************************************************/

