📄 message.c
字号:
#include "global.h"
/*write the information of registered users
* into a file*/
void log_user()
{
int i;
FILE * fp;
bucket_list p;
if((fp = fopen(LOG_FILE,"w"))==NULL) {
log_err("open log file fail.\n");
}
for(i = 0; i < SIZE; i++) {
p = hash_table[i];
while(p) {
fprintf(fp,"%s\n",p->name);
p = p->next;
}
}
fclose(fp);
}
/*divide the string received into
* several parts*/
int divide_mes(char * mes,char * str)
{
int i = 0;
int j = 0;
int k = 0;
int n;
int connfd;
n = sscanf(str,"%d,",&connfd);
if(n < 1) {
return -1;
}
/*skip the length of the message*/
while(str[i] && str[i]!=',')
i++;
i++;
/*skip the blank and tab*/
while(str[i] && (str[i]==' '||str[i]=='\t'))
i++;
/*get the content of the message*/
while(str[i]) mes[k++] = str[i++];
mes[k] = '\0';
return connfd;
}
/*delete the user from the hash table*/
void do_quit(int connfd)
{
int h = hash_int(connfd);
char * name;
bucket_list l;
addr_list a1;
addr_list a2;
pthread_mutex_lock(&addr_mutex);
a1 = addr_table[h];
a2 = a1;
while((a2 != NULL) && (a2->connfd != connfd)) {
a1 = a2;
a2 = a2->next;
}
if(!a1) {
pthread_mutex_unlock(&addr_mutex);
return;
}
else if(a1 == a2)
addr_table[h] = a1->next;
else
a1->next = a2->next;
close(a2->connfd);
pthread_mutex_lock(&name_mutex);
l = hash_lookup(a2->name);
if(l)
l->connfd = -1;
#ifdef Debug
print_l();
#endif
pthread_mutex_unlock(&name_mutex);
a2->name = NULL;
free(a2);
#ifdef Debug
print_a();
#endif
pthread_mutex_unlock(&addr_mutex);
pthread_mutex_lock(&num_mutex);
on_line_num--;
pthread_mutex_unlock(&num_mutex);
}
/*send the message to the specified user*/
void do_sent_by_name(char * mes,int connfd)
{
int i = 0;
int j = 0;
int b;
int fd;
char name[MAX_NAME];
char sname[MAX_NAME];
char error[MAX_ERR];
bucket_list l;
addr_list a;
while(mes[i]==' '||mes[i]=='\t')
i++;
/*get the user name that the user
* want the message to send to*/
while(mes[i]&&mes[i]!='\n'&&j<MAX_NAME&&
mes[i]!=' ' &&mes[i]!='\t')
name[j++] = mes[i++];
name[j] = '\0';
if(j == 0)
return;
while(mes[i]=='\n'||mes[i]==' '||
mes[i]=='\t')
i++;
pthread_mutex_lock(&addr_mutex);
a = addr_lookup(connfd);
if(a == NULL||a->name == NULL) {
pthread_mutex_unlock(&addr_mutex);
return;
}
else {
strcpy(sname,a->name);
}
pthread_mutex_unlock(&addr_mutex);
pthread_mutex_lock(&name_mutex);
l = hash_lookup(name);
if(l == NULL) {
b = 0;
} else {
if(l->connfd == -1)
b = 1;
else {
fd = l->connfd;
b = 2;
}
}
pthread_mutex_unlock(&name_mutex);
switch(b) {
case 0:
case 1:
sprintf(error,"ERR: 103");
send_mes(error,connfd);
break;
case 2:
send_name_mes(&mes[i],sname,fd);
send_name_mes(&mes[i],sname,connfd);
break;
default:
break;
}
}
/*send the user on line to the command sender*/
void do_who(int connfd)
{
int i;
char temp[MAX_MES];
addr_list a;
temp[0] = '\0';
pthread_mutex_lock(&addr_mutex);
for(i = 0; i < SIZE; i++) {
a = addr_table[i];
while(a) {
if(a->name != NULL) {
strcat(temp,a->name);
strcat(temp,"@");
strcat(temp,a->host);
strcat(temp," ");
}
a = a->next;
}
}
pthread_mutex_unlock(&addr_mutex);
send_mes(temp,connfd);
}
void do_help(int connfd)
{
char help1[] = "/log filename\n This command causes scc to log all input to the\n file filename and display it on the terminal. If no\n filename is given,scc.log will be used.\n/quit\n cause the client to terminate the connection.\n";
char help2[] = "/m nickname message\n sent the message only to \"nickname\"\n/nick nickname\n let the user to change its nickname to \"nickname\"\n/who\n to send the list of on line clients to the requester\n/help\n send the available commands to the requester\n";
send_mes(help1,connfd);
send_mes(help2,connfd);
}
/*change the nick name*/
void do_change_name(char * mes,int connfd)
{
int i = 0;
int j = 0;
char newname[MAX_NAME];
char error[MAX_ERR];
char * nn;
addr_list a;
bucket_list l1;
bucket_list l2;
while(mes[i]==' '||mes[i]=='\t')
i++;
while(mes[i]&&mes[i]!='\n'&&j<MAX_NAME&&
mes[i]!=' ' &&mes[i]!='\t')
newname[j++] = mes[i++];
if(j == MAX_NAME) {
sprintf(error,"server: new name is too long!");
send_mes(error,connfd);
return;
}
newname[j] = '\0';
nn = (char *)malloc(sizeof(char)*(strlen(newname)+2));
if(!nn) {
log_err("malloc fail!");
}
strcpy(nn,newname);
pthread_mutex_lock(&addr_mutex);
pthread_mutex_lock(&name_mutex);
l1 = hash_lookup(newname);
a = addr_lookup(connfd);
l2 = hash_lookup(a->name);
/*the name already used*/
if(l1&&l1->connfd >= 0) {
sprintf(error,"server: the name is already used by another user!");
send_mes(error,connfd);
pthread_mutex_unlock(&name_mutex);
pthread_mutex_unlock(&addr_mutex);
return;
/*change user*/
} else if(l1&&l1->connfd < 0) {
l1->connfd = connfd;
l2->connfd = -1;
a->name = l1->name;
free(nn);
/*change the user name */
} else {
free(l2->name);
l2->name = nn;
a->name = nn;
}
#ifdef Debug
print_a();
print_l();
#endif
log_user();
pthread_mutex_unlock(&name_mutex);
pthread_mutex_unlock(&addr_mutex);
}
/*classify the message into several types
* 1 stand for "send nickname"
* 2 stand for control message
* 3 stand for normal message*/
int classify_mes(char * mes,int connfd)
{
int i = 0;
int j = 0;
int len = 0;
//char temp[MAX_MES];
//receive_mes(temp,connfd);
if(mes[0] == '/')
return 2;
else if(strncmp(mes,"SCC Version:",12)==0)
return 4;
else if(strncmp(mes,"nickname:",9)==0)
return 1;
else
return 3;
}
/*case 1*/
/*the client send its nickname to the server
* max user check and nickname in used check
* are do here,also version handshake do here*/
void nickname_mes(char * mes,int connfd)
{
int i = 0;
int j = 0;
int b;
char addname[MAX_NAME];
char error[MAX_ERR];
char temp[MAX_MES];
char * name;
host_list * h;
bucket_list l;
addr_list a;
i += 9;
/*skip blank and tab*/
while(mes[i]==' '||mes[i]=='\t')
i++;
/*record the message*/
while(mes[i]!='\0'&&j<MAX_NAME)
addname[j++] = mes[i++];
addname[j] = '\0';
if(j == 0)
return;
/*nickname too long*/
else if(j == MAX_NAME) {
sprintf(temp,"server: nickname too long.");
send_mes(temp,connfd);
return;
}
h = host_delete(connfd);
pthread_mutex_lock(&addr_mutex);
pthread_mutex_lock(&name_mutex);
/*look up the name in the hash table*/
l = hash_lookup(addname);
/*if the name already in the table*/
if(l) {
/*the name is in use*/
if(l->connfd >= 0) {
pthread_mutex_unlock(&name_mutex);
pthread_mutex_unlock(&addr_mutex);
pthread_mutex_lock(&num_mutex);
on_line_num--;
pthread_mutex_unlock(&num_mutex);
free(h->host);
free(h);
sprintf(error,"ERR: 101");
send_mes(error,connfd);
return;
} else {
l->connfd = connfd;
a = addr_insert(connfd);
a->name = l->name;
a->host = h->host;
free(h);
}
} else {/*the name is not in the table*/
name=(char *)malloc((strlen(addname)+2)*sizeof(char));
if(name == NULL) {
pthread_mutex_unlock(&name_mutex);
pthread_mutex_unlock(&addr_mutex);
log_err("malloc fail!");
}
strcpy(name,addname);
l = hash_insert(name);
a = addr_insert(connfd);
l->connfd = connfd;
a->name = l->name;
a->connfd = connfd;
a->host = h->host;
free(h);
}
#ifdef Debug
print_a();
print_l();
#endif
log_user();
pthread_mutex_unlock(&name_mutex);
pthread_mutex_unlock(&addr_mutex);
}
/*case 3*/
/*send the message to all the user connected
* to the server*/
void message_mes(char * mes,int connfd)
{
int i;
addr_list a1;
addr_list a2;
pthread_mutex_lock(&addr_mutex);
a2 = addr_lookup(connfd);
if(!a2||!a2->name) {
pthread_mutex_unlock(&addr_mutex);
return;
}
for(i = 0; i < SIZE; i++) {
a1 = addr_table[i];
while(a1) {
if(a1->name != NULL)
send_name_mes(mes,a2->name,a1->connfd);
a1 = a1->next;
}
}
pthread_mutex_unlock(&addr_mutex);
}
/*case 2*/
/*handle the control message*/
void control_mes(char * mes,int connfd)
{
int i = 0;
char error[MAX_ERR];
if(strncmp(&mes[i],"/m",2)==0) {
do_sent_by_name(&mes[i+2],connfd);
} else if(strncmp(&mes[i],"/who",4)==0) {
do_who(connfd);
} else if(strncmp(&mes[i],"/nick",5)==0) {
do_change_name(&mes[i+5],connfd);
} else if(strncmp(&mes[i],"/help",5)==0) {
do_help(connfd);
} else if(strncmp(&mes[i],"/quit",5)==0) {
do_quit(connfd);
} else {
sprintf(error,"ERR: 102");
send_mes(error,connfd);
}
}
/*handle all kinds of message here*/
void handle_mes(char * str)
{
int b;
int t,n;
int connfd,len = 0;
//char mes1[MAX_MES];
char mes2[MAX_MES];
char error[MAX_ERR];
len = strlen(str);
if(len < 2||len>MAX_MES)
return;
if((connfd = divide_mes(mes2,str)) < 0)
return;
free(str);
t = classify_mes(mes2,connfd);
switch(t) {
case 1:
nickname_mes(mes2,connfd);
break;
case 2:
control_mes(mes2,connfd);
break;
case 3:
message_mes(mes2,connfd);
break;
default:
return;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -