882 |
|
strlcpy(chptr->topic_info, topic_info, sizeof(chptr->topic_info)); |
883 |
|
chptr->topic_time = topicts; |
884 |
|
} |
885 |
+ |
|
886 |
+ |
/* do_join_0() |
887 |
+ |
* |
888 |
+ |
* inputs - pointer to client doing join 0 |
889 |
+ |
* output - NONE |
890 |
+ |
* side effects - Use has decided to join 0. This is legacy |
891 |
+ |
* from the days when channels were numbers not names. *sigh* |
892 |
+ |
* There is a bunch of evilness necessary here due to |
893 |
+ |
* anti spambot code. |
894 |
+ |
*/ |
895 |
+ |
void |
896 |
+ |
channel_do_join_0(struct Client *source_p) |
897 |
+ |
{ |
898 |
+ |
dlink_node *ptr = NULL, *ptr_next = NULL; |
899 |
+ |
|
900 |
+ |
if (source_p->channel.head) |
901 |
+ |
if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER)) |
902 |
+ |
check_spambot_warning(source_p, NULL); |
903 |
+ |
|
904 |
+ |
DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head) |
905 |
+ |
{ |
906 |
+ |
struct Channel *chptr = ((struct Membership *)ptr->data)->chptr; |
907 |
+ |
|
908 |
+ |
sendto_server(source_p, NOCAPS, NOCAPS, ":%s PART %s", |
909 |
+ |
source_p->id, chptr->chname); |
910 |
+ |
sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s", |
911 |
+ |
source_p->name, source_p->username, |
912 |
+ |
source_p->host, chptr->chname); |
913 |
+ |
|
914 |
+ |
remove_user_from_channel(ptr->data); |
915 |
+ |
} |
916 |
+ |
} |
917 |
+ |
|
918 |
+ |
static char * |
919 |
+ |
channel_find_last0(struct Client *source_p, char *chanlist) |
920 |
+ |
{ |
921 |
+ |
int join0 = 0; |
922 |
+ |
|
923 |
+ |
for (char *p = chanlist; *p; ++p) /* Find last "JOIN 0" */ |
924 |
+ |
{ |
925 |
+ |
if (*p == '0' && (*(p + 1) == ',' || *(p + 1) == '\0')) |
926 |
+ |
{ |
927 |
+ |
if ((*p + 1) == ',') |
928 |
+ |
++p; |
929 |
+ |
|
930 |
+ |
chanlist = p + 1; |
931 |
+ |
join0 = 1; |
932 |
+ |
} |
933 |
+ |
else |
934 |
+ |
{ |
935 |
+ |
while (*p != ',' && *p != '\0') /* Skip past channel name */ |
936 |
+ |
++p; |
937 |
+ |
|
938 |
+ |
if (*p == '\0') /* Hit the end */ |
939 |
+ |
break; |
940 |
+ |
} |
941 |
+ |
} |
942 |
+ |
|
943 |
+ |
if (join0) |
944 |
+ |
channel_do_join_0(source_p); |
945 |
+ |
|
946 |
+ |
return chanlist; |
947 |
+ |
} |
948 |
+ |
|
949 |
+ |
void |
950 |
+ |
channel_do_join(struct Client *source_p, char *parv[]) |
951 |
+ |
{ |
952 |
+ |
char *p = NULL; |
953 |
+ |
char *key_list = NULL; |
954 |
+ |
char *chan_list = NULL; |
955 |
+ |
char *chan = NULL; |
956 |
+ |
struct Channel *chptr = NULL; |
957 |
+ |
struct MaskItem *conf = NULL; |
958 |
+ |
int i = 0; |
959 |
+ |
unsigned int flags = 0; |
960 |
+ |
|
961 |
+ |
key_list = parv[2]; |
962 |
+ |
chan_list = channel_find_last0(source_p, parv[1]); |
963 |
+ |
|
964 |
+ |
for (chan = strtoken(&p, chan_list, ","); chan; |
965 |
+ |
chan = strtoken(&p, NULL, ",")) |
966 |
+ |
{ |
967 |
+ |
const char *key = NULL; |
968 |
+ |
|
969 |
+ |
/* If we have any more keys, take the first for this channel. */ |
970 |
+ |
if (!EmptyString(key_list) && (key_list = strchr(key = key_list, ','))) |
971 |
+ |
*key_list++ = '\0'; |
972 |
+ |
|
973 |
+ |
/* Empty keys are the same as no keys. */ |
974 |
+ |
if (key && *key == '\0') |
975 |
+ |
key = NULL; |
976 |
+ |
|
977 |
+ |
if (!check_channel_name(chan, 1)) |
978 |
+ |
{ |
979 |
+ |
sendto_one_numeric(source_p, &me, ERR_BADCHANNAME, chan); |
980 |
+ |
continue; |
981 |
+ |
} |
982 |
+ |
|
983 |
+ |
if (!IsExemptResv(source_p) && |
984 |
+ |
!(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv) && |
985 |
+ |
((conf = match_find_resv(chan)) && !resv_find_exempt(source_p, conf))) |
986 |
+ |
{ |
987 |
+ |
++conf->count; |
988 |
+ |
sendto_one_numeric(source_p, &me, ERR_CHANBANREASON, |
989 |
+ |
chan, conf->reason ? conf->reason : "Reserved channel"); |
990 |
+ |
sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE, |
991 |
+ |
"Forbidding reserved channel %s from user %s", |
992 |
+ |
chan, get_client_name(source_p, HIDE_IP)); |
993 |
+ |
continue; |
994 |
+ |
} |
995 |
+ |
|
996 |
+ |
if (dlink_list_length(&source_p->channel) >= |
997 |
+ |
(HasUMode(source_p, UMODE_OPER) ? |
998 |
+ |
ConfigChannel.max_chans_per_oper : |
999 |
+ |
ConfigChannel.max_chans_per_user)) |
1000 |
+ |
{ |
1001 |
+ |
sendto_one_numeric(source_p, &me, ERR_TOOMANYCHANNELS, chan); |
1002 |
+ |
break; |
1003 |
+ |
} |
1004 |
+ |
|
1005 |
+ |
if ((chptr = hash_find_channel(chan))) |
1006 |
+ |
{ |
1007 |
+ |
if (IsMember(source_p, chptr)) |
1008 |
+ |
continue; |
1009 |
+ |
|
1010 |
+ |
if (splitmode && !HasUMode(source_p, UMODE_OPER) && |
1011 |
+ |
ConfigChannel.no_join_on_split) |
1012 |
+ |
{ |
1013 |
+ |
sendto_one_numeric(source_p, &me, ERR_UNAVAILRESOURCE, chan); |
1014 |
+ |
continue; |
1015 |
+ |
} |
1016 |
+ |
|
1017 |
+ |
/* |
1018 |
+ |
* can_join checks for +i key, bans. |
1019 |
+ |
*/ |
1020 |
+ |
if ((i = can_join(source_p, chptr, key))) |
1021 |
+ |
{ |
1022 |
+ |
sendto_one_numeric(source_p, &me, i, chptr->chname); |
1023 |
+ |
continue; |
1024 |
+ |
} |
1025 |
+ |
|
1026 |
+ |
/* |
1027 |
+ |
* This should never be the case unless there is some sort of |
1028 |
+ |
* persistant channels. |
1029 |
+ |
*/ |
1030 |
+ |
if (dlink_list_length(&chptr->members) == 0) |
1031 |
+ |
flags = CHFL_CHANOP; |
1032 |
+ |
else |
1033 |
+ |
flags = 0; |
1034 |
+ |
} |
1035 |
+ |
else |
1036 |
+ |
{ |
1037 |
+ |
if (splitmode && !HasUMode(source_p, UMODE_OPER) && |
1038 |
+ |
(ConfigChannel.no_create_on_split || ConfigChannel.no_join_on_split)) |
1039 |
+ |
{ |
1040 |
+ |
sendto_one_numeric(source_p, &me, ERR_UNAVAILRESOURCE, chan); |
1041 |
+ |
continue; |
1042 |
+ |
} |
1043 |
+ |
|
1044 |
+ |
flags = CHFL_CHANOP; |
1045 |
+ |
chptr = make_channel(chan); |
1046 |
+ |
} |
1047 |
+ |
|
1048 |
+ |
if (!HasUMode(source_p, UMODE_OPER)) |
1049 |
+ |
check_spambot_warning(source_p, chptr->chname); |
1050 |
+ |
|
1051 |
+ |
add_user_to_channel(chptr, source_p, flags, 1); |
1052 |
+ |
|
1053 |
+ |
/* |
1054 |
+ |
* Set timestamp if appropriate, and propagate |
1055 |
+ |
*/ |
1056 |
+ |
if (flags == CHFL_CHANOP) |
1057 |
+ |
{ |
1058 |
+ |
chptr->channelts = CurrentTime; |
1059 |
+ |
chptr->mode.mode |= MODE_TOPICLIMIT; |
1060 |
+ |
chptr->mode.mode |= MODE_NOPRIVMSGS; |
1061 |
+ |
|
1062 |
+ |
sendto_server(source_p, NOCAPS, NOCAPS, ":%s SJOIN %lu %s +nt :@%s", |
1063 |
+ |
me.id, (unsigned long)chptr->channelts, |
1064 |
+ |
chptr->chname, source_p->id); |
1065 |
+ |
|
1066 |
+ |
/* |
1067 |
+ |
* Notify all other users on the new channel |
1068 |
+ |
*/ |
1069 |
+ |
sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s", |
1070 |
+ |
source_p->name, source_p->username, |
1071 |
+ |
source_p->host, chptr->chname); |
1072 |
+ |
sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s MODE %s +nt", |
1073 |
+ |
me.name, chptr->chname); |
1074 |
+ |
|
1075 |
+ |
if (source_p->away[0]) |
1076 |
+ |
sendto_channel_local_butone(source_p, 0, CAP_AWAY_NOTIFY, chptr, |
1077 |
+ |
":%s!%s@%s AWAY :%s", |
1078 |
+ |
source_p->name, source_p->username, |
1079 |
+ |
source_p->host, source_p->away); |
1080 |
+ |
} |
1081 |
+ |
else |
1082 |
+ |
{ |
1083 |
+ |
sendto_server(source_p, NOCAPS, NOCAPS, ":%s JOIN %lu %s +", |
1084 |
+ |
source_p->id, (unsigned long)chptr->channelts, |
1085 |
+ |
chptr->chname); |
1086 |
+ |
sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s JOIN :%s", |
1087 |
+ |
source_p->name, source_p->username, |
1088 |
+ |
source_p->host, chptr->chname); |
1089 |
+ |
|
1090 |
+ |
if (source_p->away[0]) |
1091 |
+ |
sendto_channel_local_butone(source_p, 0, CAP_AWAY_NOTIFY, chptr, |
1092 |
+ |
":%s!%s@%s AWAY :%s", |
1093 |
+ |
source_p->name, source_p->username, |
1094 |
+ |
source_p->host, source_p->away); |
1095 |
+ |
} |
1096 |
+ |
|
1097 |
+ |
del_invite(chptr, source_p); |
1098 |
+ |
|
1099 |
+ |
if (chptr->topic[0]) |
1100 |
+ |
{ |
1101 |
+ |
sendto_one_numeric(source_p, &me, RPL_TOPIC, chptr->chname, chptr->topic); |
1102 |
+ |
sendto_one_numeric(source_p, &me, RPL_TOPICWHOTIME, chptr->chname, |
1103 |
+ |
chptr->topic_info, chptr->topic_time); |
1104 |
+ |
} |
1105 |
+ |
|
1106 |
+ |
channel_member_names(source_p, chptr, 1); |
1107 |
+ |
|
1108 |
+ |
source_p->localClient->last_join_time = CurrentTime; |
1109 |
+ |
} |
1110 |
+ |
} |
1111 |
+ |
|
1112 |
+ |
/*! \brief Removes a client from a specific channel |
1113 |
+ |
* \param source_p Pointer to source client to remove |
1114 |
+ |
* \param name Name of channel to remove from |
1115 |
+ |
* \param reason Part reason to show |
1116 |
+ |
*/ |
1117 |
+ |
static void |
1118 |
+ |
channel_part_one_client(struct Client *source_p, const char *name, const char *reason) |
1119 |
+ |
{ |
1120 |
+ |
struct Channel *chptr = NULL; |
1121 |
+ |
struct Membership *ms = NULL; |
1122 |
+ |
|
1123 |
+ |
if ((chptr = hash_find_channel(name)) == NULL) |
1124 |
+ |
{ |
1125 |
+ |
sendto_one_numeric(source_p, &me, ERR_NOSUCHCHANNEL, name); |
1126 |
+ |
return; |
1127 |
+ |
} |
1128 |
+ |
|
1129 |
+ |
if ((ms = find_channel_link(source_p, chptr)) == NULL) |
1130 |
+ |
{ |
1131 |
+ |
sendto_one_numeric(source_p, &me, ERR_NOTONCHANNEL, chptr->chname); |
1132 |
+ |
return; |
1133 |
+ |
} |
1134 |
+ |
|
1135 |
+ |
if (MyConnect(source_p) && !HasUMode(source_p, UMODE_OPER)) |
1136 |
+ |
check_spambot_warning(source_p, NULL); |
1137 |
+ |
|
1138 |
+ |
/* |
1139 |
+ |
* Remove user from the old channel (if any) |
1140 |
+ |
* only allow /part reasons in -m chans |
1141 |
+ |
*/ |
1142 |
+ |
if (*reason && (!MyConnect(source_p) || |
1143 |
+ |
((can_send(chptr, source_p, ms, reason) && |
1144 |
+ |
(source_p->localClient->firsttime + ConfigFileEntry.anti_spam_exit_message_time) |
1145 |
+ |
< CurrentTime)))) |
1146 |
+ |
{ |
1147 |
+ |
sendto_server(source_p, NOCAPS, NOCAPS, ":%s PART %s :%s", |
1148 |
+ |
source_p->id, chptr->chname, reason); |
1149 |
+ |
sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s :%s", |
1150 |
+ |
source_p->name, source_p->username, |
1151 |
+ |
source_p->host, chptr->chname, reason); |
1152 |
+ |
} |
1153 |
+ |
else |
1154 |
+ |
{ |
1155 |
+ |
sendto_server(source_p, NOCAPS, NOCAPS, ":%s PART %s", |
1156 |
+ |
source_p->id, chptr->chname); |
1157 |
+ |
sendto_channel_local(ALL_MEMBERS, 0, chptr, ":%s!%s@%s PART %s", |
1158 |
+ |
source_p->name, source_p->username, |
1159 |
+ |
source_p->host, chptr->chname); |
1160 |
+ |
} |
1161 |
+ |
|
1162 |
+ |
remove_user_from_channel(ms); |
1163 |
+ |
} |
1164 |
+ |
|
1165 |
+ |
void |
1166 |
+ |
channel_do_part(struct Client *source_p, char *parv[]) |
1167 |
+ |
{ |
1168 |
+ |
char *p = NULL, *name = NULL; |
1169 |
+ |
char reason[KICKLEN + 1] = ""; |
1170 |
+ |
|
1171 |
+ |
if (!EmptyString(parv[2])) |
1172 |
+ |
strlcpy(reason, parv[2], sizeof(reason)); |
1173 |
+ |
|
1174 |
+ |
for (name = strtoken(&p, parv[1], ","); name; |
1175 |
+ |
name = strtoken(&p, NULL, ",")) |
1176 |
+ |
channel_part_one_client(source_p, name, reason); |
1177 |
+ |
} |