Государственный комитет Российской Федерации по телекоммуникациям Сибирский государственный университет телекоммуникаций и информатики КУРСОВАЯ РАБОТА По дисциплине “Операционные системы” Тема работы Игра «Многопоточный чат на основе сокетов» Работу выполнили студенты 2 курса группы П-91 Балабко Р. С. Воронцов С. В. Скворец В. В. Работу проверил Малков Е. А. Работа защищена «___» __________2010г. С оценкой «__________» Новосибирск 2011 Содержание 2 Цель курсовой работы 3 Поставленные задачи 3 Реализация проекта 4 Листинг 7 2 Цель работы Целью нашего курсового проекта являлось создание многопользовательского многопоточного (создание потоков и их синхронизация) чата на основе сокетов (в частности нами использовался Windows Socket). Второстепенными целями проекта (поставленными нами) стали реализация клиентской области при помощи Win API и создание полнофункционально сервера обработчика событий. Поставленные задачи - Создание простой в использовании программы-клиента с помощью Win Form и Win API. - Создание стабильно функционирующего сервера, обменивающегося сообщениями с программой-клиентом и обрабатывающего описанные в них события. - Создание канальной системы общения между программой-клиентом и программойсервером используя socket и протокол TCP. 3 Реализация проекта Программу-клиент ( далее «клиент» ) разрабатывали Балабко Роман, Скворец Вячеслав. Программу-сервер ( далее «сервер» ) разрабатывали Воронцов Сергей, Скворец Вячеслав. Реализация программы-сервера: Cервер функционирует по принципу получил-обработал-отправил. 1) Получил: Сервер работает в синхронном режиме ( т.е ожидает приема сообщения от клиента). Т.к для каждого клиента создается отдельный поток, то не возникает ошибки с приемом сообщения, т.к однозначно известно кто прислал сообщение. 2) Обработал: два типа сообщений – служебные и пользовательские. Служебные: а) «auth nickname password» - авторизация пользователя на сервере. Пользователю присваивается ник, изменяются его атрибуты в зависимости от статуса на канале. б) «reg nickname password» - регистрирует nickname на сервере, связывает его с присланным паролем. Все регистрируемые пользователи хранятся в файлах. в) «join NameChannel password[optional]» - заходит на канал с именем NameChannel. Если такой канал не был создан ранее, сервер создает его. г) «quit NameChannel» - пользователь покидает канал с заданным именем. д) «creg NameChannel password[optional]» - регистрирует канал NameChannel и, если указан пароль, связывает его с каналом. Пользователь, регистрирующий канал становится его администратором. Пользовательские: «msg NameChannel Nickname message» - сообщение(message) всем пользователям, присутствующим в данный момент на канале NameChannel от Nickname. 3) Отправил: сообщения делятся по типу: а) «upd NameChannel UserNick(1) Atr(1) … UserNick(n) Atr(n) » - сообщение генерируется и отсылается пользователю при его заходе на какой-либо канал. В сообщении указывается название канала, перечисляются присутствующие на нём в данный момент пользователи и их атрибуты. б) «jin NameChannel UserNick Atr» - уведомление о входе на канал нового пользователя, посылается всем пользователям на канал NameChannel. в) «qit NameChannel UserNick» - уведомление о выходе с канала пользователя, посылается всем пользователям канала NameChannel. г) «cng LastUserNick NewUserNick NewAtr» - сообщение генерируется при изменении статуса пользователя на канале, либо при изменении ника пользователя. д) «nck NewNickname» - уведомление об изменении имени, приходит только пользователю совершившему запрос типа «auth» или «reg». е) «msg NameChannel UserNick message» - сообщение на канале. ж) «0..9»- уведомление о результате операции, совершённой пользователем. 4 На сервере используется два типа структур: База Клиентов (userinfo), База Каналов (channelBase). Одна запись клиента выглядит следующим образом: struct userinfo { SOCKET cSocket; // Сокет клиента sockaddr_in cAddr; // Ip адрес. struct hostent *hst; int cAddr_size; char nickname[32]; // имя пользователя char LastNickname[32]; // предыдущее имя пользователя int Attribute; // глобальный атрибут bool connect; // триггер 1-подключен, 0-отключен char nameCh[32][128]; // название каналов пользователя. }; Вся база клиентов выглядит следующим образом : userinfo ui[N]; - где N это максимальное количество клиентов. Одна запись канала выглядит следующим образом: struct channelHead { char nameChannel[128]; // название канала int szUser; // количество пользователей на канале bool usingCh; // триггер 1-канал активе,0-канал не активен. bool registration;// триггер 1-канал зарегистрирован,0-канал не зарегистрирован channelUser *user; // указатель на двухсвязный список содержащий пользователей. }; struct channelUser { int posUser; // хранит позицию клиента в базе клиентов int Attribute; // хранит атрибут клиента на конкретном канале channelUser *pNext,*pLost; // указатели на предыдущего и следующего клиента. }; Вся база каналов выглядит следующим образом: channelHead channelBase[N]; - где N максимальное число каналов. Для синхронизации каналов используется массив мютексов. Также на сервере ведётся архив действий и отображение текущего состояние сервера. 5 Реализация программы-клиента: Оформление клиентской области Для создания клиентской области мы использовали некоторые стандартные объекты Win API, такие как Button, Edit, Static, IpAddress, Combobox и TreeView (вывод каналов и пользователей, присутствующих на них, переключение между каналами). Основные компоненты клиентской области: 1) Edit для просмотра истории сообщений. Является недоступным для ввода текста. 2) Edit для ввода сообщения. Ограничен лимитом в 100 символов. 3) IpAddress. Окно для ввода Ip-адреса при подсоединении к серверу. Становится невидимым после успешного подсоединения. 4) Combobox. Совместно с объектом Button, располагающимся чуть ниже на клиентской области, реализует меню. Меню состоит из шести пунктов – вход в профиль, регистрация профиля, выход из профиля, вход в канал, регистрация канала и выход с канала. 5) TreeView. Реализует дерево просмотра каналов. Родительскими узлами являются сами каналы, а корневыми узлами для каждого канала являются имена пользователей присутствующих на нём. Дерево обновляется каждый раз после получения сообщений типа «upd», «jin», «qit», «cng» и «nck». Переключение между каналами происходит при помощи щелчка левой кнопкой мыши по имени канала в дереве. Весь текст из поля истории сообщений при этом заносится в текстовый файл (имя файла совпадает с именем канала), а в поле истории сообщений записывается текст из соответствующего каналу, на который совершён переход, файла (если такого файла нет, то поле истории сообщений становится пустым). Поля для ввода ника, имени канала и паролей ограничены лимитом в 25 символов. Объекты типа MessageBox уведомляют пользователя о результате совершённой операции. Работа клиентского приложения Для работы клиента создаётся два потока. В первом потоке происходит получение сообщений от сервера, после чего обновляется клиентская область. В этом потоке происходит обновление дерева каналов и истории сообщений. Во втором потоке происходит получение сообщений от пользователя, после которых выполняются все остальные действия связанные с изменением клиентской области и по большей части с отправлением сообщений серверу. Для того чтобы войти в чат, пользователь должен первым делом подсоединиться к серверу. После успешного контакта пользователю присваивается стандартный ник (Default со свободным номером), и пользователь сразу оказывается на общем канале сервера с названием ALL. В таком режиме пользователь может создавать, но не регистрировать, каналы, а также заходить на уже созданные, но незапароленные, ну и соответственно писать сообщения на этих на каналах, активно переключаясь между ними. Пользователь может зарегистрироваться, либо войти уже под зарегистрированным профилем. При этом из активного профиля можно совершить выход и войти ещё раз под другим. Дерево каналов при выходе из профиля очищается, и пользователь вновь оказывается в такой же ситуации, в какой он был до авторизации. 6 Листинг Код «программы-сервера»: pLine.h void GetNickPass(char *buff,char *nickname,char *password) { int val = 0 ; int i,k=0; for ( i = 0 ; i < (int)strlen(buff) ; i++ ) { if (val==2 ) break; if (buff[i]!=' ' && val == 0 ) { nickname[k]=buff[i]; k++; } if (buff[i]!=' ' && val == 1 ) { password[k] = buff[i]; k++; } if ( val == 0 && buff[i]==' ' ) {nickname[k]=0;k=0;val=1;continue;} if ( val == 1 && buff[i]==' ' ) {password[k]=0;k=0;val=2;continue;} } if (val == 0 ) { nickname[k-1]=0; password[0]=0; } if (password[k-1] == 10 ) password[k-1]=0; else password[k]=0; } char *RegistrationNickName(char *buff,int posUser) { FILE *f; int i = 0, k=0 ; char nickname[64]; char password[32]; int val = 0 ; char filebuff[1024]; filebuff[0]=0; for (i = 4 ; i < (int)strlen(buff) ; i++ ) { if (val == 2 ) break; if ( val == 0 && buff[i]!=' ' ) { nickname[k] = buff[i]; k++; } if ( val == 1 && buff[i]!=' ') { password[k] = buff[i]; k++; } if ( buff[i]==' ' && val == 0 ) {nickname[k]=0; val++;k=0;continue;} if ( buff[i]==' ' && val == 1 ) {password[k]=0; val++;k=0;continue;} } password[k]=0; strcpy(filebuff,pathNick); strcat(filebuff,nickname); f=fopen(filebuff,"r"); if (f==0 ) { f=fopen(filebuff,"w"); fprintf(f,"%s",password); fclose(f); sprintf(filebuff,"Registration Complete %s\n",nickname ); AddLogFile(logName,filebuff); printf("Slot[%i] %s->%s\n",posUser,ui[posUser].nickname,nickname); strcpy(ui[posUser].LastNickname,ui[posUser].nickname); 7 strcpy(ui[posUser].nickname,nickname); ui[posUser].Attribute = AS_USER ; SendNewNickname(posUser); return "0"; // все окей } else { return "1"; // такой ник уже занят } } char *AuthNickName(char *buff,int posUser) { FILE *f; char nickname[32]; char password[32]; char psAuth[32]; char filebuff[128]; int i ; GetNickPass(buff,nickname,password); strcpy(filebuff,pathNick); strcat(filebuff,nickname); f=fopen(filebuff,"r"); if ( f == 0 ) {return "3";} // нет регистрации fscanf(f,"%s",&psAuth); if (strcmp(psAuth,password)==0 ) { for ( i = 0 ; i < 1024 ; i ++ ) { if (ui[i].connect == true && strcmp(nickname,ui[i].nickname)==0 ) return "4"; // уже вошел } printf("Slot[%i] %s->%s\n",posUser,ui[posUser].nickname,nickname); strcpy(ui[posUser].LastNickname,ui[posUser].nickname); strcpy(ui[posUser].nickname,nickname); ui[posUser].Attribute = AS_USER ; SendNewNickname(posUser); return "0"; // все окей } return "2"; // неверный пароль } void Logout(int posUser) { char v[12]; char name[32]; printf("Slot[%i] %s->",posUser,ui[posUser].nickname); strcpy(name,"Default"); strcat(name,_itoa(posUser,v,10)); strcpy(ui[posUser].LastNickname,name); strcpy(ui[posUser].nickname,name); printf("%s\n",ui[posUser].nickname); ui[posUser].Attribute= AS_NUSER; SendNewNickname(posUser); } char *ProcLine(char *buff,int posUser,int *only) { char bf[128]; int i = 0 ; int k = 0 ; *only = -2; if (strncmp(buff,"reg",3)==0 ) { strcpy(buff,RegistrationNickName(buff,posUser)); *only = 1 ; } if (strncmp(buff,"auth",4)==0 ) { for ( i = 5 ; i < (int)strlen(buff) ; i ++ ) { buff[k]=buff[i]; k++; } buff[k]=0; strcpy(buff,AuthNickName(buff,posUser)); *only = 1 ; } if (strncmp(buff,"msg",3)==0) { 8 *only=0; return buff; } if (strncmp(buff,"quit",4)==0 ) { strcpy(bf, GetNameChannel(buff,5)); QuitUserChannel(bf,posUser); *only = -1; } if (strncmp(buff,"join",4)==0) { for ( i = 5 ; i < (int)strlen(buff) ; i ++ ) { buff[k]=buff[i]; k++; } buff[k]=0; JoinChannel(buff,posUser); *only = -1 ; } if (strncmp(buff,"creg",4)==0) { for ( i = 5 ; i < (int)strlen(buff) ; i ++ ) { buff[k]=buff[i]; k++; } buff[k]=0; RegistrationChannel(buff,posUser); *only = -1 ; } if ( strcmp(buff,"exit")==0) { *only = -3 ; } if (strcmp(buff,"logout")==0) { Logout(posUser); } strcat(buff,(char *)&razd); return buff; } connection.h struct userinfo { SOCKET cSocket; sockaddr_in cAddr; struct hostent *hst; int cAddr_size; char nickname[32]; char LastNickname[32]; int Attribute; bool connect; char nameCh[32][128]; }; userinfo ui[N]; void InitUserInfo() { int i; for (i=0;i<1024;i++)ui[i].connect=false; } int SearchPosUI() { int i; for (i=0;i<1024;i++) { if (ui[i].connect==false ) {ui[i].connect=true; return i ; } } return -1; } 9 void ThreadUser(void *p) { int i=0; int j = 0 ; int bytes_recv; char buff[2048]; char nameChannel[128]; int only = 0 ; bool join = false; SendNewNickname((int)p); NewUserChannel("ALL",(int)p,S_USER,1); while (1) { bytes_recv=recv(ui[(int)p].cSocket,&buff[0],sizeof(buff),0); printf("Slot[%i] -> Message : %s\n",(int)p,buff); if (strcmp(buff,ui[(int)p].nickname)==0) bytes_recv = -1 ; if (bytes_recv!=-1) strcpy(buff,ProcLine(buff,(int)p,&only)); if (bytes_recv == -1 || bytes_recv==SOCKET_ERROR || only == -3 ) { for ( i = 0 ; i < 32 ; i ++ ) { if ( ui[(int)p].nameCh[i][0] !=0 ) { QuitUserChannel(ui[(int)p].nameCh[i],(int)p); } } break; } if (only == 1 ) { send(ui[(int)p].cSocket,&buff[0],(int)strlen(buff),0); if (buff[0]!='0' ) continue; for (i = 0 ; i < 32 ; i++ ) { if ( ui[(int)p].nameCh[i][0]!=0) { j = SearchChannel(ui[(int)p].nameCh[i]); if ( channelBase[j].registration == 1 ) ChangeAtributeUser((int)p,j); strcpy(buff,UpdateChannel(ui[(int)p].nameCh[i],j,3,(int)p)); WaitForSingleObject(hMutexChannel[j],INFINITE); channelUser *snd = channelBase[j].user ; while (snd!=0) { send(ui[snd>posUser].cSocket,&buff[0],(int)strlen(buff),0); snd=snd->pNext; } ReleaseMutex(hMutexChannel[j]); } } strcpy(ui[(int)p].LastNickname,ui[(int)p].nickname); } if (only == 0 ) { strcpy(nameChannel,GetNameChannel(buff,4)); for (i = 0 ; i < 32 ; i ++ ) if (strcmp(ui[(int)p].nameCh[i],nameChannel)==0 ) {join = true ; break;} if ( join == false ) continue; i = SearchChannel(nameChannel); if ( i == -1 ) continue; WaitForSingleObject(hMutexChannel[j],INFINITE); channelUser *snd = channelBase[i].user ; strcat(buff,(char *)&razd); while ( snd!=0 ) { send(ui[snd->posUser].cSocket,&buff[0],(int)strlen(buff),0); snd=snd->pNext; } ReleaseMutex(hMutexChannel[j]); } } 10 printf ("Slot:[%d] +%s [%s] connect close\n",(int)p,(ui[(int)p].hst)?ui[(int)p].hst>h_name:"",inet_ntoa(ui[(int)p].cAddr.sin_addr)); sprintf (buff,"+%s [%s] connect close\n",(ui[(int)p].hst)?ui[(int)p].hst>h_name:"",inet_ntoa(ui[(int)p].cAddr.sin_addr)); AddLogFile(logName,buff); closesocket(ui[(int)p].cSocket); ui[(int)p].connect=false; } void workServer() { InitUserInfo(); SOCKET tSocket ; sockaddr_in tAddr; int tAddr_size = sizeof(tAddr); int pos; char buff[1024]; strcpy(channelBase[0].nameChannel,"ALL"); channelBase[0].registration = true ; channelBase[0].szUser = 0; channelBase[0].user = 0 ; channelBase[0].usingCh = true; while (tSocket=accept(sSocket,(sockaddr *)&tAddr,&tAddr_size)) { pos = SearchPosUI(); ui[pos].hst=gethostbyaddr((char *)&tAddr.sin_addr.s_addr,4,AF_INET); ui[pos].connect = true ; ui[pos].cAddr_size = tAddr_size; ui[pos].cAddr = tAddr; ui[pos].cSocket = tSocket; ui[pos].Attribute= AS_NUSER ; sprintf(buff,"Deafailt%i",pos); strcpy(ui[pos].nickname,buff); strcpy(ui[pos].LastNickname,buff); printf ("Slot:[%d] +%s [%s] new connect\n",pos,(ui[pos].hst)?ui[pos].hst>h_name:"",inet_ntoa(ui[pos].cAddr.sin_addr)); sprintf(buff,"+%s [%s] new connect\n",(ui[pos].hst)?ui[pos].hst>h_name:"",inet_ntoa(ui[pos].cAddr.sin_addr)); AddLogFile(logName,buff); _beginthread(ThreadUser,0,(void *)pos); } } head.h #define AS_NUSER -1 #define AS_USER 0 #define S_USER 0 #define S_MDR 1 #define S_ADMN 2 #define N 1024 #define rzd 11 char razd = rzd ; char pathNick[] = "BaseNickname/"; char pathChannel[] = "BaseChannel/"; HANDLE hMutexChannel[N]; struct channelUser { int posUser; int Attribute; channelUser *pNext,*pLost; }; struct channelHead { char nameChannel[128]; int szUser; bool usingCh; bool registration; channelUser *user; }; channelHead channelBase[N]; int NewUserChannel(char *,int,int,int); void AddLogFile(char *,char *); char *ProcLine(char *,int,int *); char *GetNameChannel(char *,int); 11 char *UpdateChannel(char *,int,int,int); void QuitUser(int); char *QuitUserChannel(char *,int); int SearchChannel(char *); void JoinChannel(char *,int); void RegistrationChannel(char *,int); void ChangeAtributeUser(int,int); void SendNewNickname(int); Channel.h void InitChannel() { int i; for ( i = 0 ; i < 1024 ; i ++ ) { channelBase[i].usingCh = false ; } } int SearchChannel(char *nameCh) { int i; for ( i = 0 ; i < 1024 ; i ++ ) { if ( strcmp(nameCh,channelBase[i].nameChannel)==0) return i; } return -1; } void ChangeAtributeUser(int posUser,int i) { char buff[32]; char filebuff[128]; int atr = -1; FILE *f; strcpy(filebuff,pathChannel); strcat(filebuff,channelBase[i].nameChannel); f = fopen(filebuff,"r"); if (f == 0 ) return ; fgets(buff,32,f); if ( buff[0]==10 ) buff[0]=0; while (feof(f)==false) { fscanf(f,"%s %i",&buff,&atr); if ( strcmp(buff,ui[posUser].nickname)==0) { channelUser *tm = channelBase[i].user; while (tm!=0) { if (tm->posUser == posUser ) {fclose(f);tm->Attribute = atr ;return; } tm=tm->pNext; } fclose(f); } } fclose(f); } char *GetNameChannel(char *buff,int i) { char name[128]; int k = 0 ; for (i ; i < strlen(buff) ; i ++ ) { if (buff[i]==' ' ) break; name[k] = buff[i]; k++; } if ( i == (int)strlen(buff) ) name[k-1] = 0; else name[k]=0; return name; } void SetChannelNameUser(char *nameCh,int posUser) { int i; for (i = 0 ; i < 32 ; i++ ) 12 { if (ui[posUser].nameCh[i][0]==0 ) { strcpy(ui[posUser].nameCh[i],nameCh); return; } } } void ClearChannelNameUser(char name[],int posUser) { char nameCh[128]; strcpy(nameCh,name); int i; for (i = 0 ; i < 32 ; i++ ) { if (strcmp(nameCh,ui[posUser].nameCh[i])==0 ) { ui[posUser].nameCh[i][0]=0; strcpy(name,nameCh); break; } } return ; } void SendUserChannel(int i,int posUser,int trg) { channelUser *tm =channelBase[i].user; WaitForSingleObject(hMutexChannel,INFINITE); char buff[2048]; char buffuser[2048]; strcpy(buffuser,UpdateChannel(channelBase[i].nameChannel,i,0,posUser)); strcpy(buff,UpdateChannel(channelBase[i].nameChannel,i,trg,posUser)); while (tm!=0) { if ( tm->posUser == posUser ) { send(ui[tm->posUser].cSocket,&buffuser[0],(int)strlen(buffuser),0); } else { send(ui[tm->posUser].cSocket,&buff[0],(int)strlen(buff),0); } tm=tm->pNext; } ReleaseMutex(hMutexChannel); } int NewUserChannel(char *nameCh,int posUser,int atr,int RegCh) { int i ; for ( i = 0 ; i < 1024 ; i ++ ) { if (channelBase[i].usingCh == true && strcmp(nameCh,channelBase[i].nameChannel)==0) { WaitForSingleObject(hMutexChannel[i],INFINITE); channelUser *tm = new channelUser; tm->posUser = posUser; tm->Attribute = atr; tm->pLost = 0 ; tm->pNext = channelBase[i].user ; channelBase[i].szUser ++ ; channelBase[i].registration = RegCh; if(channelBase[i].user == NULL ) { channelBase[i].user = new channelUser; channelBase[i].user = tm ; printf("Slot[%i] new user channel [%s] , size Channel [%i] , regChannel [%i]\n",i,nameCh,channelBase[i].szUser,channelBase[i].registration); SetChannelNameUser(nameCh,posUser); ReleaseMutex(hMutexChannel[i]); SendUserChannel(i,posUser,1); return i; } channelBase[i].user->pLost = tm ; channelBase[i].user = tm; printf("Slot[%i] new user channel [%s] , size Channel [%i] , regChannel [%i]\n",i,nameCh,channelBase[i].szUser,channelBase[i].registration); 13 SetChannelNameUser(nameCh,posUser); ReleaseMutex(hMutexChannel[i]); SendUserChannel(i,posUser,1); return i; } } for ( i = 0 ; i < 1024 ; i ++ ) { if (channelBase[i].usingCh == false ) break; } hMutexChannel[i] = CreateMutex(NULL,FALSE,NULL); channelBase[i].usingCh = true; channelBase[i].registration = RegCh ; strcpy(channelBase[i].nameChannel,nameCh); channelBase[i].szUser = 1 ; channelBase[i].user = new channelUser ; channelBase[i].user->Attribute = atr; channelBase[i].user->pLost = 0 ; channelBase[i].user->pNext = 0 ; channelBase[i].user->posUser = posUser; if (RegCh==0) printf("Slot[%i] new not registred channel [%s]\n",i,nameCh); else printf("Slot[%i] new user channel [%s] , size Channel [%i] , regChannel [%i]\n",i,nameCh,channelBase[i].szUser,channelBase[i].registration); SetChannelNameUser(nameCh,posUser); SendUserChannel(i,posUser,1); return i; } int AddUserChannel(char *nameCh,char *password,int posUser) { char buff[32]; char filebuff[128]; int atr = -1; int len = 0 ; FILE *f; strcpy(filebuff,pathChannel); strcat(filebuff,nameCh); f = fopen(filebuff,"r"); if ( f!=0) { if (ui[posUser].Attribute == AS_NUSER ) { fclose(f); return -1; } fgets(buff,32,f); len = strlen(buff); if ( buff[0]==10 ) buff[0]=0; else buff[len-1] = 0 ; if ( strcmp(password,buff) !=0 ) { fclose(f); return -1; } while (feof(f)==false) { fscanf(f,"%s %i",&buff,&atr); if ( strcmp(buff,ui[posUser].nickname)==0) { fclose(f); return NewUserChannel(nameCh,posUser,atr,1); } } fclose(f); return NewUserChannel(nameCh,posUser,S_USER,1); } return NewUserChannel(nameCh,posUser,S_USER,0); } void RegistrationChannel(char *buff,int posUser) { FILE *f; char sndErr[10]; char filebuff[1024]; char nameCh[32]; char passCh[32]; char upd[2048]; int i = 0 ; 14 GetNickPass(buff,nameCh,passCh); if (ui[posUser].Attribute == AS_NUSER ) { strcpy(sndErr,"8"); strcat(sndErr,(char *)&razd); send(ui[posUser].cSocket,sndErr,strlen(sndErr),0); return; } strcpy(filebuff,pathChannel); strcat(filebuff,nameCh); f=fopen(filebuff,"r"); if ( f!=0) { strcpy(sndErr,"7"); strcat(sndErr,(char *)&razd); send(ui[posUser].cSocket,sndErr,strlen(sndErr),0); return ; } f=fopen(filebuff,"w"); fprintf(f,"%s\n",passCh); fprintf(f,"%s %i\n",ui[posUser].nickname,S_ADMN); printf ("Registration Channel [%s] pass [%s]\n",nameCh,passCh); fclose(f); i = SearchChannel(nameCh); WaitForSingleObject(hMutexChannel[i],INFINITE); channelBase[i].registration = 1 ; ChangeAtributeUser(posUser,i); strcpy(sndErr,"0"); strcat(sndErr,(char *)&razd); send(ui[posUser].cSocket,sndErr,strlen(sndErr),0); channelUser *tm = channelBase[i].user ; strcpy(upd,UpdateChannel(channelBase[i].nameChannel,i,3,posUser)); while (tm!=0) { send(ui[tm->posUser].cSocket,upd,strlen(upd),0); tm=tm->pNext; } ReleaseMutex(hMutexChannel[i]); sprintf(buff,"Channel %s registred, ADMN - %s",nameCh,ui[posUser].nickname); AddLogFile(logName,buff); return ; } char *QuitUserChannel(char *nameCh,int posUser) { int i = SearchChannel(nameCh); channelUser * tm ; WaitForSingleObject(hMutexChannel[i],INFINITE); tm = channelBase[i].user ; while (tm!=0) { if ( tm->posUser == posUser ) { if ( tm->pLost == 0 ) { channelBase[i].user = tm->pNext ; if ( channelBase[i].user != 0 ) channelBase[i].user->pLost = 0 ; } else { if (tm->pNext == 0 ) tm->pLost->pNext = 0 ; else { tm->pLost->pNext = tm->pNext; tm->pNext->pLost = tm->pLost; } } channelBase[i].szUser--; break; } tm=tm->pNext; } ReleaseMutex(hMutexChannel[i]); ClearChannelNameUser(channelBase[i].nameChannel,posUser); if (channelBase[i].szUser == 0 && i!=0 ) { 15 CloseHandle(hMutexChannel[i]); channelBase[i].usingCh = false ; printf("Slot[%i] channel [%s] quit [%s] szCh[%i] UsingCh [%i] RegCh [%i] \n",i,channelBase[i].nameChannel,ui[posUser].nickname,channelBase[i].szUser,channelBase[i].usingC h,channelBase[i].registration); return 0; } printf("Slot[%i] channel [%s] quit [%s] szCh[%i] UsingCh [%i] RegCh [%i] \n",i,channelBase[i].nameChannel,ui[posUser].nickname,channelBase[i].szUser,channelBase[i].usingC h,channelBase[i].registration); SendUserChannel(i,posUser,2); return 0; } char *UpdateChannel(char *nameCh,int i,int trg,int posUser) { WaitForSingleObject(hMutexChannel[i],INFINITE); char v[12]; char buff[2048]; int len ; if ( trg == 0 ) { strcpy(buff,"upd "); strcat(buff,nameCh); len = strlen(buff); channelUser *tm = channelBase[i].user; while (tm!=0) { buff[len]=' '; buff[len+1]=0; strcat(buff,ui[tm->posUser].nickname); len = strlen(buff); buff[len]=' '; buff[len+1]=0; strcat(buff,_itoa(tm->Attribute,v,10)); len = strlen(buff); tm=tm->pNext; } strcat(buff,(char *)&razd); } if ( trg == 1 ) { channelUser *tm = channelBase[i].user; while (tm->posUser!=posUser) {tm=tm->pNext;} strcpy(buff,"jin "); strcat(buff,nameCh); strcat(buff," "); strcat(buff,ui[posUser].nickname); strcat(buff," "); strcat(buff,_itoa(tm->Attribute,v,10)); strcat(buff,(char *)&razd); } if ( trg == 2 ) { strcpy(buff,"qit "); strcat(buff,nameCh); strcat(buff," "); strcat(buff,ui[posUser].nickname); strcat(buff,(char *)&razd); } if ( trg == 3 ) { strcpy(buff,"cng "); strcat(buff,nameCh); strcat(buff," "); strcat(buff,ui[posUser].LastNickname); strcat(buff," "); channelUser *tm = channelBase[i].user; while (tm->posUser!=posUser) {tm=tm->pNext;} strcat(buff,ui[posUser].nickname); strcat(buff," "); strcat(buff,_itoa(tm->Attribute,v,10)); strcat(buff,(char *)&razd); } ReleaseMutex(hMutexChannel[i]); return buff; } void JoinChannel(char *buff,int posUser) { 16 char nameCh[32]; char password[32]; int i; GetNickPass(buff,nameCh,password); for (i = 0 ; i < 32 ; i ++ ) if (strcmp(ui[posUser].nameCh[i],nameCh)==0 ) return; if (AddUserChannel(nameCh,password,posUser) == -1 ) { strcpy(nameCh,"6"); strcat(nameCh,(char *)&razd); send(ui[posUser].cSocket,nameCh,(int)strlen(nameCh),0); } } void SendNewNickname(int posUser) { char filebuff[1024]; strcpy(filebuff,"nck "); strcat(filebuff,ui[posUser].nickname); strcat(filebuff,(char *)&razd); send(ui[posUser].cSocket,&filebuff[0],strlen(filebuff),0); } workingServer.h int StartServer(int sPORT) { char wsaData[1024]; if (WSAStartup(0x0202,(WSADATA *)&wsaData)) { printf ("Error WSAStartup %d\n",WSAGetLastError()); AddLogFile(logName, "Error WSAStartup \n" ); WSACleanup(); return -1; } else AddLogFile(logName, " WSAStartup OK \n" ); if ((sSocket=socket(AF_INET,SOCK_STREAM,0))<0) { printf ("Error Socket %d\n",WSAGetLastError()); AddLogFile(logName, "Error Socket \n" ); WSACleanup(); return -2; } else AddLogFile(logName, "Socket OK \n" ); sAddres.sin_port = htons(sPORT); sAddres.sin_family = AF_INET; sAddres.sin_addr.s_addr = 0 ; if(bind(sSocket,(sockaddr *)&sAddres,sizeof(sAddres)) ) { printf("Error bind %d\n",WSAGetLastError()); AddLogFile(logName, "Error bind \n" ); closesocket(sSocket); WSACleanup(); return -3; } else AddLogFile(logName,"bind OK \n"); if ( listen(sSocket,0x100) ) { printf("Error listen %d\n",WSAGetLastError()); AddLogFile(logName, "Error listen \n" ); closesocket(sSocket); WSACleanup(); return -4; } else AddLogFile(logName,"Listen OK \n"); PrintTime(); AddLogFile(logName,"Server started\n"); printf (":Server started\n"); return 0; } int EndServer() { closesocket(sSocket); AddLogFile(logName,"Close Socket\n"); WSACleanup(); 17 AddLogFile(logName,"Close WSA\n"); PrintTime(); AddLogFile(logName,"Server Close\n" ); return 0; } logFile.h void AddLogFile(char *FileName,char *message) { FILE *f; SYSTEMTIME st; char buff[1024]; f=fopen(FileName,"a+"); GetSystemTime(&st); sprintf(buff,"%d.%d.%d ",st.wHour,st.wMinute,st.wSecond); fwrite((char *)&buff,strlen(buff),1,f); fwrite(message,strlen(message),1,f); fclose(f); } index.cpp #include <stdio.h> #include <winsock2.h> #include <windows.h> #include <process.h> #include <conio.h> #include "head.h" SOCKET sSocket; sockaddr_in sAddres; void PrintTime(); char baseName[]="base.txt"; char logName[]="log12.txt"; #include "connection.h" #include "logFile.h" #include "workingServer.h" #include "pLine.h" #include "Channel.h" void PrintTime() { SYSTEMTIME st; GetSystemTime(&st); printf("%d.%d.%d",st.wHour,st.wMinute,st.wSecond); } int main (int argc,char *argv) { if (StartServer(1952) != workServer(); Sleep(1000*10); EndServer(); _getch(); return 0; } 0 ) return -1; 18 Код «программы-клиента»: Client.h #include #include #include #include #include <stdio.h> <process.h> <winsock2.h> <windows.h> <conio.h> #define MY_PORT 1952 #define maxNick 25 #define sim 11 void TreeRedraw(int flag); void MessagePrint(); int GetUserName(char *name, int count); void STS(char *msg); void GMS(void *p); int Connecting(char *IpAddress, HWND hWnd); SOCKET serverSocket, ClientSocket; sockaddr_in LocalAddr, ClientAddr; int ClientAddr_size = sizeof(ClientAddr); char *message; int answer; char bufer[2048]; HWND hwnd; struct hostent *hst; int bytes_recv; char *nick = new char[maxNick+1]; int separation(char *in, char *out, int count){ int i=count; while(in[i]!=sim){ out[i-count]=in[i]; i++; } out[i-count]=0; return i; } void STS(char *msg){ send(serverSocket,msg,strlen(msg)+1,0); } void GMS(void *p){ int i; while((bytes_recv=recv(serverSocket,&bufer[0],sizeof(bufer)-1,0))!=SOCKET_ERROR){ bufer[bytes_recv]=0; i=-1; message = new char [2048]; do{ i=separation(bufer,message,i+1); switch(message[0]){ case 'u': TreeRedraw(0); break; case 'j': TreeRedraw(1); break; case 'q': TreeRedraw(2); break; case 'c': 19 TreeRedraw(3); break; case 'm': MessagePrint(); break; case 'n': GetUserName(nick,4); break; case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56 : answer=atoi(message); break; } } while(bufer[i+1]!=0); delete[] message; } } int Connecting(char *IpAddress, HWND hWnd){ hwnd=hWnd; if (WSAStartup(0x0202,(WSADATA *) &bufer)){ WSACleanup(); return 1; } if ((serverSocket=socket(AF_INET,SOCK_STREAM,0))<0){ WSACleanup(); return 1; } LocalAddr.sin_family = AF_INET; LocalAddr.sin_port = htons(MY_PORT); LocalAddr.sin_addr.s_addr = 0 ; if (inet_addr(IpAddress)!=INADDR_NONE) LocalAddr.sin_addr.s_addr = inet_addr(IpAddress); else if (hst = gethostbyname (IpAddress)) ((unsigned long *)&LocalAddr.sin_addr)[0]=((unsigned long **)hst>h_addr_list)[0][0]; else{ closesocket(serverSocket); WSACleanup(); return 1; } if (connect(serverSocket,(sockaddr *)&LocalAddr,sizeof(LocalAddr))) return 1; _beginthread(GMS,NULL,NULL); return 0; } ClientAreal.cpp #include #include #include #include #define #define #define #define #define #define #define #define #define <stdio.h> "Client.h" <windows.h> <commctrl.h> LogEdit 1 MsgEdit 2 LoginEdit 3 PswdEdit 4 MemBtn 5 DoBtn 6 SndBtn 7 ExitBtn 8 ChnEdit 9 20 #define #define #define #define #define #define #define #define ChpEdit 10 Static 11 ComboBox 12 IpAdr 13 CnctBtn 14 TreeView 15 Time 17 Static2 18 #define #define #define #define #define #define maxMsg 100 maxNick 25 stringLength maxMsg+maxNick*2+10 maxChannels 30 maxUsers 200 maxLog 30000 LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM); HTREEITEM ChannelAdd(char *channelName); void UserAdd(char *userName, HTREEITEM hRoot); HTREEITEM GetTreeItem(LPTV_ITEM item, HTREEITEM hRoot); int GetChannelName(char *name); int GetUserName(char *name, int count); int GetMessage(char *msg, int count); void TreeRedraw(int flag); char *log = new char [maxLog]; HTREEITEM SELECT; HDC hdc; RECT rt; HWND hWnd; HWND hLog, hMsg, hNick, hPas1, hMem, hPas2, hChnl, hDo; HWND hSnd, hExit, hCnct; HWND hTree, hIp, hCombo, hTime, hStatic, hStatic2; int TransSwitch=0; HTREEITEM ChannelAdd(char *channelName){ TV_ITEM item; HTREEITEM hRoot; LPTV_INSERTSTRUCT lPis = new TV_INSERTSTRUCT; item.mask=TVIF_TEXT; item.pszText=channelName; item.cChildren=1; item.cchTextMax=25; lPis->hInsertAfter=TVI_SORT; lPis->hParent=TVI_ROOT; lPis->item=item; hRoot=TreeView_InsertItem(hTree,lPis); return hRoot; } void UserAdd(char *userName, HTREEITEM hRoot){ TV_ITEM item; LPTV_INSERTSTRUCT lPis = new TV_INSERTSTRUCT; item.mask=TVIF_TEXT; item.pszText=userName; item.cChildren=0; item.cchTextMax=40; lPis->hInsertAfter=TVI_SORT; lPis->hParent=hRoot; lPis->item=item; TreeView_InsertItem(hTree,lPis); } HTREEITEM GetTreeItem(LPTV_ITEM item, HTREEITEM hRoot){ if (hRoot==NULL) hRoot=TreeView_GetSelection(hTree); item->hItem = hRoot; 21 item->mask = TVIF_TEXT; item->pszText=new char[50]; item->cchTextMax=50; TreeView_GetItem(hTree,item); return hRoot; } int GetChannelName(char *name){ int i=4; do{ name[i-4]=message[i]; i++; } while(message[i]!=' '); name[i-4]=0; return i; } int GetUserName(char *name, int count){ int i=count; char *buf = new char [25]; do{ buf[i-count]=message[i]; i++; } while((message[i]!=' ') && (message[i]!=0)); buf[i-count]=0; switch(message[i+1]){ case 48: if ((message[i+2]==' ') || (message[i+2]==0)) sprintf(name,"%s [User]",buf); else{ strcpy(name,buf); i-=2; } break; case 49: if ((message[i+2]==' ') || (message[i+2]==0)) sprintf(name,"%s [Moder]",buf); else{ strcpy(name,buf); i-=2; } break; case 50: if ((message[i+2]==' ') || (message[i+2]==0)) sprintf(name,"%s [Admin]",buf); else{ strcpy(name,buf); i-=2; } break; default: strcpy(name,buf); i-=2; } delete[] buf; return i+2; } int GetMessage(char *msg, int count){ int i=count; do{ msg[i-count]=message[i]; i++; } while((message[i]!=0)); msg[i-count]='\n'; msg[i-count+1]=0; return i; 22 } void TreeRedraw(int flag){ LPTV_ITEM item = new TV_ITEM; HTREEITEM hRoot=TreeView_GetChild(hTree,TVI_ROOT), hBuf; int i; char *string = new char [50]; TransSwitch=1; SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); GetTreeItem(item, NULL); i=GetChannelName(string); if (flag==0){ hRoot=ChannelAdd(string); if (TreeView_GetSelection(hTree)==NULL) SELECT=hRoot; TransSwitch=0; SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); } else while(strcmp(item->pszText,string)!=0){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); hRoot=TreeView_GetNextVisible(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item, NULL); } switch(flag){ case 0: do{ i=GetUserName(string,i+1); UserAdd(string,hRoot); } while(message[i]!=0); SendMessage(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot); SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); break; case 1: i=GetUserName(string,i+1); UserAdd(string,hRoot); hRoot=TreeView_GetParent(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); break; case 2: i=GetUserName(string,i+1); hRoot=TreeView_GetChild(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item,NULL); while(strncmp(item->pszText,string,strlen(string))!=0){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); hRoot=TreeView_GetNextVisible(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item,NULL); } SendMessage(hTree, TVM_DELETEITEM, NULL, (LPARAM)hRoot); hRoot=TreeView_GetParent(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); break; case 3: hBuf=hRoot; i=GetUserName(string,i+1); hRoot=TreeView_GetChild(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item,NULL); while(strncmp(item->pszText,string,strlen(string))!=0){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); hRoot=TreeView_GetNextVisible(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item,NULL); 23 } SendMessage(hTree, TVM_DELETEITEM, NULL, (LPARAM)hRoot); i=GetUserName(string,i+1); hRoot=hBuf; UserAdd(string,hRoot); break; } TransSwitch=0; SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)SELECT); delete[] string; delete item; } void MessagePrint(){ FILE *f; LPTV_ITEM item = new TV_ITEM; HTREEITEM hRoot=TreeView_GetChild(hTree,TVI_ROOT); int i, nLen; char *string1 = new char [maxMsg+maxNick*2+10]; char *string2 = new char [maxMsg+maxNick*2+10]; TransSwitch=1; SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); GetTreeItem(item,NULL); i=GetChannelName(string1); while(strcmp(item->pszText,string1)!=0){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); hRoot=TreeView_GetNextVisible(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item,NULL); } ZeroMemory(string1,strlen(string1)); i=GetUserName(string1,i+1); sprintf(string2,"%s : ",string1); ZeroMemory(string1,strlen(string1)); i=GetMessage(string1,i+1); strcat(string2,string1); if (hRoot==SELECT){ nLen = GetWindowTextLength (hLog); SendMessage (hLog, EM_SETSEL, nLen, nLen); SendMessage (hLog, EM_REPLACESEL, 0, (LPARAM)string2); } else{ sprintf(string1,"%s.chnl",item->pszText); f=fopen(string1,"a+"); fprintf(f,"%s",string2); fclose(f); } SetWindowText(hMsg, (LPCSTR)""); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)SELECT); SendMessage(hMsg ,WM_ACTIVATE, WA_ACTIVE, NULL); TransSwitch=0; delete item; delete[] string1; delete[] string2; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ MSG msg; WNDCLASS wc; LPCSTR lpszAppName="Client areal ver. 1"; BOOL ret; HTREEITEM hRoot; wc.lpszClassName = lpszAppName; wc.hInstance=hInstance; wc.lpfnWndProc = (WNDPROC)MyWndProc; wc.hCursor = LoadCursor(NULL, IDC_ARROW); 24 wc.hIcon = 0; wc.lpszMenuName = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+7); wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; if(!RegisterClass(&wc)) return 0; hWnd = CreateWindow(lpszAppName, lpszAppName, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | (WS_MAXIMIZEBOX) &~(WS_THICKFRAME), 100, 100, 610, 500, NULL, NULL, hInstance, NULL); hLog = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, "edit", "", WS_CHILD | WS_VISIBLE | ES_READONLY | ES_MULTILINE | WS_DLGFRAME | WS_VSCROLL , 20, 50, 300, 300, hWnd, (HMENU)LogEdit, hInstance, NULL); hMsg = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, "edit", "Enter the message", WS_CHILD | WS_VISIBLE | ES_MULTILINE | WS_DLGFRAME | WS_VSCROLL, 20, 360, 300, 60, hWnd, (HMENU)MsgEdit, hInstance, NULL); SendMessage (hMsg, EM_LIMITTEXT, maxMsg, NULL); hNick = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, "edit", "Nickname", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,480, 30, 100, 20, hWnd, (HMENU)LoginEdit, hInstance, NULL); SendMessage (hNick, EM_LIMITTEXT, maxNick, NULL); hPas1 = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, "edit", "Password", WS_CHILD | WS_VISIBLE | ES_PASSWORD | ES_AUTOHSCROLL, 480, 55, 100, 20, hWnd, (HMENU)PswdEdit, hInstance, NULL); SendMessage (hPas1, EM_LIMITTEXT, maxNick, NULL); hSnd = CreateWindow("BUTTON", "Send", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , 350, 360, 80, 50, hWnd, (HMENU)SndBtn, hInstance, NULL); hExit = CreateWindow("BUTTON", "Exit", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 425, 100, 30, hWnd, (HMENU)ExitBtn, hInstance, NULL); hChnl = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, "edit", "Channel name", WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,350, 90, 120, 25, hWnd, (HMENU)ChnEdit, hInstance, NULL); SendMessage (hChnl, EM_LIMITTEXT, maxNick, NULL); hPas2 = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE, "edit", "", WS_CHILD | WS_VISIBLE | ES_PASSWORD | ES_AUTOHSCROLL,475, 90, 105, 25, hWnd, (HMENU)ChpEdit, hInstance, NULL); SendMessage (hPas2, EM_LIMITTEXT, maxNick, NULL); hIp = CreateWindow(WC_IPADDRESS, NULL, WS_CHILD | WS_VISIBLE, 20, 10, 150, 25, hWnd, (HMENU)IpAdr, hInstance, NULL); SendMessage(hIp, IPM_SETADDRESS, NULL, MAKEIPADDRESS(192,168,0,1)); hCnct = CreateWindow("BUTTON", "To connect", WS_CHILD | WS_VISIBLE, 175, 10, 145, 25, hWnd, (HMENU)CnctBtn, hInstance, NULL); hCombo = CreateWindow("COMBOBOX", "", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_DLGFRAME, 340, 30, 135, 150, hWnd, (HMENU)ComboBox, hInstance, NULL); SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)"Log in"); SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)"To be registred"); SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)"Log out"); SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)"Channel enter"); SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)"Channel registration"); SendMessage(hCombo, CB_ADDSTRING, NULL, (LPARAM)"Channel exit"); SendMessage(hCombo, CB_SELECTSTRING, NULL, (LPARAM)"Log in"); SendMessage(hCombo, CB_SETMINVISIBLE, NULL, NULL); hDo = CreateWindow("BUTTON", "Log in", WS_CHILD | WS_VISIBLE, 340, 55, 135, 20, hWnd, (HMENU)DoBtn, hInstance, NULL); hStatic = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE,"static", "", SS_CENTER | SS_LEFT | SS_SUNKEN | WS_BORDER | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 480, 30, 100, 45, hWnd, (HMENU)Static, hInstance, NULL); hTime = CreateWindowEx(WS_EX_STATICEDGE, DATETIMEPICK_CLASS, "Calendar", DTS_LONGDATEFORMAT | WS_CHILD | WS_DLGFRAME | WS_OVERLAPPED | WS_VISIBLE, 440, 360, 140, 50, hWnd, (HMENU)Time, hInstance, NULL); hStatic2 = CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE,"static", "", SS_CENTER | SS_LEFT | SS_SUNKEN | WS_BORDER | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 350, 120, 230, 25, hWnd, (HMENU)Static2, hInstance, NULL); 25 InitCommonControls(); hTree = CreateWindowEx(WS_EX_STATICEDGE, WC_TREEVIEW, "Channels", WS_VISIBLE | WS_CHILD | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | WS_DLGFRAME | WS_VSCROLL | WS_HSCROLL, 350, 150, 230, 200, hWnd, (HMENU) TreeView, hInstance, NULL); ret = RegisterHotKey(hWnd,0xB001, MOD_CONTROL | MOD_ALT, 'D'); SendMessage(hIp,WM_ACTIVATE, WA_ACTIVE, NULL); ShowWindow(hStatic,SW_HIDE); ShowWindow(hWnd,SW_SHOW); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ FILE *f; PAINTSTRUCT ps; HTREEITEM hRoot; LPTV_ITEM item = new TV_ITEM; int nLen, i; char *string1 = new char [stringLength]; char *string2 = new char [stringLength]; switch (message) { case WM_HOTKEY: SendMessage(hLog, WM_SETTEXT, NULL, (LPARAM)""); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); EndPaint(hWnd, &ps); break; case WM_DESTROY: STS("exit"); hRoot=TreeView_GetChild(hTree,TVI_ROOT); TransSwitch=1; while(hRoot!=NULL){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item, NULL); sprintf(string1,"%s.chnl",item->pszText); remove(string1); hRoot=TreeView_GetNextVisible(hTree,hRoot); } PostQuitMessage(0); break; case WM_COMMAND: switch(LOWORD(wParam)){ case ExitBtn: SendMessage(hWnd, WM_DESTROY, NULL, NULL); break; case CnctBtn: if (ShowWindow(hIp,NULL)){ GetWindowText(hIp,string1,16); if (Connecting(string1, hWnd)){ ShowWindow(hIp,SW_SHOW); MessageBox(hWnd,"Connection error!","Error",MB_OK | MB_ICONERROR); break; } SendMessage(hStatic2, WM_SETTEXT, NULL, (LPARAM)"ALL is active"); SendMessage(hTree,WM_ACTIVATE, WA_ACTIVE, NULL); 26 SendMessage(hLog, WM_SETTEXT, NULL, (LPARAM)""); SendMessage(hIp, WM_ACTIVATE, WA_ACTIVE, NULL); MessageBox(hWnd,"You are successfully connected to a server!","Information",MB_OK | MB_ICONINFORMATION); SendMessage(hCnct, WM_SETTEXT, NULL, (LPARAM)"To disconnect"); ShowWindow(hIp, SW_HIDE); } else{ STS("exit"); hRoot=TreeView_GetChild(hTree,TVI_ROOT); TransSwitch=1; while(hRoot!=NULL){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); hRoot=GetTreeItem(item, NULL); sprintf(string1,"%s.chnl",item->pszText); remove(string1); hRoot=TreeView_GetNextVisible(hTree,hRoot); } TreeView_DeleteAllItems(hTree); SendMessage(hCnct, WM_SETTEXT, NULL, (LPARAM)"To connect"); SendMessage(hStatic2, WM_SETTEXT, NULL, (LPARAM)""); SendMessage(hLog, WM_SETTEXT, NULL, (LPARAM)""); ShowWindow(hIp, SW_SHOW); ShowWindow(hNick,SW_SHOW); ShowWindow(hPas1,SW_SHOW); ShowWindow(hStatic,SW_HIDE); SendMessage(hIp, WM_ACTIVATE, WA_ACTIVE, NULL); } break; case SndBtn: GetWindowText(hMsg, string1, 101); GetTreeItem(item,NULL); sprintf(string2,"msg %s %s %s",item->pszText,nick,string1); STS(string2); break; case DoBtn: switch (SendMessage(hCombo, CB_GETCURSEL, NULL ,NULL)){ case 0: if (ShowWindow(hIp,SW_SHOW)){ MessageBox(hWnd,"You are not connected to any server!","Error",MB_OK | MB_ICONERROR); break; } ShowWindow(hIp, SW_HIDE); GetWindowText(hNick, string1, 26); sprintf(string2,"auth %s ",string1); GetWindowText(hPas1, string1, 26); strcat(string2,string1); STS(string2); Sleep(250); switch(answer){ case 0: MessageBox(hWnd,"You have successfully entered!","Information",MB_OK | MB_ICONINFORMATION); break; case 2: MessageBox(hWnd,"The incorrect password!","Error",MB_OK | MB_ICONERROR); break; case 3: MessageBox(hWnd,"Such user is not registered!","Error",MB_OK | MB_ICONERROR); break; 27 case 4: MessageBox(hWnd,"You have already entered!","Information",MB_OK | MB_ICONINFORMATION); break; } sprintf(string2,"You are %s",nick); SendMessage(hStatic,WM_SETTEXT,NULL,(LPARAM)string2); if (answer!=0) break; ShowWindow(hNick,SW_HIDE); ShowWindow(hPas1,SW_HIDE); ShowWindow(hStatic,SW_SHOW); SendMessage(hIp ,WM_ACTIVATE, WA_ACTIVE, NULL); break; case 1: if (ShowWindow(hIp,SW_SHOW)){ MessageBox(hWnd,"You are not connected to any server!","Error",MB_OK | MB_ICONERROR); break; } ShowWindow(hIp, SW_HIDE); GetWindowText(hNick, string1, 26); sprintf(string2,"reg %s ",string1); GetWindowText(hPas1, string1, 26); strcat(string2,string1); STS(string2); Sleep(250); switch(answer){ case 0: MessageBox(hWnd,"Successful registration! Can enter!","Information",MB_OK | MB_ICONINFORMATION); break; case 1: MessageBox(hWnd,"Such user is already registered!","Error",MB_OK | MB_ICONERROR); break; } sprintf(string2,"You are %s",nick); SendMessage(hStatic,WM_SETTEXT,NULL,(LPARAM)string2); if (answer!=0) break; ShowWindow(hNick,SW_HIDE); ShowWindow(hPas1,SW_HIDE); ShowWindow(hStatic,SW_SHOW); SendMessage(hIp ,WM_ACTIVATE, WA_ACTIVE, NULL); break; case 2: if (ShowWindow(hNick,SW_SHOW)){ MessageBox(hWnd,"You are not authorised!","Prevention",MB_OK | MB_ICONEXCLAMATION); break; } ShowWindow(hNick, SW_HIDE); hRoot=TreeView_GetChild(hTree,TVI_ROOT); while(hRoot!=NULL){ SendMessage(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); 28 hRoot=GetTreeItem(item, NULL); sprintf(string1,"quit %s ",item>pszText); Sleep(250); STS(string1); hRoot=TreeView_GetNextVisible(hTree,hRoot); } TreeView_DeleteAllItems(hTree); Sleep(250); STS("logout"); Sleep(250); STS("join ALL "); ShowWindow(hNick,SW_SHOW); ShowWindow(hPas1,SW_SHOW); ShowWindow(hStatic,SW_HIDE); SendMessage(hStatic ,WM_ACTIVATE, WA_ACTIVE, NULL); break; case 3: if (ShowWindow(hIp,SW_SHOW)){ MessageBox(hWnd,"You are not connected to any server!","Error",MB_OK | MB_ICONERROR); break; } ShowWindow(hIp, SW_HIDE); GetWindowText(hChnl, string1, 26); sprintf(string2,"join %s ",string1); GetWindowText(hPas2, string1, 26); strcat(string2,string1); STS(string2); Sleep(250); if (answer==6) MessageBox(hWnd,"It was not possible to enter on the channel!","Error",MB_OK | MB_ICONERROR); break; case 4: if (ShowWindow(hIp,SW_SHOW)){ MessageBox(hWnd,"You are not connected to any server!","Error",MB_OK | MB_ICONERROR); break; } ShowWindow(hIp, SW_HIDE); GetWindowText(hChnl, string1, 26); sprintf(string2,"creg %s ",string1); GetWindowText(hPas2, string1, 26); strcat(string2,string1); STS(string2); Sleep(250); switch(answer){ case 0: MessageBox(hWnd,"Successful registration! Can enter!","Information",MB_OK | MB_ICONINFORMATION); break; case 7: MessageBox(hWnd,"Such channel is already registered!","Error",MB_OK | MB_ICONERROR); break; case 8: MessageBox(hWnd,"You are not registered user!","Error",MB_OK | MB_ICONERROR); break; } SendMessage(hIp ,WM_ACTIVATE, WA_ACTIVE, NULL); break; 29 case 5: hRoot=TreeView_GetSelection(hTree); TransSwitch=1; if (TreeView_GetParent(hTree,hRoot)!=NULL){ hRoot=TreeView_GetParent(hTree,hRoot); SendMessage(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot); } hRoot=GetTreeItem(item,NULL); sprintf(string1,"quit %s ",item->pszText); STS(string1); sprintf(string1,"%s.chnl",item->pszText); remove(string1); SendMessage(hTree, TVM_DELETEITEM, NULL, (LPARAM)hRoot); SendMessage(hIp ,WM_ACTIVATE, WA_ACTIVE, NULL); break; } break; } switch(HIWORD(wParam)){ case CBN_SELCHANGE: SendMessage(hCombo, CB_GETLBTEXT, SendMessage(hCombo, CB_GETCURSEL, NULL, NULL), (LPARAM)string1); SetWindowText(hDo,string1); break; case EN_SETFOCUS: switch(LOWORD(wParam)){ case MsgEdit: GetWindowText(hMsg, string1, 26); if (!strcmp("Enter the message",string1)) SendMessage (hMsg, WM_SETTEXT, 0, (LPARAM)""); break; case LoginEdit: GetWindowText(hNick, string1, 26); if (!strcmp("Nickname",string1)) SendMessage (hNick, WM_SETTEXT, 0, (LPARAM)""); break; case PswdEdit: GetWindowText(hPas1, string1, 26); if (!strcmp("Password",string1)) SendMessage (hPas1, WM_SETTEXT, 0, (LPARAM)""); break; case ChnEdit: GetWindowText(hChnl, string1, 26); if (!strcmp("Channel name",string1)) SendMessage (hChnl, WM_SETTEXT, 0, (LPARAM)""); break; } break; case EN_KILLFOCUS: switch(LOWORD(wParam)){ case MsgEdit: if (!SendMessage(hMsg, EM_LINELENGTH,0,NULL)) SendMessage (hMsg, WM_SETTEXT, 0, (LPARAM)"Enter the message"); break; case LoginEdit: 30 if (!SendMessage(hNick, EM_LINELENGTH,0,NULL)) SendMessage (hNick, WM_SETTEXT, 0, (LPARAM)"Nickname"); break; case PswdEdit: if (!SendMessage(hPas1, EM_LINELENGTH,0,NULL)) SendMessage (hPas1, WM_SETTEXT, 0, (LPARAM)"Password"); break; case ChnEdit: if (!SendMessage(hChnl, EM_LINELENGTH,0,NULL)) SendMessage (hChnl, WM_SETTEXT, 0, (LPARAM)"Channel name"); break; } break; } break; case WM_NOTIFY: switch(((LPNMHDR)lParam)->code){ case TVN_SELCHANGED: if (!TransSwitch){ hRoot=GetTreeItem(item,NULL); if (TreeView_GetParent(hTree,hRoot)!=NULL) break; sprintf(string1,"%s is active",item->pszText); SendMessage(hStatic2,WM_SETTEXT,NULL,(LPARAM)string1); GetTreeItem(item, SELECT); sprintf(log,"%s.chnl",item->pszText); f=fopen(log,"w"); GetWindowText(hLog,string1,maxLog+1); fprintf(f,"%s",string1); fclose(f); GetTreeItem(item, hRoot); sprintf(log,"%s.chnl",item->pszText); SELECT=hRoot; SendMessage(hLog, WM_SETTEXT, NULL, (LPARAM)""); f=fopen(log,"r"); if (f==NULL) break; fgets(string1,2,f); if (feof(f)) break; else rewind(f); while(!feof(f)){ fgets(string1,maxMsg,f); if (feof(f)) break; nLen = GetWindowTextLength (hLog); SendMessage (hLog, EM_SETSEL, nLen, nLen); SendMessage (hLog, EM_REPLACESEL, 0, (LPARAM)string1); } fclose(f); } break; } break; default: delete item; delete[] string1; delete[] string2; return DefWindowProc(hWnd, message, wParam, lParam); 31 } delete item; delete[] string1; delete[] string2; } 32