001 I64 Str2UserFlags(U8 *str) { 002 I64 ret=0; 003 if(!str) return ret; 004 if(StrOcc(str,'v')) ret|=IRCD_USERMODE_v; 005 if(StrOcc(str,'q')) ret|=IRCD_USERMODE_q; 006 if(StrOcc(str,'a')) ret|=IRCD_USERMODE_a; 007 if(StrOcc(str,'o')) ret|=IRCD_USERMODE_o; 008 if(StrOcc(str,'h')) ret|=IRCD_USERMODE_h; 009 return ret; 010 } 011 U8 *Flags2UserModeStr(I64 flags) { 012 U8 *ret=MAlloc(16); 013 StrCpy(ret,""); 014 if(flags&IRCD_USERMODE_v) CatPrint(ret,"v"); 015 if(flags&IRCD_USERMODE_q) CatPrint(ret,"q"); 016 if(flags&IRCD_USERMODE_o) CatPrint(ret,"o"); 017 if(flags&IRCD_USERMODE_a) CatPrint(ret,"a"); 018 if(flags&IRCD_USERMODE_h) CatPrint(ret,"h"); 019 return ret; 020 } 021 022 023 024 U0 IrcChannelAdd(U8 *name) 025 { 026 IrcChannel *channel = CAlloc(sizeof(IrcChannel),gihon_task); 027 channel->name = StrNew(name,gihon_task); 028 channel->topic = CAlloc(4096,gihon_task); 029 channel->users = CAlloc(sizeof(IrcUser),gihon_task); 030 channel->backlog=FifoI64New(BACKLOG_FIFO_SZ,gihon_task); 031 IrcChannel *channels = channel_head; 032 while (channels->next) 033 { 034 channels = channels->next; 035 } 036 channel->prev = channels; 037 channels->next = channel; 038 ircd_chans_total++; 039 } 040 041 U0 IrcChannelDel(IrcChannel *channel) 042 { 043 U8 *msg; 044 IrcChannel *prev = channel->prev; 045 IrcChannel *next = channel->next; 046 if(prev) prev->next = next; 047 if(next) next->prev = prev; 048 while(FifoI64Rem(channel->backlog,&msg)) 049 Free(msg); 050 FifoI64Del(channel->backlog); 051 Free(channel->name); 052 Free(channel); 053 ircd_chans_total--; 054 } 055 056 U0 IrcList(IrcClient *client) { 057 IrcChannel *channel = channel_head; 058 IrcUser *u; 059 U8 buf[4096]; 060 I64 users; 061 GihonFifoIns(client->msgs, MStrPrint(":%s 321 %s Channel :Users Name\n",ircd_hostname,client->nick)); 062 while (channel) 063 { 064 if (channel->name) { 065 u=channel->users; 066 users=0; 067 while(u&&(u=u->next)) 068 users++; 069 StrPrint(buf,":%s 322 %s %s %d :'%s'\n",ircd_hostname,client->nick,channel->name,users,channel->topic); 070 GihonFifoIns(client->msgs, StrNew(buf)); 071 } 072 channel = channel->next; 073 } 074 GihonFifoIns(client->msgs, MStrPrint(":%s 323 %s :End of /LIST\n",ircd_hostname,client->nick)); 075 } 076 077 IrcChannel *IrcGetChanByName(U8 *channame) 078 { 079 IrcChannel *channel = channel_head; 080 while (channel) 081 { 082 if (channel->name&&!StrCmp(channel->name, channame)) return channel; 083 channel = channel->next; 084 } 085 return NULL; 086 } 087 088 U0 IrcChannelUserAdd(IrcChannel *channel, IrcClient *client, U64 flags=NULL) 089 { 090 IrcUser *user = CAlloc(sizeof(IrcUser),gihon_task); 091 IrcUser *users = channel->users; 092 while(users->next) users=users->next; 093 user->client = client; 094 user->flags = flags; 095 user->prev = users; 096 users->next = user; 097 } 098 099 Bool IrcChannelUserDel(IrcChannel *channel, IrcClient *client) 100 { 101 Bool removed=FALSE; 102 IrcUser *users = channel->users->next; 103 IrcUser *prev = NULL; 104 IrcUser *next = NULL; 105 re_enter: 106 while (users) 107 { 108 if (users->client==client) 109 { 110 prev=users->prev; 111 next=users->next; 112 if(prev) prev->next = next; 113 if(next) next->prev = prev; 114 Free(users); 115 users=next; 116 removed=TRUE; 117 //Maybe there are multiple references to a user in a channel 118 goto re_enter; 119 } 120 users = users->next; 121 } 122 return removed; 123 } 124 125 U0 IrcChannelTopic(U8 *channame, IrcClient *client, U8 *topic) 126 { 127 U8 *buf = CAlloc(4096); 128 IrcChannel *channel = IrcGetChanByName(channame); 129 IrcUser *user; 130 IrcUser *users; 131 if (channel) 132 { 133 user = channel->users->next; 134 while (user) 135 { 136 if (user->client==client) 137 { 138 if (user->flags >= IRCD_USERMODE_o&&client->logged_in) 139 { 140 StrPrint(channel->topic, topic); 141 IrcSaveChannelTopic(channel,topic); 142 users = channel->users->next; 143 while (users) 144 { 145 StrPrint(buf, ":%s!%s@%s TOPIC %s :%s\r\n", client->nick, client->username, 146 client->host, channame, channel->topic); 147 GihonFifoIns(users->client->msgs, StrNew(buf)); 148 users = users->next; 149 } 150 } 151 else 152 { 153 StrPrint(buf, ":%s 482 %s %s :You do not have access to change the topic on this channel\r\n", 154 ircd_hostname, client->username, channame); 155 GihonFifoIns(client->msgs, StrNew(buf)); 156 } 157 Free(buf); 158 return; 159 } 160 user = user->next; 161 } 162 } 163 Free(buf); 164 } 165 166 #include "MessageTag.HC"; 167 CDate IrcPrsTimeTag(U8 *str,CDateStruct *ds=NULL) { 168 U8 *buf=IrcParseMessageTag(str,"time"); 169 CDateStruct _ds; 170 if(!ds) ds=&_ds; 171 MemSet(ds,0,sizeof CDateStruct); 172 if(!buf) return 0; 173 I64 yr,mon,day,hr,mn,sc,s100; 174 StrScan(buf,"%d-%d-%dT%d:%d:%d.%dZ",&yr,&mon,&day, 175 &hr,&mn,&sc,&s100 176 ); 177 ds->year=yr; 178 ds->mon=mon; 179 ds->day_of_mon=day; 180 ds->hour=hr; 181 ds->min=mn; 182 ds->sec=sc; 183 ds->sec100=s100; 184 Free(buf); 185 return Struct2Date(ds); 186 } 187 I64 DateCmp(CDate a,CDate b) { 188 if(a.date>b.date) return 1; 189 if(a.date<b.date) return -1; 190 if(a.time>b.time) return 1; 191 if(a.time<b.time) return -1; 192 return 0; 193 } 194 U0 IrcBacklog(IrcClient *to,U8 *name) { 195 IrcChannel *channel = channel_head->next; 196 CFifoI64 *shalow; 197 U8 *tmp,buf[4096],who[4096],msg[4096],time_tag[4096]; 198 U8 *msg_ptr=msg,*who_ptr=who,*time_tag_ptr=time_tag; 199 while(channel) { 200 if(channel->name&&!StrCmp(channel->name,name)) { 201 shalow=MAllocIdent(channel->backlog); 202 while(FifoI64Rem(shalow,&tmp)) { 203 StrScan(tmp," %s:%s",&who_ptr,&msg_ptr); 204 StrPrint(buf, ":%s!%s@%s PRIVMSG %s :%s\r\n", who, to->username,to->host, name, msg); 205 GihonFifoIns(to->msgs, StrNew(buf)); 206 } 207 Free(shalow); 208 break; 209 } 210 channel=channel->next; 211 } 212 } 213 214 215 Bool IrcChannelJoin(U8 *_channame, IrcClient *client,U8 *password=NULL) 216 { 217 Bool ret=TRUE; 218 U64 flags = IRCD_USERMODE_v; 219 IrcChannel *channel; 220 IrcUser *users; 221 U8 *orig = StrNew(_channame),*channame,*time_code,*user_flags_str; 222 _channame = orig; 223 while (*_channame) { 224 channame = _channame; 225 if (StrFirstOcc(channame,",")) { 226 _channame=StrFirstOcc(channame,",")+1; 227 _channame[-1]=0; 228 } else 229 _channame += StrLen(_channame); 230 if (channame[0]==':') channame++; // Fix for Revolution IRC client? 231 channel = IrcGetChanByName(channame); 232 if (!channel) 233 { 234 if(channame[0]!='#') { 235 GihonFifoIns(client->msgs,MStrPrint(":%s 403 %s %s :Channel names need to start with '#'.\r\n", 236 ircd_hostname, client->username, channame)); 237 return; 238 } 239 user_flags_str=IrcGetChannelUserMode(channame,client->nick); 240 if(!user_flags_str) { 241 flags=IRCD_USERMODE_q|IRCD_USERMODE_o|IRCD_USERMODE_v; 242 IrcSetChannelUserMode(channame,client->nick,"oqv"); 243 } else { 244 flags=Str2UserFlags(user_flags_str); 245 Free(user_flags_str); 246 } 247 IrcChannelAdd(channame); 248 channel = IrcGetChanByName(channame); 249 } 250 users=channel->users->next; 251 while(users) { 252 if(users->client==client) 253 goto already_in_chan; 254 users=users->next; 255 } 256 if (channel) 257 { 258 if(channel->password_hash) { 259 if(!password) 260 goto bad_pass; 261 if(HashStr(password)!=channel->password_hash) 262 goto bad_pass; 263 } else if(password) { 264 bad_pass: 265 ret=FALSE; 266 GihonFifoIns(client->msgs,MStrPrint(":%s 475 %s %s :Invalid channel password.\r\n", 267 ircd_hostname, client->username, channame)); 268 goto already_in_chan; 269 } 270 user_flags_str=IrcGetChannelUserMode(channame,client->nick); 271 if(user_flags_str) 272 flags=Str2UserFlags(user_flags_str); 273 else 274 flags=IRCD_USERMODE_v; //TODO default flags for poo poo 275 Free(user_flags_str); 276 IrcChannelUserAdd(channel, client, flags); 277 IrcClientJoin(channame, client); 278 IrcBacklog(client,channame); 279 } 280 already_in_chan:; 281 } 282 Free(orig); 283 return ret; 284 } 285 286 U0 IrcChannelKick(U8 *channame, IrcClient *client, U8 *nick, U8 *reason=NULL) 287 { 288 U8 *buf = CAlloc(4096); 289 IrcChannel *channel = IrcGetChanByName(channame); 290 IrcClient *kick_client = IrcGetClientByNick(nick); 291 IrcUser *user; 292 IrcUser *users; 293 if (channel && kick_client) 294 { 295 user = channel->users->next; 296 while (user) 297 { 298 if (user->client==client) 299 { 300 if (user->flags >= IRCD_USERMODE_h) 301 { 302 users = channel->users->next; 303 while (users) 304 { 305 StrPrint(buf, ":%s!%s@%s KICK %s %s :%s\r\n", client->nick, client->username, 306 client->host, channame, nick, reason); 307 GihonFifoIns(users->client->msgs, StrNew(buf)); 308 users = users->next; 309 } 310 IrcChannelUserDel(channel, kick_client); 311 } 312 else 313 { 314 StrPrint(buf, ":%s 482 %s %s :You must be a channel half-operator\r\n", 315 ircd_hostname, client->username, channame); 316 GihonFifoIns(client->msgs, StrNew(buf)); 317 } 318 Free(buf); 319 return; 320 } 321 user = user->next; 322 } 323 } 324 Free(buf); 325 } 326 327 U0 IrcChannelMode(U8 *channame, IrcClient *client, U8 *mode, U8 *nick=NULL) 328 { 329 U64 res = 0; 330 Bool set = FALSE; 331 U8 *buf = CAlloc(4096),*flags_str; 332 IrcChannel *channel = IrcGetChanByName(channame); 333 IrcClient *mode_client = NULL; 334 IrcUser *user; 335 IrcUser *users; 336 337 if(!channel) return; 338 339 if(!client->logged_in) { 340 StrPrint(buf, ":%s 482 %s %s :You must logged in to use MODE.\r\n", 341 ircd_hostname, client->username, channame); 342 GihonFifoIns(client->msgs, StrNew(buf)); 343 Free(buf); 344 return; 345 } 346 347 if(!StrCmp("-k",mode)) { 348 user = channel->users->next; 349 while (user) { 350 if (user->client==client) { 351 if(user->flags>=IRCD_USERMODE_o) { 352 IrcSetChannelPassword(channel,NULL); 353 goto fin; 354 } 355 } 356 user=user->next; 357 } 358 StrPrint(buf, ":%s 482 %s %s :You have to be an operator to set remove a password.\r\n", 359 ircd_hostname, client->username, channame); 360 GihonFifoIns(client->msgs, StrNew(buf)); 361 goto fin; 362 } else if(!StrCmp("+k",mode)) { 363 user = channel->users->next; 364 while (user) { 365 if (user->client==client) { 366 if(user->flags>=IRCD_USERMODE_o) { 367 IrcSetChannelPassword(channel,nick); 368 goto fin; 369 } 370 } 371 user=user->next; 372 } 373 StrPrint(buf, ":%s 482 %s %s :Only operators can set channel passwords.\r\n", 374 ircd_hostname, client->username, channame); 375 GihonFifoIns(client->msgs, StrNew(buf)); 376 goto fin; 377 } 378 379 if (nick) 380 { // Set user mode 381 mode_client = IrcGetClientByNick(nick); 382 if (!mode_client) 383 { 384 // nick does not exist? 385 Free(buf); 386 return; 387 } 388 else 389 { 390 user = channel->users->next; 391 while (user) 392 { 393 if (user->client==client) 394 { 395 if ((!StrCmp("-v", mode) || !StrCmp("+v", mode))) 396 { 397 set = TRUE; 398 if (user->flags < IRCD_USERMODE_h) 399 { 400 res = IRCD_USERMODE_h; 401 } 402 } 403 if ((!StrCmp("-h", mode) || !StrCmp("+h", mode))) 404 { 405 set = TRUE; 406 if (user->flags < IRCD_USERMODE_o) 407 { 408 res = IRCD_USERMODE_o; 409 } 410 } 411 if ((!StrCmp("-o", mode) || !StrCmp("+o", mode))) 412 { 413 set = TRUE; 414 if (user->flags < IRCD_USERMODE_q) 415 { 416 res = IRCD_USERMODE_q; 417 } 418 } 419 if (set) 420 { 421 if (!res) 422 { 423 users = channel->users->next; 424 while (users) 425 { 426 if (users->client==mode_client) 427 { 428 if (mode[0]=='-') 429 { 430 if (user->flags >= users->flags) 431 { 432 switch (mode[1]) 433 { 434 case 'v': 435 users->flags&=~IRCD_USERMODE_v; 436 break; 437 //Removing an pridvledge will remove "parent privledges". 438 case 'h': 439 users->flags&=~IRCD_USERMODE_h; 440 case 'o': 441 users->flags&=~IRCD_USERMODE_o; 442 case 'a': 443 users->flags&=~IRCD_USERMODE_a; 444 case 'q': 445 users->flags&=~IRCD_USERMODE_q; 446 default: 447 break; 448 } 449 } 450 } 451 if (mode[0]=='+') 452 { 453 switch (mode[1]) 454 { 455 case 'v': 456 users->flags|=IRCD_USERMODE_v; 457 break; 458 case 'h': 459 users->flags|=IRCD_USERMODE_h; 460 break; 461 case 'o': 462 users->flags|=IRCD_USERMODE_o; 463 break; 464 case 'a': 465 users->flags|=IRCD_USERMODE_a; 466 break; 467 case 'q': 468 users->flags|=IRCD_USERMODE_q; 469 break; 470 default: 471 break; 472 } 473 } 474 } 475 flags_str=Flags2UserModeStr(users->flags); 476 IrcSetChannelUserMode(channame,users->client->nick,flags_str); 477 Free(flags_str); 478 StrPrint(buf, ":%s!%s@%s MODE %s %s %s\r\n", client->nick, client->username,client->host, channame, mode, nick); 479 GihonFifoIns(users->client->msgs, StrNew(buf)); 480 users = users->next; 481 } 482 } 483 else 484 { 485 switch (res) 486 { 487 case IRCD_USERMODE_h: 488 StrPrint(buf, ":%s 482 %s %s :You must have channel halfop access or above to set channel mode #\r\n", 489 ircd_hostname, client->username, channame); 490 buf[StrLen(buf)-3] = mode[1]; 491 GihonFifoIns(client->msgs, StrNew(buf)); 492 break; 493 case IRCD_USERMODE_o: 494 StrPrint(buf, ":%s 482 %s %s :You must have channel op access or above to set channel mode #\r\n", 495 ircd_hostname, client->username, channame); 496 buf[StrLen(buf)-3] = mode[1]; 497 GihonFifoIns(client->msgs, StrNew(buf)); 498 break; 499 case IRCD_USERMODE_q: 500 StrPrint(buf, ":%s 482 %s %s :You must be the channel owner to set channel mode #\r\n", 501 ircd_hostname, client->username, channame); 502 buf[StrLen(buf)-3] = mode[1]; 503 GihonFifoIns(client->msgs, StrNew(buf)); 504 break; 505 default: 506 break; 507 } 508 } 509 } 510 Free(buf); 511 return; 512 } 513 user = user->next; 514 } 515 } 516 } 517 else 518 { // TODO: Set channel mode 519 if (channel) 520 { 521 522 } 523 524 } 525 fin: 526 Free(buf); 527 } 528 529 U0 IrcChannelPart(U8 *channame, IrcClient *client, U8 *msg=NULL) 530 { 531 IrcChannel *channel = IrcGetChanByName(channame); 532 if (channel) 533 { 534 if(IrcChannelUserDel(channel, client)); 535 IrcClientPart(channame, client, msg); 536 } 537 } 538 539 U0 IrcChannelsQuit(IrcClient *client, U8 *msg=NULL) 540 { 541 IrcChannel *channel = channel_head->next; 542 while (channel) 543 { 544 if(IrcChannelUserDel(channel, client)) 545 IrcClientQuit(channel->name, client, msg); 546 channel = channel->next; 547 } 548 }