unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
send.c (37874B)
1 /* 2 * Unreal Internet Relay Chat Daemon, src/send.c 3 * Copyright (C) 1990 Jarkko Oikarinen and 4 * University of Oulu, Computing Center 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 1, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 /* send.c 2.32 2/28/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen */ 22 23 /** @file 24 * @brief The sending functions to users, channels, servers. 25 */ 26 27 #include "unrealircd.h" 28 29 /* Some forward declarions are needed */ 30 void vsendto_one(Client *to, MessageTag *mtags, const char *pattern, va_list vl); 31 void vsendto_prefix_one(Client *to, Client *from, MessageTag *mtags, const char *pattern, va_list vl) __attribute__((format(printf,4,0))); 32 static int vmakebuf_local_withprefix(char *buf, size_t buflen, Client *from, const char *pattern, va_list vl) __attribute__((format(printf,4,0))); 33 34 #define ADD_CRLF(buf, len) { if (len > 510) len = 510; \ 35 buf[len++] = '\r'; buf[len++] = '\n'; buf[len] = '\0'; } while(0) 36 37 /* These are two local (static) buffers used by the various send functions */ 38 static char sendbuf[2048]; 39 static char sendbuf2[MAXLINELENGTH]; 40 41 /** This is used to ensure no duplicate messages are sent 42 * to the same server uplink/direction. In send functions 43 * that deliver to multiple users or servers the value is 44 * increased by 1 and then for each delivery in the loop 45 * it is checked if to->direction->local->serial == current_serial 46 * and if so, sending is skipped. 47 */ 48 MODVAR int current_serial; 49 50 /** Mark the socket as "dead". 51 * This is used when exit_client() cannot be used from the 52 * current code because doing so would be (too) unexpected. 53 * The socket is closed later in the main loop. 54 * NOTE: this function is becoming less important, now that 55 * exit_client() will not actively free the client. 56 * Still, sometimes we need to use dead_socket() 57 * since we don't want to be doing IsDead() checks after 58 * each and every sendto...(). 59 * @param to Client to mark as dead 60 * @param notice The quit reason to use 61 */ 62 int dead_socket(Client *to, const char *notice) 63 { 64 DBufClear(&to->local->recvQ); 65 DBufClear(&to->local->sendQ); 66 67 if (IsDeadSocket(to)) 68 return -1; /* already pending to be closed */ 69 70 SetDeadSocket(to); 71 72 /* We may get here because of the 'CPR' in check_deadsockets(). 73 * In which case, we return -1 as well. 74 */ 75 if (to->local->error_str) 76 return -1; /* don't overwrite & don't send multiple times */ 77 78 if (!IsUser(to) && !IsUnknown(to) && !IsRPC(to) && !IsControl(to) && !IsClosing(to)) 79 { 80 /* Looks like a duplicate error message to me? 81 * If so, remove it here. 82 */ 83 unreal_log(ULOG_ERROR, "link", "LINK_CLOSING", to, 84 "Link to server $client.details closed: $reason", 85 log_data_string("reason", notice)); 86 } 87 safe_strdup(to->local->error_str, notice); 88 return -1; 89 } 90 91 /** This is a callback function from the event loop. 92 * All it does is call send_queued(). 93 */ 94 void send_queued_cb(int fd, int revents, void *data) 95 { 96 Client *to = data; 97 98 if (IsDeadSocket(to)) 99 return; 100 101 send_queued(to); 102 } 103 104 /** This function is called when queued data might be ready to be 105 * sent to the client. It is called from the event loop and also 106 * a couple of other places (such as when closing the connection). 107 */ 108 int send_queued(Client *to) 109 { 110 int len, rlen; 111 dbufbuf *block; 112 int want_read; 113 114 /* We NEVER write to dead sockets. */ 115 if (IsDeadSocket(to)) 116 return -1; 117 118 while (DBufLength(&to->local->sendQ) > 0) 119 { 120 block = container_of(to->local->sendQ.dbuf_list.next, dbufbuf, dbuf_node); 121 len = block->size; 122 123 /* Deliver it and check for fatal error.. */ 124 if ((rlen = deliver_it(to, block->data, len, &want_read)) < 0) 125 { 126 char buf[256]; 127 snprintf(buf, 256, "Write error: %s", STRERROR(ERRNO)); 128 return dead_socket(to, buf); 129 } 130 dbuf_delete(&to->local->sendQ, rlen); 131 if (want_read) 132 { 133 /* SSL_write indicated that it cannot write data at this 134 * time and needs to READ data first. Let's stop talking 135 * to the user and ask to notify us when there's data 136 * to read. 137 */ 138 fd_setselect(to->local->fd, FD_SELECT_READ, send_queued_cb, to); 139 fd_setselect(to->local->fd, FD_SELECT_WRITE, NULL, to); 140 break; 141 } 142 /* Restore handling of reads towards read_packet(), since 143 * it may be overwritten in an earlier call to send_queued(), 144 * to handle reads by send_queued_cb(), see directly above. 145 */ 146 fd_setselect(to->local->fd, FD_SELECT_READ, read_packet, to); 147 if (rlen < len) 148 { 149 /* incomplete write due to EWOULDBLOCK, reschedule */ 150 fd_setselect(to->local->fd, FD_SELECT_WRITE, send_queued_cb, to); 151 break; 152 } 153 } 154 155 /* Nothing left to write, stop asking for write-ready notification. */ 156 if ((DBufLength(&to->local->sendQ) == 0) && (to->local->fd >= 0)) 157 fd_setselect(to->local->fd, FD_SELECT_WRITE, NULL, to); 158 159 return (IsDeadSocket(to)) ? -1 : 0; 160 } 161 162 /** Mark "to" with "there is data to be send" */ 163 void mark_data_to_send(Client *to) 164 { 165 if (!IsDeadSocket(to) && (to->local->fd >= 0) && (DBufLength(&to->local->sendQ) > 0)) 166 { 167 fd_setselect(to->local->fd, FD_SELECT_WRITE, send_queued_cb, to); 168 } 169 } 170 171 /** Send data to clients, servers, channels, IRCOps, etc. 172 * There are a lot of send functions. The most commonly functions 173 * are: sendto_one() to send to an individual user, 174 * sendnumeric() to send a numeric to an individual user 175 * and sendto_channel() to send a message to a channel. 176 * @defgroup SendFunctions Send functions 177 * @{ 178 */ 179 180 /** Send a message to a single client. 181 * This function is used quite a lot, after sendnumeric() it is the most-used send function. 182 * @param to The client to send to 183 * @param mtags Any message tags associated with this message (can be NULL) 184 * @param pattern The format string / pattern to use. 185 * @param ... Format string parameters. 186 * @section sendto_one_examples Examples 187 * @subsection sendto_one_mode_r Send "MODE -r" 188 * This will send the `:serv.er.name MODE yournick -r` message. 189 * Note that it will send only this message to illustrate the sendto_one() function. 190 * It does *not* set anyone actually -r. 191 * @code 192 * sendto_one(client, NULL, ":%s MODE %s :-r", me.name, client->name); 193 * @endcode 194 */ 195 void sendto_one(Client *to, MessageTag *mtags, FORMAT_STRING(const char *pattern), ...) 196 { 197 va_list vl; 198 va_start(vl, pattern); 199 vsendto_one(to, mtags, pattern, vl); 200 va_end(vl); 201 } 202 203 /** Send a message to a single client - va_list variant. 204 * This function is similar to sendto_one() except that it 205 * doesn't use varargs but uses a va_list instead. 206 * Generally this function is NOT used outside send.c, so not by modules. 207 * @param to The client to send to 208 * @param mtags Any message tags associated with this message (can be NULL) 209 * @param pattern The format string / pattern to use. 210 * @param vl Format string parameters. 211 */ 212 void vsendto_one(Client *to, MessageTag *mtags, const char *pattern, va_list vl) 213 { 214 const char *mtags_str = mtags ? mtags_to_string(mtags, to) : NULL; 215 216 /* Need to ignore -Wformat-nonliteral here */ 217 #if defined(__GNUC__) 218 #pragma GCC diagnostic push 219 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 220 #endif 221 ircvsnprintf(sendbuf, sizeof(sendbuf)-3, pattern, vl); 222 #if defined(__GNUC__) 223 #pragma GCC diagnostic pop 224 #endif 225 226 if (BadPtr(mtags_str)) 227 { 228 /* Simple message without message tags */ 229 sendbufto_one(to, sendbuf, 0); 230 } else { 231 /* Message tags need to be prepended */ 232 snprintf(sendbuf2, sizeof(sendbuf2)-3, "@%s %s", mtags_str, sendbuf); 233 sendbufto_one(to, sendbuf2, 0); 234 } 235 } 236 237 238 /** Send a line buffer to the client. 239 * This function is used (usually indirectly) for pretty much all 240 * cases where a line needs to be sent to a client. 241 * @param to The client to which the buffer should be send. 242 * @param msg The message. 243 * @param quick Normally set to 0, see the notes. 244 * @note 245 * - Neither 'to' or 'msg' may be NULL. 246 * - If quick is set to 0 then the length is calculated, 247 * the string is cut off at 510 bytes if needed, and 248 * CR+LF is added if needed. 249 * If quick is >0 then it is assumed the message already 250 * is within boundaries and passed all safety checks and 251 * contains CR+LF at the end. This if, for example, used in 252 * channel broadcasts to save some CPU cycles. It is NOT 253 * recommended as normal usage since you need to be very 254 * careful to take everything into account, including side- 255 * effects not mentioned here. 256 */ 257 void sendbufto_one(Client *to, char *msg, unsigned int quick) 258 { 259 int len; 260 Hook *h; 261 Client *intended_to = to; 262 263 if (to->direction) 264 to = to->direction; 265 if (IsDeadSocket(to)) 266 return; /* This socket has already 267 been marked as dead */ 268 if (to->local->fd < 0) 269 { 270 /* This is normal when 'to' was being closed (via exit_client 271 * and close_connection) --Run 272 */ 273 return; 274 } 275 276 /* Unless 'quick' is set, we do some safety checks, 277 * cut the string off at the appropriate place and add 278 * CR+LF if needed (nearly always). 279 */ 280 if (!quick) 281 { 282 char *p = msg; 283 if (*msg == '@') 284 { 285 /* The message includes one or more message tags: 286 * Spec-wise the rules allow about 8K for message tags 287 * (MAXTAGSIZE) and then 512 bytes for 288 * the remainder of the message (BUFSIZE). 289 */ 290 p = strchr(msg+1, ' '); 291 if (!p) 292 { 293 unreal_log(ULOG_WARNING, "send", "SENDBUFTO_ONE_MALFORMED_MSG", to, 294 "Malformed message to $client: $buf", 295 log_data_string("buf", msg)); 296 return; 297 } 298 if (p - msg > MAXTAGSIZE) 299 { 300 unreal_log(ULOG_WARNING, "send", "SENDBUFTO_ONE_OVERSIZED_MSG", to, 301 "Oversized message to $client (length $length): $buf", 302 log_data_integer("length", p - msg), 303 log_data_string("buf", msg)); 304 return; 305 } 306 p++; /* skip space character */ 307 } 308 len = strlen(p); 309 if (!len || (p[len - 1] != '\n')) 310 { 311 if (len > 510) 312 len = 510; 313 p[len++] = '\r'; 314 p[len++] = '\n'; 315 p[len] = '\0'; 316 } 317 len = strlen(msg); /* (note: we could use pointer jugling to avoid a strlen here) */ 318 } else { 319 len = quick; 320 } 321 322 if (len >= MAXLINELENGTH) 323 { 324 unreal_log(ULOG_WARNING, "send", "SENDBUFTO_ONE_OVERSIZED_MSG2", to, 325 "Oversized message to $client (length $length): $buf", 326 log_data_integer("length", len), 327 log_data_string("buf", msg)); 328 #ifdef DEBUGMODE 329 abort(); 330 #else 331 return; 332 #endif 333 } 334 335 if (IsMe(to)) 336 { 337 char tmp_msg[500]; 338 339 strlcpy(tmp_msg, msg, sizeof(tmp_msg)); 340 stripcrlf(tmp_msg); 341 unreal_log(ULOG_WARNING, "send", "SENDBUFTO_ONE_ME_MESSAGE", to, 342 "Trying to send data to myself: $buf", 343 log_data_string("buf", tmp_msg)); 344 return; 345 } 346 347 for (h = Hooks[HOOKTYPE_PACKET]; h; h = h->next) 348 { 349 (*(h->func.intfunc))(&me, to, intended_to, &msg, &len); 350 if (!msg) 351 return; 352 } 353 354 #if defined(RAWCMDLOGGING) 355 { 356 char copy[512], *p; 357 strlcpy(copy, msg, len > sizeof(copy) ? sizeof(copy) : len); 358 p = strchr(copy, '\n'); 359 if (p) *p = '\0'; 360 p = strchr(copy, '\r'); 361 if (p) *p = '\0'; 362 unreal_log(ULOG_INFO, "rawtraffic", "TRAFFIC_OUT", to, 363 "-> $client: $data", 364 log_data_string("data", copy)); 365 } 366 #endif 367 368 if (DBufLength(&to->local->sendQ) > get_sendq(to)) 369 { 370 unreal_log(ULOG_INFO, "flood", "SENDQ_EXCEEDED", to, 371 "Flood of queued data to $client.details [$client.ip] exceeds class::sendq ($sendq > $class_sendq) (Too much data queued to be sent to this client)", 372 log_data_integer("sendq", DBufLength(&to->local->sendQ)), 373 log_data_integer("class_sendq", get_sendq(to))); 374 dead_socket(to, "Max SendQ exceeded"); 375 return; 376 } 377 378 dbuf_put(&to->local->sendQ, msg, len); 379 380 /* 381 * Update statistics. The following is slightly incorrect 382 * because it counts messages even if queued, but bytes 383 * only really sent. Queued bytes get updated in SendQueued. 384 */ 385 // FIXME: something is wrong here, I think we do double counts, either in message or in traffic, I forgot.. CHECK !!!! 386 to->local->traffic.messages_sent++; 387 me.local->traffic.messages_sent++; 388 389 /* Previously we ran send_queued() here directly, but that is 390 * a bad idea, CPU-wise. So now we just mark the client indicating 391 * that there is data to send. 392 */ 393 if (IsControl(to)) 394 send_queued(to); /* send this one ASAP */ 395 else 396 mark_data_to_send(to); 397 } 398 399 /** A single function to send data to a channel. 400 * Previously there were 6 different functions to send channel data, 401 * now there is 1 single function. This also means that you most 402 * likely will pass NULL or 0 as some parameters. 403 * @param channel The channel to send to 404 * @param from The source of the message 405 * @param skip The client to skip (can be NULL). 406 * Note that if you specify a remote link then 407 * you usually mean xyz->direction and not xyz. 408 * @param member_modes Require any of the member_modes to be set (eg: "o"), or NULL to skip this check. 409 * @param clicap Client capability the recipient should have 410 * (this only works for local clients, we will 411 * always send the message to remote clients and 412 * assume the server there will handle it) 413 * @param sendflags Determines whether to send the message to local/remote users 414 * @param mtags The message tags to attach to this message 415 * @param pattern The pattern (eg: ":%s PRIVMSG %s :%s") 416 * @param ... The parameters for the pattern. 417 * @note For all channel messages, it is important to attach the correct 418 * message tags (mtags) via a new_message() call, as can be seen 419 * in the example. 420 * @section sendto_channel_examples Examples 421 * @subsection sendto_channel_privmsg Send a PRIVMSG to a channel 422 * This command will send the message "Hello everyone!!!" to the channel when executed. 423 * @code 424 * CMD_FUNC(cmd_sayhello) 425 * { 426 * MessageTag *mtags = NULL; 427 * Channel *channel = NULL; 428 * if ((parc < 2) || BadPtr(parv[1])) 429 * { 430 * sendnumeric(client, ERR_NEEDMOREPARAMS, "SAYHELLO"); 431 * return; 432 * } 433 * channel = find_channel(parv[1]); 434 * if (!channel) 435 * { 436 * sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]); 437 * return; 438 * } 439 * new_message(client, recv_mtags, &mtags); 440 * sendto_channel(channel, client, client->direction, NULL, 0, 441 * SEND_LOCAL|SEND_REMOTE, mtags, 442 * ":%s PRIVMSG %s :Hello everyone!!!", 443 * client->name, channel->name); 444 * free_message_tags(mtags); 445 * } 446 * @endcode 447 */ 448 void sendto_channel(Channel *channel, Client *from, Client *skip, 449 char *member_modes, long clicap, int sendflags, 450 MessageTag *mtags, 451 FORMAT_STRING(const char *pattern), ...) 452 { 453 va_list vl; 454 Member *lp; 455 Client *acptr; 456 char member_modes_ext[64]; 457 458 if (member_modes) 459 { 460 channel_member_modes_generate_equal_or_greater(member_modes, member_modes_ext, sizeof(member_modes_ext)); 461 member_modes = member_modes_ext; 462 } 463 464 ++current_serial; 465 for (lp = channel->members; lp; lp = lp->next) 466 { 467 acptr = lp->client; 468 469 /* Skip sending to 'skip' */ 470 if ((acptr == skip) || (acptr->direction == skip)) 471 continue; 472 /* Don't send to deaf clients (unless 'senddeaf' is set) */ 473 if (IsDeaf(acptr) && (sendflags & SKIP_DEAF)) 474 continue; 475 /* Don't send to NOCTCP clients */ 476 if (has_user_mode(acptr, 'T') && (sendflags & SKIP_CTCP)) 477 continue; 478 /* Now deal with 'member_modes' (if not NULL) */ 479 if (member_modes && !check_channel_access_member(lp, member_modes)) 480 continue; 481 /* Now deal with 'clicap' (if non-zero) */ 482 if (clicap && MyUser(acptr) && ((clicap & CAP_INVERT) ? HasCapabilityFast(acptr, clicap) : !HasCapabilityFast(acptr, clicap))) 483 continue; 484 485 if (MyUser(acptr)) 486 { 487 /* Local client */ 488 if (sendflags & SEND_LOCAL) 489 { 490 va_start(vl, pattern); 491 vsendto_prefix_one(acptr, from, mtags, pattern, vl); 492 va_end(vl); 493 } 494 } 495 else 496 { 497 /* Remote client */ 498 if (sendflags & SEND_REMOTE) 499 { 500 /* Message already sent to remote link? */ 501 if (acptr->direction->local->serial != current_serial) 502 { 503 va_start(vl, pattern); 504 vsendto_prefix_one(acptr, from, mtags, pattern, vl); 505 va_end(vl); 506 507 acptr->direction->local->serial = current_serial; 508 } 509 } 510 } 511 } 512 513 if (sendflags & SEND_REMOTE) 514 { 515 /* For the remaining uplinks that we have not sent a message to yet... 516 * broadcast-channel-messages=never: don't send it to them 517 * broadcast-channel-messages=always: always send it to them 518 * broadcast-channel-messages=auto: send it to them if the channel is set +H (history) 519 */ 520 521 if ((iConf.broadcast_channel_messages == BROADCAST_CHANNEL_MESSAGES_ALWAYS) || 522 ((iConf.broadcast_channel_messages == BROADCAST_CHANNEL_MESSAGES_AUTO) && has_channel_mode(channel, 'H'))) 523 { 524 list_for_each_entry(acptr, &server_list, special_node) 525 { 526 if ((acptr == skip) || (acptr->direction == skip)) 527 continue; /* still obey this rule.. */ 528 if (acptr->direction->local->serial != current_serial) 529 { 530 va_start(vl, pattern); 531 vsendto_prefix_one(acptr, from, mtags, pattern, vl); 532 va_end(vl); 533 534 acptr->direction->local->serial = current_serial; 535 } 536 } 537 } 538 } 539 } 540 541 /** Send a message to a server, taking into account server options if needed. 542 * @param one The client to skip (can be NULL) 543 * @param servercaps Server capabilities which must be present (OR'd together, if multiple) 544 * @param noservercaps Server capabilities which must NOT be present (OR'd together, if multiple) 545 * @param mtags The message tags to attach to this message. 546 * @param format The format string / pattern, such as ":%s NICK %s". 547 * @param ... The parameters for the format string 548 */ 549 void sendto_server(Client *one, unsigned long servercaps, unsigned long noservercaps, MessageTag *mtags, FORMAT_STRING(const char *format), ...) 550 { 551 Client *acptr; 552 553 /* noone to send to.. */ 554 if (list_empty(&server_list)) 555 return; 556 557 list_for_each_entry(acptr, &server_list, special_node) 558 { 559 va_list vl; 560 561 if (one && acptr == one->direction) 562 continue; 563 564 if (servercaps && !CHECKSERVERPROTO(acptr, servercaps)) 565 continue; 566 567 if (noservercaps && CHECKSERVERPROTO(acptr, noservercaps)) 568 continue; 569 570 va_start(vl, format); 571 vsendto_one(acptr, mtags, format, vl); 572 va_end(vl); 573 } 574 } 575 576 /** Send a message to all local users on all channels where 577 * the user 'user' is on. 578 * This is used for events such as a nick change and quit. 579 * @param user The user and source of the message. 580 * @param skip The client to skip (can be NULL) 581 * @param clicap Client capability the recipient should have 582 * (this only works for local clients, we will 583 * always send the message to remote clients and 584 * assume the server there will handle it) 585 * @param mtags The message tags to attach to this message. 586 * @param pattern The pattern (eg: ":%s NICK %s"). 587 * @param ... The parameters for the pattern. 588 */ 589 void sendto_local_common_channels(Client *user, Client *skip, long clicap, MessageTag *mtags, FORMAT_STRING(const char *pattern), ...) 590 { 591 va_list vl; 592 Membership *channels; 593 Member *users; 594 Client *acptr; 595 596 /* We now create the buffer _before_ we send it to the clients. -- Syzop */ 597 *sendbuf = '\0'; 598 va_start(vl, pattern); 599 vmakebuf_local_withprefix(sendbuf, sizeof sendbuf, user, pattern, vl); 600 va_end(vl); 601 602 ++current_serial; 603 604 if (user->user) 605 { 606 for (channels = user->user->channel; channels; channels = channels->next) 607 { 608 for (users = channels->channel->members; users; users = users->next) 609 { 610 acptr = users->client; 611 612 if (!MyConnect(acptr)) 613 continue; /* only process local clients */ 614 615 if (acptr->local->serial == current_serial) 616 continue; /* message already sent to this client */ 617 618 if (clicap && ((clicap & CAP_INVERT) ? HasCapabilityFast(acptr, clicap) : !HasCapabilityFast(acptr, clicap))) 619 continue; /* client does not have the specified capability */ 620 621 if (acptr == skip) 622 continue; /* the one to skip */ 623 624 if (!user_can_see_member(acptr, user, channels->channel)) 625 continue; /* the sending user (quit'ing or nick changing) is 'invisible' -- skip */ 626 627 acptr->local->serial = current_serial; 628 sendto_one(acptr, mtags, "%s", sendbuf); 629 } 630 } 631 } 632 } 633 634 /** Send a QUIT message to all local users on all channels where 635 * the user 'user' is on. 636 * This is used for events such as a nick change and quit. 637 * @param user The user and source of the message. 638 * @param skip The client to skip (can be NULL) 639 * @param clicap Client capability the recipient should have 640 * (this only works for local clients, we will 641 * always send the message to remote clients and 642 * assume the server there will handle it) 643 * @param mtags The message tags to attach to this message. 644 * @param pattern The pattern (eg: ":%s NICK %s"). 645 * @param ... The parameters for the pattern. 646 */ 647 void quit_sendto_local_common_channels(Client *user, MessageTag *mtags, const char *reason) 648 { 649 va_list vl; 650 Membership *channels; 651 Member *users; 652 Client *acptr; 653 char sender[512]; 654 MessageTag *m; 655 const char *real_quit_reason = NULL; 656 657 m = find_mtag(mtags, "unrealircd.org/real-quit-reason"); 658 if (m && m->value) 659 real_quit_reason = m->value; 660 661 if (IsUser(user)) 662 { 663 snprintf(sender, sizeof(sender), "%s!%s@%s", 664 user->name, user->user->username, GetHost(user)); 665 } else { 666 strlcpy(sender, user->name, sizeof(sender)); 667 } 668 669 ++current_serial; 670 671 if (user->user) 672 { 673 for (channels = user->user->channel; channels; channels = channels->next) 674 { 675 for (users = channels->channel->members; users; users = users->next) 676 { 677 acptr = users->client; 678 679 if (!MyConnect(acptr)) 680 continue; /* only process local clients */ 681 682 if (acptr->local->serial == current_serial) 683 continue; /* message already sent to this client */ 684 685 if (!user_can_see_member(acptr, user, channels->channel)) 686 continue; /* the sending user (QUITing) is 'invisible' -- skip */ 687 688 acptr->local->serial = current_serial; 689 if (!reason) 690 sendto_one(acptr, mtags, ":%s QUIT", sender); 691 else if (!IsOper(acptr) || !real_quit_reason) 692 sendto_one(acptr, mtags, ":%s QUIT :%s", sender, reason); 693 else 694 sendto_one(acptr, mtags, ":%s QUIT :%s", sender, real_quit_reason); 695 } 696 } 697 } 698 } 699 700 /* 701 ** send a msg to all ppl on servers/hosts that match a specified mask 702 ** (used for enhanced PRIVMSGs) 703 ** 704 ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de) 705 */ 706 707 static int match_it(Client *one, const char *mask, int what) 708 { 709 switch (what) 710 { 711 case MATCH_HOST: 712 return match_simple(mask, one->user->realhost); 713 case MATCH_SERVER: 714 default: 715 return match_simple(mask, one->user->server); 716 } 717 } 718 719 /** Send to all clients which match the mask. 720 * This function is rarely used. 721 * @param one The client to skip 722 * @param from The sender 723 * @param mask The mask 724 * @param what One of MATCH_HOST or MATCH_SERVER 725 * @param mtags Message tags associated with the message 726 * @param pattern Format string 727 * @param ... Parameters to the format string 728 */ 729 void sendto_match_butone(Client *one, Client *from, const char *mask, int what, 730 MessageTag *mtags, FORMAT_STRING(const char *pattern), ...) 731 { 732 va_list vl; 733 Client *acptr; 734 char cansendlocal, cansendglobal; 735 736 if (MyConnect(from)) 737 { 738 cansendlocal = (ValidatePermissionsForPath("chat:notice:local",from,NULL,NULL,NULL)) ? 1 : 0; 739 cansendglobal = (ValidatePermissionsForPath("chat:notice:global",from,NULL,NULL,NULL)) ? 1 : 0; 740 } 741 else 742 cansendlocal = cansendglobal = 1; 743 744 /* To servers... */ 745 if (cansendglobal) 746 { 747 char buf[512]; 748 749 va_start(vl, pattern); 750 ircvsnprintf(buf, sizeof(buf), pattern, vl); 751 va_end(vl); 752 753 sendto_server(one, 0, 0, mtags, "%s", buf); 754 } 755 756 /* To local clients... */ 757 if (cansendlocal) 758 { 759 list_for_each_entry(acptr, &lclient_list, lclient_node) 760 { 761 if (!IsMe(acptr) && (acptr != one) && IsUser(acptr) && match_it(acptr, mask, what)) 762 { 763 va_start(vl, pattern); 764 vsendto_prefix_one(acptr, from, mtags, pattern, vl); 765 va_end(vl); 766 } 767 } 768 } 769 } 770 771 /** Send a message to all locally connected users with specified user mode. 772 * @param umodes The umode that the recipient should have set (one of UMODE_) 773 * @param pattern The format string / pattern to use. 774 * @param ... Format string parameters. 775 */ 776 void sendto_umode(int umodes, FORMAT_STRING(const char *pattern), ...) 777 { 778 va_list vl; 779 Client *acptr; 780 char nbuf[1024]; 781 782 list_for_each_entry(acptr, &lclient_list, lclient_node) 783 if (IsUser(acptr) && (acptr->umodes & umodes) == umodes) 784 { 785 ircsnprintf(nbuf, sizeof(nbuf), ":%s NOTICE %s :", me.name, acptr->name); 786 strlcat(nbuf, pattern, sizeof nbuf); 787 788 va_start(vl, pattern); 789 vsendto_one(acptr, NULL, nbuf, vl); 790 va_end(vl); 791 } 792 } 793 794 /** Send a message to all users with specified user mode (local & remote users). 795 * @param umodes The umode that the recipient should have set (one of UMODE_*) 796 * @param pattern The format string / pattern to use. 797 * @param ... Format string parameters. 798 */ 799 void sendto_umode_global(int umodes, FORMAT_STRING(const char *pattern), ...) 800 { 801 va_list vl; 802 Client *acptr; 803 Umode *um; 804 char nbuf[1024]; 805 char modestr[128]; 806 char *p; 807 808 /* Convert 'umodes' (int) to 'modestr' (string) */ 809 get_usermode_string_raw_r(umodes, modestr, sizeof(modestr)); 810 811 list_for_each_entry(acptr, &lclient_list, lclient_node) 812 { 813 if (IsUser(acptr) && (acptr->umodes & umodes) == umodes) 814 { 815 ircsnprintf(nbuf, sizeof(nbuf), ":%s NOTICE %s :", me.name, acptr->name); 816 strlcat(nbuf, pattern, sizeof nbuf); 817 818 va_start(vl, pattern); 819 vsendto_one(acptr, NULL, nbuf, vl); 820 va_end(vl); 821 } else 822 if (IsServer(acptr) && *modestr) 823 { 824 snprintf(nbuf, sizeof(nbuf), ":%s SENDUMODE %s :%s", me.id, modestr, pattern); 825 va_start(vl, pattern); 826 vsendto_one(acptr, NULL, nbuf, vl); 827 va_end(vl); 828 } 829 } 830 } 831 832 /** Send CAP DEL and CAP NEW notification to clients supporting it. 833 * This function is mostly meant to be used by the CAP and SASL modules. 834 * @param add Whether the CAP token is added (1) or removed (0) 835 * @param token The CAP token 836 */ 837 void send_cap_notify(int add, const char *token) 838 { 839 Client *client; 840 ClientCapability *clicap = ClientCapabilityFindReal(token); 841 long CAP_NOTIFY = ClientCapabilityBit("cap-notify"); 842 843 list_for_each_entry(client, &lclient_list, lclient_node) 844 { 845 if (HasCapabilityFast(client, CAP_NOTIFY)) 846 { 847 if (add) 848 { 849 const char *args = NULL; 850 if (clicap) 851 { 852 if (clicap->visible && !clicap->visible(client)) 853 continue; /* invisible CAP, so don't announce it */ 854 if (clicap->parameter && (client->local->cap_protocol >= 302)) 855 args = clicap->parameter(client); 856 } 857 if (!args) 858 { 859 sendto_one(client, NULL, ":%s CAP %s NEW :%s", 860 me.name, (*client->name ? client->name : "*"), token); 861 } else { 862 sendto_one(client, NULL, ":%s CAP %s NEW :%s=%s", 863 me.name, (*client->name ? client->name : "*"), token, args); 864 } 865 } else { 866 sendto_one(client, NULL, ":%s CAP %s DEL :%s", 867 me.name, (*client->name ? client->name : "*"), token); 868 } 869 } 870 } 871 } 872 873 /* Prepare buffer based on format string and 'from' for LOCAL delivery. 874 * The prefix (:<something>) will be expanded to :nick!user@host if 'from' 875 * is a person, taking into account the rules for hidden/cloaked host. 876 * NOTE: Do not send this prepared buffer to remote clients or servers, 877 * they do not want or need the expanded prefix. In that case, simply 878 * use ircvsnprintf() directly. 879 */ 880 static int vmakebuf_local_withprefix(char *buf, size_t buflen, Client *from, const char *pattern, va_list vl) 881 { 882 int len; 883 884 /* This expands the ":%s " part of the pattern 885 * into ":nick!user@host ". 886 * In case of a non-person (server) it doesn't do 887 * anything since no expansion is needed. 888 */ 889 if (from && from->user && !strncmp(pattern, ":%s ", 4)) 890 { 891 va_arg(vl, char *); /* eat first parameter */ 892 893 *buf = ':'; 894 strlcpy(buf+1, from->name, buflen-1); 895 896 if (IsUser(from)) 897 { 898 char *username = from->user->username; 899 char *host = GetHost(from); 900 901 if (*username) 902 { 903 strlcat(buf, "!", buflen); 904 strlcat(buf, username, buflen); 905 } 906 if (*host) 907 { 908 strlcat(buf, "@", buflen); 909 strlcat(buf, host, buflen); 910 } 911 } 912 /* Now build the remaining string */ 913 #if defined(__GNUC__) 914 #pragma GCC diagnostic push 915 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 916 #endif 917 ircvsnprintf(buf + strlen(buf), buflen - strlen(buf), &pattern[3], vl); 918 #if defined(__GNUC__) 919 #pragma GCC diagnostic pop 920 #endif 921 } 922 else 923 { 924 ircvsnprintf(buf, buflen, pattern, vl); 925 } 926 927 len = strlen(buf); 928 ADD_CRLF(buf, len); 929 return len; 930 } 931 932 /** Send a message to a client, expand the sender prefix. 933 * This is similar to sendto_one() except that it will expand the source part :%s 934 * to :nick!user@host if needed, while with sendto_one() it will be :nick. 935 * @param to The client to send to 936 * @param mtags Any message tags associated with this message (can be NULL) 937 * @param pattern The format string / pattern to use. 938 * @param ... Format string parameters. 939 */ 940 void sendto_prefix_one(Client *to, Client *from, MessageTag *mtags, FORMAT_STRING(const char *pattern), ...) 941 { 942 va_list vl; 943 va_start(vl, pattern); 944 vsendto_prefix_one(to, from, mtags, pattern, vl); 945 va_end(vl); 946 } 947 948 /** Send a message to a single client, expand the sender prefix - va_list variant. 949 * This is similar to vsendto_one() except that it will expand the source part :%s 950 * to :nick!user@host if needed, while with sendto_one() it will be :nick. 951 * This function is also similar to sendto_prefix_one(), but this is the va_list 952 * variant. 953 * @param to The client to send to 954 * @param mtags Any message tags associated with this message (can be NULL) 955 * @param pattern The format string / pattern to use. 956 * @param ... Format string parameters. 957 */ 958 void vsendto_prefix_one(Client *to, Client *from, MessageTag *mtags, const char *pattern, va_list vl) 959 { 960 const char *mtags_str = mtags ? mtags_to_string(mtags, to) : NULL; 961 962 if (to && from && MyUser(to) && from->user) 963 vmakebuf_local_withprefix(sendbuf, sizeof(sendbuf)-3, from, pattern, vl); 964 else 965 ircvsnprintf(sendbuf, sizeof(sendbuf)-3, pattern, vl); 966 967 if (BadPtr(mtags_str)) 968 { 969 /* Simple message without message tags */ 970 sendbufto_one(to, sendbuf, 0); 971 } else { 972 /* Message tags need to be prepended */ 973 snprintf(sendbuf2, sizeof(sendbuf2)-3, "@%s %s", mtags_str, sendbuf); 974 sendbufto_one(to, sendbuf2, 0); 975 } 976 } 977 978 /** Introduce user to all other servers, except the one to skip. 979 * @param one Server to skip (can be NULL) 980 * @param client Client to introduce 981 * @param umodes User modes of client 982 */ 983 void sendto_serv_butone_nickcmd(Client *one, MessageTag *mtags, Client *client, const char *umodes) 984 { 985 Client *acptr; 986 987 list_for_each_entry(acptr, &server_list, special_node) 988 { 989 if (one && acptr == one->direction) 990 continue; 991 992 sendto_one_nickcmd(acptr, mtags, client, umodes); 993 } 994 } 995 996 /** Introduce user to a server. 997 * @param server Server to send to (locally connected!) 998 * @param client Client to introduce 999 * @param umodes User modes of client 1000 */ 1001 void sendto_one_nickcmd(Client *server, MessageTag *mtags, Client *client, const char *umodes) 1002 { 1003 char *vhost; 1004 char mtags_generated = 0; 1005 1006 if (!*umodes) 1007 umodes = "+"; 1008 1009 if (SupportVHP(server)) 1010 { 1011 if (IsHidden(client)) 1012 vhost = client->user->virthost; 1013 else 1014 vhost = client->user->realhost; 1015 } 1016 else 1017 { 1018 if (IsHidden(client) && client->umodes & UMODE_SETHOST) 1019 vhost = client->user->virthost; 1020 else 1021 vhost = "*"; 1022 } 1023 1024 if (mtags == NULL) 1025 { 1026 moddata_add_s2s_mtags(client, &mtags); 1027 mtags_generated = 1; 1028 } 1029 1030 sendto_one(server, mtags, 1031 ":%s UID %s %d %lld %s %s %s %s %s %s %s %s :%s", 1032 client->uplink->id, client->name, client->hopcount, 1033 (long long)client->lastnick, 1034 client->user->username, client->user->realhost, client->id, 1035 client->user->account, umodes, vhost, getcloak(client), 1036 encode_ip(client->ip), client->info); 1037 1038 if (mtags_generated) 1039 safe_free_message_tags(mtags); 1040 } 1041 1042 /* sidenote: sendnotice() and sendtxtnumeric() assume no client or server 1043 * has a % in their nick, which is a safe assumption since % is illegal. 1044 */ 1045 1046 /** Send a server notice to a client. 1047 * @param to The client to send to 1048 * @param pattern The format string / pattern to use. 1049 * @param ... Format string parameters. 1050 */ 1051 void sendnotice(Client *to, FORMAT_STRING(const char *pattern), ...) 1052 { 1053 static char realpattern[1024]; 1054 va_list vl; 1055 char *name = *to->name ? to->name : "*"; 1056 1057 ircsnprintf(realpattern, sizeof(realpattern), ":%s NOTICE %s :%s", me.name, name, pattern); 1058 1059 va_start(vl, pattern); 1060 vsendto_one(to, NULL, realpattern, vl); 1061 va_end(vl); 1062 } 1063 1064 /** Send MultiLine list as a notice, one for each line. 1065 * @param client The client to send to 1066 * @param m The MultiLine list. 1067 */ 1068 void sendnotice_multiline(Client *client, MultiLine *m) 1069 { 1070 for (; m; m = m->next) 1071 sendnotice(client, "%s", m->line); 1072 } 1073 1074 /** Send numeric message to a client - format to user specific needs. 1075 * This will ignore the numeric definition of src/numeric.c and always send ":me.name numeric clientname " 1076 * followed by the pattern and format string you choose. 1077 * @param to The recipient 1078 * @param mtags NULL, or NULL-terminated array of message tags 1079 * @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c 1080 * @param pattern The format string / pattern to use. 1081 * @param ... Format string parameters. 1082 * @note Don't forget to add a colon if you need it (eg `:%%s`), this is a common mistake. 1083 */ 1084 void sendtaggednumericfmt(Client *to, MessageTag *mtags, int numeric, FORMAT_STRING(const char *pattern), ...) 1085 { 1086 va_list vl; 1087 char realpattern[512]; 1088 1089 snprintf(realpattern, sizeof(realpattern), ":%s %.3d %s %s", me.name, numeric, to->name[0] ? to->name : "*", pattern); 1090 1091 va_start(vl, pattern); 1092 vsendto_one(to, mtags, realpattern, vl); 1093 va_end(vl); 1094 } 1095 1096 /** Send text numeric message to a client (RPL_TEXT). 1097 * Because this generic output numeric is commonly used it got a special function for it. 1098 * @param to The recipient 1099 * @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c 1100 * @param pattern The format string / pattern to use. 1101 * @param ... Format string parameters. 1102 * @note Don't forget to add a colon if you need it (eg `:%%s`), this is a common mistake. 1103 */ 1104 void sendtxtnumeric(Client *to, FORMAT_STRING(const char *pattern), ...) 1105 { 1106 static char realpattern[1024]; 1107 va_list vl; 1108 1109 ircsnprintf(realpattern, sizeof(realpattern), ":%s %d %s :%s", me.name, RPL_TEXT, to->name, pattern); 1110 1111 va_start(vl, pattern); 1112 vsendto_one(to, NULL, realpattern, vl); 1113 va_end(vl); 1114 } 1115 1116 /** Build buffer in order to send a numeric message to a client - rarely used. 1117 * @param buf The buffer that should be used 1118 * @param buflen The size of the buffer 1119 * @param to The recipient 1120 * @param numeric The numeric, one of RPL_* or ERR_*, see src/numeric.c 1121 * @param pattern The format string / pattern to use. 1122 * @param ... Format string parameters. 1123 */ 1124 void buildnumericfmt(char *buf, size_t buflen, Client *to, int numeric, FORMAT_STRING(const char *pattern), ...) 1125 { 1126 va_list vl; 1127 char realpattern[512]; 1128 1129 snprintf(realpattern, sizeof(realpattern), ":%s %.3d %s %s", me.name, numeric, to->name[0] ? to->name : "*", pattern); 1130 1131 va_start(vl, pattern); 1132 /* Need to ignore -Wformat-nonliteral here */ 1133 #if defined(__GNUC__) 1134 #pragma GCC diagnostic push 1135 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1136 #endif 1137 vsnprintf(buf, buflen, realpattern, vl); 1138 #if defined(__GNUC__) 1139 #pragma GCC diagnostic pop 1140 #endif 1141 va_end(vl); 1142 } 1143 1144 void add_nvplist_numeric_fmt(NameValuePrioList **lst, int priority, const char *name, Client *to, int numeric, FORMAT_STRING(const char *pattern), ...) 1145 { 1146 va_list vl; 1147 char realpattern[512], buf[512]; 1148 1149 snprintf(realpattern, sizeof(realpattern), ":%s %.3d %s %s", me.name, numeric, to->name[0] ? to->name : "*", pattern); 1150 1151 va_start(vl, pattern); 1152 /* Need to ignore -Wformat-nonliteral here */ 1153 #if defined(__GNUC__) 1154 #pragma GCC diagnostic push 1155 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 1156 #endif 1157 vsnprintf(buf, sizeof(buf), realpattern, vl); 1158 #if defined(__GNUC__) 1159 #pragma GCC diagnostic pop 1160 #endif 1161 va_end(vl); 1162 1163 add_nvplist(lst, priority, name, buf); 1164 } 1165 1166 /* Send raw data directly to socket, bypassing everything. 1167 * Looks like an interesting function to call? NO! STOP! 1168 * Don't use this function. It may only be used by the initial 1169 * Z-Line check via the codepath to banned_client(). 1170 * YOU SHOULD NEVER USE THIS FUNCTION. 1171 * If you want to send raw data (without formatting) to a client 1172 * then have a look at sendbufto_one() instead. 1173 * 1174 * Side-effects: 1175 * Too many to list here. Only in the early accept code the 1176 * "if's" and side-effects are under control. 1177 * 1178 * By the way, did I already mention that you SHOULD NOT USE THIS 1179 * FUNCTION? ;) 1180 */ 1181 void send_raw_direct(Client *user, FORMAT_STRING(const char *pattern), ...) 1182 { 1183 va_list vl; 1184 int sendlen; 1185 1186 *sendbuf = '\0'; 1187 va_start(vl, pattern); 1188 sendlen = vmakebuf_local_withprefix(sendbuf, sizeof(sendbuf), user, pattern, vl); 1189 va_end(vl); 1190 (void)send(user->local->fd, sendbuf, sendlen, 0); 1191 } 1192 1193 /** @} */