void ChannelHandler::LeaveParticipant (const QString& nick,
			const QString& msg)
	{
		if (Nick2Entry_.contains (nick))
			MakeLeaveMessage (nick, msg);
		RemoveUserFromChannel (nick);
	}
	void ChannelHandler::KickParticipant (const QString& nick,
			const QString& target, const QString& msg)
	{
		if (Nick2Entry_.contains (target))
			MakeKickMessage (target, msg, nick);

		RemoveUserFromChannel (target);
	}
Exemple #3
0
void *ClientHandler(void *arg)
{
  struct Client *client = ((struct Client *)arg);
  struct ParsedMsg msg;
  struct ThreadChanList chan_list = {
    .size = 0,
    .head = NULL
  };
  struct NamesList name_list = {
    .cnt = 0,
    .names = NULL
  };
  struct ThreadChanNode *ptr;
  union RegistrationFlags registered;
  char raw_msg[IRC_MSG_MAX_LENGTH];
  char send_msg[IRC_MSG_MAX_LENGTH];
  char nick[IRC_NICK_BUF_SIZE];
  ssize_t bytes = 0;
  int ret, index, connect = 1;

  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  registered.clear = 0;

  memset(&raw_msg, 0, IRC_MSG_MAX_LENGTH);
  memset(&send_msg, 0, IRC_MSG_MAX_LENGTH);
  memset(&nick, 0, IRC_NICK_BUF_SIZE);

  while (registered.flags.user == 0 || registered.flags.nick == 0) {
    if ((bytes = IRCMsgRead(client->sockfd, raw_msg)) < 0) {
      printf("disconnected\n");
      registered.flags.fail = 1;
      break;
    }
    printf("raw: %s len %d\n", raw_msg, (int)strlen(raw_msg));
    FormParsedMsg(raw_msg, &msg);
    if (msg.cmd == IRCCMD_QUIT) {
      registered.flags.fail = 1;
      break;
    }
    if (msg.cmd == IRCCMD_USER) {
      registered.flags.user = 1;
    } else if (msg.cmd == IRCCMD_NICK) {
      if (registered.flags.nick == 0) {
        if (msg.cnt == 0) {
          ErrorHandler(client->sockfd, 
                      "nickname parameter expected for a command and isn’t found",
                       ERR_ERRONEUSNICKNAME);
          FreeParsedMsg(&msg);
          continue;
        }
        if (msg.params[0][0] == '#') {
          ErrorHandler(client->sockfd, "USER NICK: #nick invalid", ERR_ERRONEUSNICKNAME);
          FreeParsedMsg(&msg);
          continue;
        }
        ret = AddUser(&all_users, msg.params[0], client);
        if (ret == IRC_USERERR_EXIST) {
          ErrorHandler(client->sockfd, "NICK already exist", ERR_NICKNAMEINUSE);
          FreeParsedMsg(&msg);
          continue;
        } else if (ret == IRC_USERERR_NICK) {
          ErrorHandler(client->sockfd, "INCORRECT NICK", ERR_ERRONEUSNICKNAME);
          FreeParsedMsg(&msg);
          continue;
        } else if (ret == IRC_USERERR_CANTADD) {
          ErrorHandler(client->sockfd, "USER CANT ADD", IRC_USERERR_CANTADD);
          FreeParsedMsg(&msg);
          registered.flags.fail = 1;
        } else {
          ret = strlen(msg.params[0]);
          strncpy(nick, msg.params[0], ret);
          nick[ret] = '\0';
          registered.flags.nick = 1;
        }
      }
    }
    FreeParsedMsg(&msg);
  }

  if (!registered.flags.fail) {
    printf("successfully registered user: %s\n", nick);
    registered.flags.connect = 1;
    SendConnectMsg(&all_users, "anonimus", nick);
    while (registered.flags.connect) {
      if ((bytes = IRCMsgRead(client->sockfd, raw_msg)) < 0) {
        printf("disconnected...\n");
        break;
      }
      printf("raw: %s len %d\n", raw_msg, (int)strlen(raw_msg));
      FormParsedMsg(raw_msg, &msg);

      switch (msg.cmd) {
        case IRCCMD_QUIT:
          registered.flags.connect = 0;
          if (chan_list.size > 0) {
            if (FormSendMsg(send_msg, raw_msg, nick) == 0) {
              for (ptr = chan_list.head; ptr != NULL; ptr = ptr->next) 
                SendMsgToChannel(&all_chan, &all_users, ptr->chan, nick,
                              send_msg);
            }
          }
          break;

        case IRCCMD_JOIN:
          if (msg.cnt == 0) {
            ErrorHandler(client->sockfd, "JOIN :Not enough parameters", ERR_NEEDMOREPARAMS);
            break;
          }
          if (AddUserToChannel(&all_chan, &all_users, msg.params[0],
                              nick) == 0) {
            printf("add to channel %s\n", msg.params[0]);
            chan_list.head = ThrListAddFront(&chan_list, msg.params[0]);
            if (FormSendMsg(send_msg, raw_msg, nick) == 0) {
              SendMsgToUser(&all_users, nick, send_msg);
              SendMsgToChannel(&all_chan, &all_users, msg.params[0], nick,
                              send_msg);
              pthread_mutex_lock(&client->send_lock);
              SendChannelList(client->sockfd, &all_chan, &all_users, msg.params[0],
                              "anonimous", nick);
              pthread_mutex_unlock(&client->send_lock);
            }
            printf("TO SEND: %s\n", send_msg);
          } else {
            ErrorHandler(client->sockfd, "Cannot join channel", ERR_CHANNELISFULL);
          }
          break;

        case IRCCMD_PRIVMSG:
          if (msg.cnt == 2) {
            if (FormSendMsg(send_msg, raw_msg, nick) == 0) {
              printf("send %s \nto %s len %d\n", send_msg, msg.params[0],
                                                (int)strlen(send_msg));
              if (msg.params[0][0] == '#') {
                if (SendMsgToChannel(&all_chan, &all_users, msg.params[0], 
                                    nick, send_msg) < 0)
                  perror("SendMsgToChannel failed");
              } else {
                SendMsgToUser(&all_users, msg.params[0], send_msg);
              }
            }
          } else {
            ErrorHandler(client->sockfd, "PRIVMSG: Not enough parameters", 
                        ERR_NEEDMOREPARAMS);
          }
          break;

        case IRCCMD_PART:
          if (msg.cnt != 0) {
            RemoveUserFromChannel(&all_chan, &all_users, msg.params[0], nick);
            chan_list.head = DeleteThrNode(&chan_list, msg.params[0]);
            if (FormSendMsg(send_msg, raw_msg, nick) == 0) {
              printf("send %s \nto %s\n", send_msg, msg.params[0]);
              SendMsgToUser(&all_users, nick, send_msg);
              SendMsgToChannel(&all_chan, &all_users, msg.params[0], nick, send_msg);
            }
          } else {
            ErrorHandler(client->sockfd, "PART: Not enough parameters", 
                        ERR_NEEDMOREPARAMS);
          }
          break;
         
        case IRCCMD_NICK:
          if (msg.cnt == 0) {
            ErrorHandler(client->sockfd, 
                      "nickname parameter expected for a command and isn’t found",
                       ERR_ERRONEUSNICKNAME);
            break;
          }
          if (msg.params[0][0] == '#') {
            ErrorHandler(client->sockfd, "USER NICK: #nick invalid", ERR_ERRONEUSNICKNAME);
            break; 
          }
          printf("change nick: %s -> %s\n", nick, msg.params[0]);
          if ((ret = RenameUser(&all_users, nick, msg.params[0])) == 0) { 
            ret = strlen(msg.params[0]);
            strncpy(nick, msg.params[0], ret);
            nick[ret] = '\0';
          } else {
            if (ret == IRC_USERERR_NOTFOUND) {
              ErrorHandler(client->sockfd, "User not found", ERR_NICKNAMEINUSE);
            } else if (ret == IRC_USERERR_EXIST) {
              ErrorHandler(client->sockfd, "User exist", ERR_NICKNAMEINUSE);
            }
            perror("RenameUser");
          }
          break;
          
        case IRCCMD_PING:
          if (msg.cnt == 1) {
            FormPongMsg(&all_users, raw_msg, nick);
          } else {
            ErrorHandler(client->sockfd, "PING: Not enough parameters", 
                        ERR_NEEDMOREPARAMS);
          }
          break;
        case IRCCMD_LIST:
          pthread_mutex_lock(&client->send_lock);
          SendAllChannelsList(client->sockfd, &all_chan, &all_users,
                              "anonimous", nick);
          pthread_mutex_unlock(&client->send_lock);
          break;
      }
      FreeParsedMsg(&msg);
    }
  }
  if (chan_list.size > 0) {
    for (ptr = chan_list.head; ptr != NULL; ptr = ptr->next)
      RemoveUserFromChannel(&all_chan, &all_users, ptr->chan, nick);
    FreeThreadList(&chan_list);
  }

  close(client->sockfd);
  pthread_mutex_destroy(&client->send_lock);
  DelUser(&all_users, (const char *)&nick);
  free(client);
  printf("close... %s\n", nick);
  pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
  struct sockaddr_in ser_addr, cl_addr;
  struct Client *client;
  int listen_sock, connect;
  socklen_t len = (socklen_t)sizeof(struct sockaddr_in);
  pthread_attr_t attr;
  const int kOpt = 1;

  if (argc != 3) {
    printf("format: IP_ADDR PORT\n");
    exit(EXIT_FAILURE);
  }

  listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  if (listen_sock < 0) {
    perror("socket");
    exit(EXIT_FAILURE);
  }

  if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &kOpt,
                sizeof(int)) == -1 ) {
    perror("setsockopt");
  }

  memset(&ser_addr, 0, sizeof(struct sockaddr_in));

  ser_addr.sin_family = AF_INET;
  ser_addr.sin_addr.s_addr = inet_addr(argv[1]);
  ser_addr.sin_port = htons(atoi(argv[2]));

  if (bind(listen_sock, (struct sockaddr *)&ser_addr, len) < 0) {
    perror("bind");
    exit(EXIT_FAILURE);
  }

  if (listen(listen_sock, IRC_USERS_MAX) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
  }

  UsersInit(&all_users);
  ChannelsInit(&all_chan);
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  while (1) {
    if ((connect = accept(listen_sock, (struct sockaddr *)&cl_addr,
                          &len)) > 0) {
      client = (struct Client *)malloc(sizeof(struct Client));
      if (client == NULL) {
        perror("malloc");
        break;
      }
      client->sockfd = connect;
      pthread_mutex_init(&client->send_lock, NULL);
      if (pthread_create(&(client->pid), &attr, ClientHandler,
                        (void *)client) > 0) {
        perror("pthread_create");
      }

    } else {
      perror("accept");
      break;
    }
  }
  pthread_attr_destroy(&attr);
  pthread_mutex_destroy(&all_users.lock);
  pthread_mutex_destroy(&all_chan.lock);
  close(listen_sock);
  return 0;
}