--- srvx-1.4.0-rc3/src/chanserv.c	2010-04-08 13:28:57.000000000 +0200
+++ srvx-1.4.0-rc3-invite/src/chanserv.c	2010-04-08 13:48:57.000000000 +0200
@@ -55,8 +55,9 @@
 #define KEY_SUPPORT_HELPER_EPITHET  "support_helper_epithet"
 #define KEY_NODELETE_LEVEL          "nodelete_level"
 #define KEY_MAX_USERINFO_LENGTH     "max_userinfo_length"
 #define KEY_GIVEOWNERSHIP_PERIOD    "giveownership_timeout"
+#define KEY_INVITED_INTERVAL		"invite_timeout"
 
 /* ChanServ database */
 #define KEY_CHANNELS                "channels"
 #define KEY_NOTE_TYPES              "note_types"
@@ -309,8 +310,9 @@
     { "CSMSG_INVITED_USER", "Invited $b%s$b to join %s." },
     { "CSMSG_INVITING_YOU_REASON", "$b%s$b invites you to join %s: %s" },
     { "CSMSG_INVITING_YOU", "$b%s$b invites you to join %s." },
     { "CSMSG_ALREADY_PRESENT", "%s is already in $b%s$b." },
+	{ "CSMSG_ALREADY_INVITED", "%s has already been invited to $b%s$b." },
     { "CSMSG_YOU_ALREADY_PRESENT", "You are already in $b%s$b." },
     { "CSMSG_LOW_CHANNEL_ACCESS", "You lack sufficient access in %s for $S to invite you." },
     { "CSMSG_INFOLINE_TOO_LONG", "Your infoline may not exceed %u characters." },
     { "CSMSG_BAD_INFOLINE", "You may not use the character \\%03o in your infoline." },
@@ -498,8 +500,10 @@
     unsigned long   db_backup_frequency;
     unsigned long   channel_expire_frequency;
     unsigned long   dnr_expire_frequency;
 
+	unsigned long   invited_timeout;
+
     unsigned long   info_delay;
     unsigned long   adjust_delay;
     unsigned long   channel_expire_delay;
     unsigned int    nodelete_level;
@@ -539,8 +543,14 @@
     struct userData **users;
     struct helpfile_table table;
 };
 
+struct ChanUser
+{
+	struct userNode *user;
+    struct chanNode *chan;
+};
+
 enum note_access_type
 {
     NOTE_SET_CHANNEL_ACCESS,
     NOTE_SET_CHANNEL_SETTER,
@@ -4294,12 +4304,30 @@
     reply("CSMSG_MODES_SET", unsplit_string(argv+1, argc-1, NULL));
     return 1;
 }
 
+static void
+chanserv_del_invite_mark(void *data)
+{
+	struct ChanUser *chanuser = data;
+	struct chanNode *channel = chanuser->chan;
+	unsigned int i;
+	if(!channel) return;
+	for(i = 0; i < channel->invited.used; i++)
+    {
+        if(channel->invited.list[i] == chanuser->user) {
+			userList_remove(&channel->invited, chanuser->user);
+		}
+	}
+	free(chanuser);
+}
+
 static CHANSERV_FUNC(cmd_invite)
 {
     struct userData *uData;
     struct userNode *invite;
+	struct ChanUser *chanuser;
+	unsigned int i;
 
     uData = GetChannelUser(channel->channel_info, user->handle_info);
 
     if(argc > 1)
@@ -4318,8 +4346,16 @@
         reply("CSMSG_ALREADY_PRESENT", invite->nick, channel->name);
         return 0;
     }
 
+	for(i = 0; i < channel->invited.used; i++)
+    {
+        if(channel->invited.list[i] == invite) {
+			reply("CSMSG_ALREADY_INVITED", invite->nick, channel->name);
+			return 0;
+		}
+	}
+
     if(user != invite)
     {
         if(argc > 2)
         {
@@ -4332,8 +4368,13 @@
     irc_invite(chanserv, invite, channel);
     if(argc > 1)
         reply("CSMSG_INVITED_USER", argv[1], channel->name);
 
+	userList_append(&channel->invited, invite);
+	chanuser = calloc(1, sizeof(*chanuser));
+	chanuser->user=invite;
+	chanuser->chan=channel;
+	timeq_add(now + chanserv_conf.invited_timeout, chanserv_del_invite_mark, chanuser);
     return 1;
 }
 
 static CHANSERV_FUNC(cmd_inviteme)
@@ -6471,8 +6520,9 @@
     struct userData *uData = NULL;
     struct banData *bData;
     struct handle_info *handle;
     unsigned int modes = 0, info = 0;
+	unsigned int i;
     char *greeting;
 
     if(IsLocal(user) || !channel->channel_info || IsSuspended(channel->channel_info))
         return 0;
@@ -6480,8 +6530,16 @@
     cData = channel->channel_info;
     if(channel->members.used > cData->max)
         cData->max = channel->members.used;
 
+	for(i = 0; i < channel->invited.used; i++)
+    {
+        if(channel->invited.list[i] == user) {
+			userList_remove(&channel->invited, user);
+		}
+	}
+	
+	
     /* Check for bans.  If they're joining through a ban, one of two
      * cases applies:
      *   1: Join during a netburst, by riding the break.  Kick them
      *      unless they have ops or voice in the channel.
@@ -7042,8 +7100,10 @@
     str = database_get_data(conf_node, KEY_CHAN_EXPIRE_DELAY, RECDB_QSTRING);
     chanserv_conf.channel_expire_delay = str ? ParseInterval(str) : 86400*30;
     str = database_get_data(conf_node, KEY_DNR_EXPIRE_FREQ, RECDB_QSTRING);
     chanserv_conf.dnr_expire_frequency = str ? ParseInterval(str) : 3600;
+	str = database_get_data(conf_node, KEY_INVITED_INTERVAL, RECDB_QSTRING);
+    chanserv_conf.invited_timeout = str ? ParseInterval(str) : 600;
     str = database_get_data(conf_node, KEY_NODELETE_LEVEL, RECDB_QSTRING);
     chanserv_conf.nodelete_level = str ? atoi(str) : 1;
     str = database_get_data(conf_node, KEY_MAX_CHAN_USERS, RECDB_QSTRING);
     chanserv_conf.max_chan_users = str ? atoi(str) : 512;
--- srvx-1.4.0-rc3/src/hash.c	2010-04-08 13:28:57.000000000 +0200
+++ srvx-1.4.0-rc3-invite/src/hash.c	2010-04-08 13:47:53.000000000 +0200
@@ -376,8 +376,9 @@
         cNode = calloc(1, sizeof(*cNode) + strlen(name));
         strcpy(cNode->name, name);
         banList_init(&cNode->banlist);
         modeList_init(&cNode->members);
+		userList_init(&cNode->invited);
         mod_chanmode(NULL, cNode, argv, nn, MCP_FROM_SERVER);
         dict_insert(channels, cNode->name, cNode);
         cNode->timestamp = time_;
         rel_age = 1;
@@ -463,8 +464,9 @@
         dcf_list[n](channel);
 
     modeList_clean(&channel->members);
     banList_clean(&channel->banlist);
+	userList_clean(&channel->invited);
     free(channel);
 }
 
 struct modeNode *
--- srvx-1.4.0-rc3/src/hash.h	2010-04-08 13:28:57.000000000 +0200
+++ srvx-1.4.0-rc3-invite/src/hash.h	2010-04-08 13:47:54.000000000 +0200
@@ -161,8 +161,9 @@
 
     struct modeList members;
     struct banList banlist;
     struct policer join_policer;
+	struct userList invited;
     unsigned int join_flooded : 1;
     unsigned int bad_channel : 1;
 
     struct chanData *channel_info;
