// The Master Thread implements an idea of synchrony. Its task // is to use barrier synchronization and let every thread run its // main loop OR event loop just once before not every other thread // has also proceeded in doing so // this ensures the "eventually entry" of any railway API code that is // sequentialized due to the use of simple binary semaphore mutex // variables // Every thread has its own localLOCK variable, that is increased in // every loop step, the thread must wait // if its own localLOCK is > 0. It is reset to 0 if ALL threads have // set their localLOCKs to > 0 and hence have done a step void* ThreadFunctionMaster(void* port) { int track; while (!MasterShutdown) { //do not wait for terminated threads if (localTERMINATED2) { localLOCK2 = 1; } //wait for all localTicks to be increased if ((localLOCK2 == 1)&&(1)) { //fill ContactMem and OccupiedMem array for (track = 0; track < 48; track++) { ContactMem[track][0] = getcontact(railway,track,FIRST,1); ContactMem[track][1] = getcontact(railway,track,SECOND,1); OccupiedMem[track] = trackused(railway,track); } //increase a tick counter (useless) TICK++; //if (DEBUGCONTROLLER) printf("TICK %d\n",TICK); localLOCK2 = 0; }//end if usleep(1000); // sleep for 1ms } return (void *)1; }
void GGPROTO::dccconnect(uin_t uin) { struct gg_dcc *local_dcc; MCONTACT hContact = getcontact(uin, 0, 0, NULL); DWORD ip, myuin; WORD port; debugLogA("dccconnect(): Connecting to uin %d.", uin); // If unknown user or not on list ignore if (!hContact) return; // Read user IP and port ip = swap32(getDword(hContact, GG_KEY_CLIENTIP, 0)); port = getWord(hContact, GG_KEY_CLIENTPORT, 0); myuin = getDword(GG_KEY_UIN, 0); // If not port nor ip nor my uin (?) specified if (!ip || !port || !uin) return; if (!(local_dcc = gg_dcc_get_file(ip, port, myuin, uin))) return; // Add client dcc to watches gg_EnterCriticalSection(&ft_mutex, "dccconnect", 36, "ft_mutex", 1); list_add(&watches, local_dcc, 0); gg_LeaveCriticalSection(&ft_mutex, "dccconnect", 36, 1, "ft_mutex", 1); }
HANDLE GGPROTO::AddToList(int flags, PROTOSEARCHRESULT *psr) { #ifdef DEBUGMODE debugLogA("AddToList(): id=%s"); #endif GGSEARCHRESULT *sr = (GGSEARCHRESULT *)psr; uin_t uin; if (psr->cbSize == sizeof(GGSEARCHRESULT)) uin = sr->uin; else uin = _ttoi(psr->id); return getcontact(uin, 1, flags & PALF_TEMPORARY ? 0 : 1, sr->nick); }
/* * Get nation argument. * If @arg is not empty, use it. * Else prompt for input using @prompt. * If no input is provided, return -1. * If the argument identifies a country, return its number. getnatp() * can be assumed to succeed for this number. * Else complain and return -1. * If HIDDEN is enabled, countries not contacted are not eligible * unless the player is a deity. */ int natarg(char *arg, char *prompt) { struct natstr *np = natargp(arg, prompt); if (!np) return -1; if (opt_HIDDEN) { if (!player->god && !getcontact(getnatp(player->cnum), np->nat_cnum)) { if (np->nat_stat != STAT_GOD) { pr("Country '%s' has not been contacted.\n", arg); return -1; } } } return np->nat_cnum; }
void __cdecl GGPROTO::dccmainthread(void*) { uin_t uin; gg_event *e; struct timeval tv; fd_set rd, wd; int ret; SOCKET maxfd; DWORD tick; list_t l; char szFilename[MAX_PATH]; // Zero up lists watches = transfers = requests = l = NULL; debugLogA("dccmainthread(): started. DCC Server Thread Starting"); // Readup number if (!(uin = getDword(GG_KEY_UIN, 0))) { debugLogA("dccmainthread(): No Gadu-Gadu number specified. Exiting."); if (hEvent) SetEvent(hEvent); #ifdef DEBUGMODE debugLogA("dccmainthread(): end 1."); #endif return; } // Create listen socket on config direct port if (!(dcc = gg_dcc_socket_create(uin, (uint16_t)getWord(GG_KEY_DIRECTPORT, GG_KEYDEF_DIRECTPORT)))) { debugLogA("dccmainthread(): Cannot create DCC listen socket. Exiting."); // Signalize mainthread we haven't start if (hEvent) SetEvent(hEvent); #ifdef DEBUGMODE debugLogA("dccmainthread(): end 2."); #endif return; } gg_dcc_port = dcc->port; gg_dcc_ip = inet_addr("255.255.255.255"); debugLogA("dccmainthread(): Listening on port %d.", gg_dcc_port); // Signalize mainthread we started if (hEvent) SetEvent(hEvent); // Add main dcc handler to watches list_add(&watches, dcc, 0); // Do while we are in the main server thread while(pth_dcc.dwThreadId && dcc) { // Timeouts tv.tv_sec = 1; tv.tv_usec = 0; // Prepare descriptiors for select FD_ZERO(&rd); FD_ZERO(&wd); for (maxfd = 0, l = watches; l; l = l->next) { gg_common *w = (gg_common*)l->data; if (!w || w->state == GG_STATE_ERROR || w->state == GG_STATE_IDLE || w->state == GG_STATE_DONE) continue; // Check if it's proper descriptor if (w->fd == -1) continue; if (w->fd > maxfd) maxfd = w->fd; if ((w->check & GG_CHECK_READ)) FD_SET(w->fd, &rd); if ((w->check & GG_CHECK_WRITE)) FD_SET(w->fd, &wd); } // Wait for data on selects ret = select(maxfd + 1, &rd, &wd, NULL, &tv); // Check for select error if (ret == -1) { if (errno == EBADF) debugLogA("dccmainthread(): Bad descriptor on select()."); else if (errno != EINTR) debugLogA("dccmainthread(): Unknown error on select()."); continue; } // Process watches (carefull with l) l = watches; gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); while (l) { struct gg_common *local_c = (gg_common*)l->data; struct gg_dcc *local_dcc = (gg_dcc*)l->data; struct gg_dcc7 *local_dcc7 = (gg_dcc7*)l->data; l = l->next; switch (local_c->type) { default: if (!local_dcc || (!FD_ISSET(local_dcc->fd, &rd) && !FD_ISSET(local_dcc->fd, &wd))) continue; ///////////////////////////////////////////////////////////////// // Process DCC events // Connection broken/closed gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 2, "ft_mutex", 1); if (!(e = gg_dcc_socket_watch_fd(local_dcc))) { debugLogA("dccmainthread(): Socket closed."); // Remove socket and _close gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); list_remove(&watches, local_dcc, 0); gg_dcc_socket_free(local_dcc); // Check if it's main socket if (local_dcc == dcc) dcc = NULL; continue; } else { gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); debugLogA("dccmainthread(): Event: %s", ggdebug_eventtype(e)); } switch(e->type) { // Client connected case GG_EVENT_DCC_NEW: list_add(&watches, e->event.dcc_new, 0); e->event.dcc_new = NULL; break; // case GG_EVENT_NONE: // If transfer in progress do status if (local_dcc->file_fd != -1 && local_dcc->offset > 0 && (((tick = GetTickCount()) - local_dcc->tick) > GGSTATREFRESHEVERY)) { PROTOFILETRANSFERSTATUS pfts; local_dcc->tick = tick; mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc->file_info.filename); memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS)); pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); pfts.hContact = (UINT_PTR)local_dcc->contact; pfts.flags = (local_dcc->type == GG_SESSION_DCC_SEND); pfts.pszFiles = NULL; pfts.totalFiles = 1; pfts.currentFileNumber = 0; pfts.totalBytes = local_dcc->file_info.size; pfts.totalProgress = local_dcc->offset; pfts.szWorkingDir = local_dcc->folder; pfts.szCurrentFile = szFilename; pfts.currentFileSize = local_dcc->file_info.size; pfts.currentFileProgress = local_dcc->offset; pfts.currentFileTime = 0; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 3, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc, (LPARAM)&pfts); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); } break; // Connection was successfuly ended case GG_EVENT_DCC_DONE: debugLogA("dccmainthread(): Client: %d, Transfer done ! Closing connection.", dcc->peer_uin); // Remove from watches list_remove(&watches, local_dcc, 0); // Close file & success if (local_dcc->file_fd != -1) { PROTOFILETRANSFERSTATUS pfts; mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc->file_info.filename); memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS)); pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); pfts.hContact = (UINT_PTR)local_dcc->contact; pfts.flags = (local_dcc->type == GG_SESSION_DCC_SEND); pfts.pszFiles = NULL; pfts.totalFiles = 1; pfts.currentFileNumber = 0; pfts.totalBytes = local_dcc->file_info.size; pfts.totalProgress = local_dcc->file_info.size; pfts.szWorkingDir = local_dcc->folder; pfts.szCurrentFile = szFilename; pfts.currentFileSize = local_dcc->file_info.size; pfts.currentFileProgress = local_dcc->file_info.size; pfts.currentFileTime = 0; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 4, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc, (LPARAM)&pfts); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); _close(local_dcc->file_fd); local_dcc->file_fd = -1; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 5, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_SUCCESS, local_dcc, 0); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); } // Free dcc gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL; break; // Client error case GG_EVENT_DCC_ERROR: switch (e->event.dcc_error) { case GG_ERROR_DCC_HANDSHAKE: debugLogA("dccmainthread(): Client: %d, Handshake error.", local_dcc->peer_uin); break; case GG_ERROR_DCC_NET: debugLogA("dccmainthread(): Client: %d, Network error.", local_dcc->peer_uin); break; case GG_ERROR_DCC_FILE: debugLogA("dccmainthread(): Client: %d, File read/write error.", local_dcc->peer_uin); break; case GG_ERROR_DCC_EOF: debugLogA("dccmainthread(): Client: %d, End of file/connection error.", local_dcc->peer_uin); break; case GG_ERROR_DCC_REFUSED: debugLogA("dccmainthread(): Client: %d, Connection refused error.", local_dcc->peer_uin); break; default: debugLogA("dccmainthread(): Client: %d, Unknown error.", local_dcc->peer_uin); } // Don't do anything if it's main socket if (local_dcc == dcc) break; // Remove from watches list_remove(&watches, local_dcc, 0); // Close file & fail if (local_dcc->contact) { _close(local_dcc->file_fd); local_dcc->file_fd = -1; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 6, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_FAILED, local_dcc, 0); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); } // Free dcc gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL; break; // Need file acknowledgement case GG_EVENT_DCC_NEED_FILE_ACK: debugLogA("dccmainthread(): Client: %d, File ack filename \"%s\" size %d.", local_dcc->peer_uin, local_dcc->file_info.filename, local_dcc->file_info.size); // Do not watch for transfer until user accept it list_remove(&watches, local_dcc, 0); // Add to waiting transfers list_add(&transfers, local_dcc, 0); ////////////////////////////////////////////////// // Add file recv request { // Make new ggtransfer struct local_dcc->contact = (void*)getcontact(local_dcc->peer_uin, 0, 0, NULL); TCHAR* filenameT = mir_utf8decodeT((char*)dcc->file_info.filename); PROTORECVFILET pre = {0}; pre.dwFlags = PRFF_TCHAR; pre.fileCount = 1; pre.timestamp = time(NULL); pre.descr.t = filenameT; pre.files.t = &filenameT; pre.lParam = (LPARAM)local_dcc; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 7, "ft_mutex", 1); ProtoChainRecvFile((UINT_PTR)local_dcc->contact, &pre); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); mir_free(filenameT); } break; // Need client accept case GG_EVENT_DCC_CLIENT_ACCEPT: debugLogA("dccmainthread(): Client: %d, Client accept.", local_dcc->peer_uin); // Check if user is on the list and if it is my uin if (getcontact(local_dcc->peer_uin, 0, 0, NULL) && getDword(GG_KEY_UIN, -1) == local_dcc->uin) break; // Kill unauthorized dcc list_remove(&watches, dcc, 0); gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL; break; // Client connected as we wished to (callback) case GG_EVENT_DCC_CALLBACK: { int found = 0; debugLogA("dccmainthread(): Callback from client %d.", local_dcc->peer_uin); // Seek for stored callback request for (l = requests; l; l = l->next) { struct gg_dcc *req = (gg_dcc*)l->data; if (req && req->peer_uin == local_dcc->peer_uin) { gg_dcc_set_type(local_dcc, GG_SESSION_DCC_SEND); found = 1; // Copy data req ===> dcc local_dcc->folder = req->folder; local_dcc->contact = req->contact; local_dcc->file_fd = req->file_fd; memcpy(&local_dcc->file_info, &req->file_info, sizeof(struct gg_file_info)); // Copy data back to dcc ===> req memcpy(req, local_dcc, sizeof(struct gg_dcc)); // Remove request list_remove(&requests, req, 0); // Remove dcc from watches list_remove(&watches, local_dcc, 0); // Add request to watches list_add(&watches, req, 0); // Free old dat gg_free_dcc(local_dcc); debugLogA("dccmainthread(): Found stored request to client %d, filename \"%s\" size %d, folder \"%s\".", req->peer_uin, req->file_info.filename, req->file_info.size, req->folder); break; } } if (!found) { debugLogA("dccmainthread(): Unknown request to client %d.", local_dcc->peer_uin); // Kill unauthorized dcc list_remove(&watches, local_dcc, 0); gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL; } break; } } // Free event gg_free_event(e); break; case GG_SESSION_DCC7_SOCKET: case GG_SESSION_DCC7_GET: case GG_SESSION_DCC7_SEND: case GG_SESSION_DCC7_VOICE: if (!local_dcc7 || (!FD_ISSET(local_dcc7->fd, &rd) && !FD_ISSET(local_dcc7->fd, &wd))) continue; ///////////////////////////////////////////////////////////////// // Process DCC7 events // Connection broken/closed gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 8, "ft_mutex", 1); if (!(e = gg_dcc7_watch_fd(local_dcc7))) { debugLogA("dccmainthread(): Socket closed."); // Remove socket and _close gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); list_remove(&watches, local_dcc7, 0); gg_dcc7_free(local_dcc7); continue; } else { gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); debugLogA("dccmainthread(): Event: %s", ggdebug_eventtype(e)); } switch(e->type) { // case GG_EVENT_NONE: // If transfer in progress do status if (local_dcc7->file_fd != -1 && local_dcc7->offset > 0 && (((tick = GetTickCount()) - local_dcc7->tick) > GGSTATREFRESHEVERY)) { PROTOFILETRANSFERSTATUS pfts; local_dcc7->tick = tick; mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc7->filename); memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS)); pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); pfts.hContact = (UINT_PTR)local_dcc7->contact; pfts.flags = (local_dcc7->type == GG_SESSION_DCC7_SEND); pfts.pszFiles = NULL; pfts.totalFiles = 1; pfts.currentFileNumber = 0; pfts.totalBytes = local_dcc7->size; pfts.totalProgress = local_dcc7->offset; pfts.szWorkingDir = local_dcc7->folder; pfts.szCurrentFile = szFilename; pfts.currentFileSize = local_dcc7->size; pfts.currentFileProgress = local_dcc7->offset; pfts.currentFileTime = 0; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 9, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc7, (LPARAM)&pfts); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); } break; // Connection was successfuly ended case GG_EVENT_DCC7_DONE: debugLogA("dccmainthread(): Client: %d, Transfer done ! Closing connection.", dcc->peer_uin); // Remove from watches list_remove(&watches, local_dcc7, 0); // Close file & success if (local_dcc7->file_fd != -1) { PROTOFILETRANSFERSTATUS pfts; mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc7->filename); memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS)); pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS); pfts.hContact = (UINT_PTR)local_dcc7->contact; pfts.flags = (local_dcc7->type == GG_SESSION_DCC7_SEND); pfts.pszFiles = NULL; pfts.totalFiles = 1; pfts.currentFileNumber = 0; pfts.totalBytes = local_dcc7->size; pfts.totalProgress = local_dcc7->size; pfts.szWorkingDir = local_dcc7->folder; pfts.szCurrentFile = szFilename; pfts.currentFileSize = local_dcc7->size; pfts.currentFileProgress = local_dcc7->size; pfts.currentFileTime = 0; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 10, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc7, (LPARAM)&pfts); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); _close(local_dcc7->file_fd); local_dcc7->file_fd = -1; gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 11, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_SUCCESS, local_dcc7, 0); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); } // Free dcc gg_dcc7_free(local_dcc7); break; // Client error case GG_EVENT_DCC7_ERROR: switch (e->event.dcc7_error) { case GG_ERROR_DCC7_HANDSHAKE: debugLogA("dccmainthread(): Client: %d, Handshake error.", local_dcc7->peer_uin); break; case GG_ERROR_DCC7_NET: debugLogA("dccmainthread(): Client: %d, Network error.", local_dcc7->peer_uin); break; case GG_ERROR_DCC7_FILE: debugLogA("dccmainthread(): Client: %d, File read/write error.", local_dcc7->peer_uin); break; case GG_ERROR_DCC7_EOF: debugLogA("dccmainthread(): Client: %d, End of file/connection error.", local_dcc7->peer_uin); break; case GG_ERROR_DCC7_REFUSED: debugLogA("dccmainthread(): Client: %d, Connection refused error.", local_dcc7->peer_uin); break; case GG_ERROR_DCC7_RELAY: debugLogA("dccmainthread(): Client: %d, Relay connection error.", local_dcc7->peer_uin); break; default: debugLogA("dccmainthread(): Client: %d, Unknown error.", local_dcc7->peer_uin); } // Remove from watches list_remove(&watches, local_dcc7, 0); // Close file & fail if (local_dcc7->file_fd != -1) { _close(local_dcc7->file_fd); local_dcc7->file_fd = -1; } if (local_dcc7->contact) { gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 12, "ft_mutex", 1); ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_FAILED, local_dcc7, 0); gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1); } // Free dcc gg_dcc7_free(local_dcc7); break; } // Free event gg_free_event(e); break; } } gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 1, "ft_mutex", 1); } // Close all dcc client sockets for (l = watches; l; l = l->next) { struct gg_common *c = (gg_common*)l->data; if (!c) continue; if (c->type == GG_SESSION_DCC7_SOCKET || c->type == GG_SESSION_DCC7_SEND || c->type == GG_SESSION_DCC7_GET) { struct gg_dcc7 *local_dcc7 = (gg_dcc7*)l->data; gg_dcc7_free(local_dcc7); } else { struct gg_dcc *local_dcc = (gg_dcc*)l->data; gg_dcc_socket_free(local_dcc); // Check if it's main socket if (local_dcc == dcc) dcc = NULL; } } // Close all waiting for aknowledgle transfers for (l = transfers; l; l = l->next) { struct gg_common *c = (gg_common*)l->data; if (!c) continue; if (c->type == GG_SESSION_DCC7_SOCKET || c->type == GG_SESSION_DCC7_SEND || c->type == GG_SESSION_DCC7_GET) { struct gg_dcc7 *local_dcc7 = (gg_dcc7*)l->data; gg_dcc7_free(local_dcc7); } else { struct gg_dcc *local_dcc = (gg_dcc*)l->data; gg_dcc_socket_free(local_dcc); } } // Close all waiting dcc requests for (l = requests; l; l = l->next) { struct gg_dcc *local_dcc = (gg_dcc*)l->data; if (local_dcc) gg_free_dcc(local_dcc); } list_destroy(watches, 0); list_destroy(transfers, 0); list_destroy(requests, 0); gg_dcc_port = 0; gg_dcc_ip = 0; debugLogA("dccmainthread(): end. DCC Server Thread Ending"); }
//////////////////////////////////////////////////////////////////////////////// // This is main groupchat initialization routine // TCHAR* GGPROTO::gc_getchat(uin_t sender, uin_t *recipients, int recipients_count) { list_t l; GGGC *chat; TCHAR id[32]; uin_t uin; DBVARIANT dbv; GCDEST gcd = { m_szModuleName, 0, GC_EVENT_ADDGROUP }; GCEVENT gce = { sizeof(gce), &gcd }; debugLogA("gc_getchat(): Count %d.", recipients_count); if (!recipients) return NULL; // Look for existing chat for(l = chats; l; l = l->next) { chat = (GGGC *)l->data; if (!chat) continue; if (chat->recipients_count == recipients_count + (sender ? 1 : 0)) { int i, j, found = 0, sok = (sender == 0); if (!sok) { for (i = 0; i < chat->recipients_count; i++) { if (sender == chat->recipients[i]) { sok = 1; break; } } } if (sok) for(i = 0; i < chat->recipients_count; i++) for(j = 0; j < recipients_count; j++) if (recipients[j] == chat->recipients[i]) found++; // Found all recipients if (found == recipients_count) { if (chat->ignore) debugLog(_T("gc_getchat(): Ignoring existing id %s, size %d."), chat->id, chat->recipients_count); else debugLog(_T("gc_getchat(): Returning existing id %s, size %d."), chat->id, chat->recipients_count); return !(chat->ignore) ? chat->id : NULL; } } } // Make new uin list to chat mapping chat = (GGGC *)malloc(sizeof(GGGC)); UIN2IDT(gc_id ++, chat->id); chat->ignore = FALSE; // Check groupchat policy (new) / only for incoming if (sender) { int unknown = (getcontact(sender, 0, 0, NULL) == NULL), unknownSender = unknown; for(int i = 0; i < recipients_count; i++) if (!getcontact(recipients[i], 0, 0, NULL)) unknown ++; if ((getWord(GG_KEY_GC_POLICY_DEFAULT, GG_KEYDEF_GC_POLICY_DEFAULT) == 2) || (getWord(GG_KEY_GC_POLICY_TOTAL, GG_KEYDEF_GC_POLICY_TOTAL) == 2 && recipients_count >= getWord(GG_KEY_GC_COUNT_TOTAL, GG_KEYDEF_GC_COUNT_TOTAL)) || (getWord(GG_KEY_GC_POLICY_UNKNOWN, GG_KEYDEF_GC_POLICY_UNKNOWN) == 2 && unknown >= getWord(GG_KEY_GC_COUNT_UNKNOWN, GG_KEYDEF_GC_COUNT_UNKNOWN))) chat->ignore = TRUE; if (!chat->ignore && ((getWord(GG_KEY_GC_POLICY_DEFAULT, GG_KEYDEF_GC_POLICY_DEFAULT) == 1) || (getWord(GG_KEY_GC_POLICY_TOTAL, GG_KEYDEF_GC_POLICY_TOTAL) == 1 && recipients_count >= getWord(GG_KEY_GC_COUNT_TOTAL, GG_KEYDEF_GC_COUNT_TOTAL)) || (getWord(GG_KEY_GC_POLICY_UNKNOWN, GG_KEYDEF_GC_POLICY_UNKNOWN) == 1 && unknown >= getWord(GG_KEY_GC_COUNT_UNKNOWN, GG_KEYDEF_GC_COUNT_UNKNOWN)))) { TCHAR *senderName = unknownSender ? TranslateT("Unknown") : pcli->pfnGetContactDisplayName(getcontact(sender, 0, 0, NULL), 0); TCHAR error[256]; mir_sntprintf(error, TranslateT("%s has initiated conference with %d participants (%d unknowns).\nDo you want to participate?"), senderName, recipients_count + 1, unknown); chat->ignore = MessageBox(NULL, error, m_tszUserName, MB_OKCANCEL | MB_ICONEXCLAMATION) != IDOK; } if (chat->ignore) { // Copy recipient list chat->recipients_count = recipients_count + 1; chat->recipients = (uin_t *)calloc(chat->recipients_count, sizeof(uin_t)); int i = 0; for(; i < recipients_count; i++) chat->recipients[i] = recipients[i]; if (sender) chat->recipients[i] = sender; debugLog(_T("gc_getchat(): Ignoring new chat %s, count %d."), chat->id, chat->recipients_count); list_add(&chats, chat, 0); return NULL; } } // Create new chat window TCHAR status[256]; TCHAR *senderName; if (sender) { senderName = pcli->pfnGetContactDisplayName(getcontact(sender, 1, 0, NULL), 0); mir_sntprintf(status, TranslateT("%s initiated the conference.") , senderName); } else { senderName = NULL; mir_sntprintf(status, TranslateT("This is my own conference.")); } GCSESSION gcwindow = { sizeof(gcwindow) }; gcwindow.iType = GCW_CHATROOM; gcwindow.pszModule = m_szModuleName; gcwindow.ptszName = sender ? senderName : TranslateT("Conference"); gcwindow.ptszID = chat->id; gcwindow.dwItemData = (UINT_PTR)chat; gcwindow.ptszStatusbarText = status; // Here we put nice new hash sign TCHAR *name = (TCHAR*)calloc(mir_tstrlen(gcwindow.ptszName) + 2, sizeof(TCHAR)); *name = '#'; mir_tstrcpy(name + 1, gcwindow.ptszName); gcwindow.ptszName = name; // Create new room if (CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM) &gcwindow)) { debugLog(_T("gc_getchat(): Cannot create new chat window %s."), chat->id); free(name); free(chat); return NULL; } free(name); gcd.ptszID = chat->id; gce.ptszUID = id; gce.dwFlags = GCEF_ADDTOLOG; gce.time = 0; // Add normal group gce.ptszStatus = TranslateT("Participants"); CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); gcd.iType = GC_EVENT_JOIN; // Add myself if (uin = getDword(GG_KEY_UIN, 0)) { UIN2IDT(uin, id); TCHAR* nickT; if (!getTString(GG_KEY_NICK, &dbv)) { nickT = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } else { nickT = mir_tstrdup(TranslateT("Me")); } gce.ptszNick = nickT; gce.bIsMe = 1; CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); mir_free(nickT); debugLog(_T("gc_getchat(): Myself %s: %s (%s) to the list..."), gce.ptszUID, gce.ptszNick, gce.ptszStatus); } else debugLogA("gc_getchat(): Myself adding failed with uin %d !!!", uin); // Copy recipient list chat->recipients_count = recipients_count + (sender ? 1 : 0); chat->recipients = (uin_t *)calloc(chat->recipients_count, sizeof(uin_t)); int i; for(i = 0; i < recipients_count; i++) chat->recipients[i] = recipients[i]; if (sender) chat->recipients[i] = sender; // Add contacts for(i = 0; i < chat->recipients_count; i++) { MCONTACT hContact = getcontact(chat->recipients[i], 1, 0, NULL); UIN2IDT(chat->recipients[i], id); if (hContact && (name = pcli->pfnGetContactDisplayName(hContact, 0)) != NULL) gce.ptszNick = name; else gce.ptszNick = TranslateT("'Unknown'"); gce.bIsMe = 0; gce.dwFlags = 0; debugLog(_T("gc_getchat(): Added %s: %s (%s) to the list..."), gce.ptszUID, gce.ptszNick, gce.ptszStatus); CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); } gcd.iType = GC_EVENT_CONTROL; CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce); CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); debugLog(_T("gc_getchat(): Returning new chat window %s, count %d."), chat->id, chat->recipients_count); list_add(&chats, chat, 0); return chat->id; }
int GGPROTO::gc_event(WPARAM, LPARAM lParam) { GCHOOK *gch = (GCHOOK *)lParam; GGGC *chat = NULL; uin_t uin; // Check if we got our protocol, and fields are set if (!gch || !gch->pDest || !gch->pDest->ptszID || !gch->pDest->pszModule || mir_strcmpi(gch->pDest->pszModule, m_szModuleName) || !(uin = getDword(GG_KEY_UIN, 0)) || !(chat = gc_lookup(gch->pDest->ptszID))) return 0; // Window terminated (Miranda exit) if (gch->pDest->iType == SESSION_TERMINATE) { debugLog(_T("gc_event(): Terminating chat %x, id %s from chat window..."), chat, gch->pDest->ptszID); // Destroy chat entry free(chat->recipients); list_remove(&chats, chat, 1); // Remove contact from contact list (duh!) should be done by chat.dll !! for (MCONTACT hContact = db_find_first(); hContact; ) { MCONTACT hNext = db_find_next(hContact); DBVARIANT dbv; if (!getTString(hContact, "ChatRoomID", &dbv)) { if (dbv.ptszVal && !mir_tstrcmp(gch->pDest->ptszID, dbv.ptszVal)) CallService(MS_DB_CONTACT_DELETE, hContact, 0); db_free(&dbv); } hContact = hNext; } return 1; } // Message typed / send only if online if (isonline() && (gch->pDest->iType == GC_USER_MESSAGE) && gch->ptszText) { TCHAR id[32]; UIN2IDT(uin, id); DBVARIANT dbv; GCDEST gcd = { m_szModuleName, gch->pDest->ptszID, GC_EVENT_MESSAGE }; GCEVENT gce = { sizeof(gce), &gcd }; gce.ptszUID = id; gce.ptszText = gch->ptszText; TCHAR* nickT; if (!getTString(GG_KEY_NICK, &dbv)){ nickT = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } else nickT = mir_tstrdup(TranslateT("Me")); gce.ptszNick = nickT; // Get rid of CRLF at back int lc = (int)mir_tstrlen(gch->ptszText) - 1; while(lc >= 0 && (gch->ptszText[lc] == '\n' || gch->ptszText[lc] == '\r')) gch->ptszText[lc --] = 0; gce.time = time(NULL); gce.bIsMe = 1; gce.dwFlags = GCEF_ADDTOLOG; debugLog(_T("gc_event(): Sending conference message to room %s, \"%s\"."), gch->pDest->ptszID, gch->ptszText); CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); mir_free(nickT); T2Utf pszText_utf8(gch->ptszText); gg_EnterCriticalSection(&sess_mutex, "gc_event", 57, "sess_mutex", 1); gg_send_message_confer(sess, GG_CLASS_CHAT, chat->recipients_count, chat->recipients, pszText_utf8); gg_LeaveCriticalSection(&sess_mutex, "gc_event", 57, 1, "sess_mutex", 1); return 1; } // Privmessage selected if (gch->pDest->iType == GC_USER_PRIVMESS) { MCONTACT hContact = NULL; if ((uin = _ttoi(gch->ptszUID)) && (hContact = getcontact(uin, 1, 0, NULL))) CallService(MS_MSG_SENDMESSAGE, hContact, 0); } debugLog(_T("gc_event(): Unhandled event %d, chat %x, uin %d, text \"%s\"."), gch->pDest->iType, chat, uin, gch->ptszText); return 0; }
int news(void) { struct natstr *natp; time_t now; int page; time_t then; time_t delta; struct nwsstr nws; struct nstr_item nstr; int page_has_news[N_MAX_PAGE + 1]; int there_is_news = 0; short sectors_taken[MAXNOC][MAXNOC]; short sectors_delta; short max_delta = -1; short abs_delta; short k; int sectors_were_taken = 0; natid i, j; char num[128]; char *verb; if (!snxtitem(&nstr, EF_NEWS, "*", NULL)) return RET_SYN; memset(page_has_news, 0, sizeof(page_has_news)); memset(sectors_taken, 0, sizeof(sectors_taken)); (void)time(&now); natp = getnatp(player->cnum); then = natp->nat_newstim; if (player->argp[1]) { /* * We want to hide events before contact. Proper solution * would be to timestamp the contact. Cheesy approximation: * disable old news. */ if (opt_HIDDEN && !player->god) { pr("Sorry, argument doesn't work with HIDDEN enabled\n"); return RET_FAIL; } delta = days(atoi(player->argp[1])); then = now - delta; } natp->nat_newstim = now; head(); pr("\nThe details of Empire news since %s", ctime(&then)); while (nxtitem(&nstr, &nws)) { if (!nws.nws_vrb || CANT_HAPPEN(nws.nws_vrb > N_MAX_VERB)) continue; if (nws.nws_when < then) continue; if (opt_HIDDEN) { if (!player->god && !(getcontact(getnatp(player->cnum), nws.nws_ano) && getcontact(getnatp(player->cnum), nws.nws_vno))) continue; } ++page_has_news[rpt[(int)nws.nws_vrb].r_newspage]; ++there_is_news; } for (page = 1; page <= N_MAX_PAGE; page++) { if (!page_has_news[page]) continue; pr("\n\t === %s ===\n", page_headings[page].name); snxtitem_rewind(&nstr); while (nxtitem(&nstr, &nws)) { if (CANT_HAPPEN(nws.nws_vrb > N_MAX_VERB)) continue; if (rpt[(int)nws.nws_vrb].r_newspage != page) continue; if (nws.nws_when < then) continue; if (nws.nws_ntm == 0) nws.nws_ntm = 1; if (opt_HIDDEN) { if (!player->god && !(getcontact(getnatp(player->cnum), nws.nws_ano) && getcontact(getnatp(player->cnum), nws.nws_vno))) continue; } if (page == N_FRONT && (nws.nws_vrb == N_WON_SECT || nws.nws_vrb == N_AWON_SECT || nws.nws_vrb == N_PWON_SECT)) { sectors_taken[nws.nws_ano][nws.nws_vno] += nws.nws_ntm; sectors_were_taken += nws.nws_ntm; } preport(&nws); } } if (sectors_were_taken) { for (i = 0; i < MAXNOC; ++i) { for (j = 0; j < i; ++j) { sectors_delta = sectors_taken[i][j] - sectors_taken[j][i]; if (max_delta < abs(sectors_delta)) max_delta = abs(sectors_delta); } } pr("\n\t === The Bottom Line ==\n"); for (k = max_delta; k > 0; --k) { for (i = 0; i < MAXNOC; ++i) { for (j = 0; j < i; ++j) { sectors_delta = sectors_taken[i][j] - sectors_taken[j][i]; abs_delta = abs(sectors_delta); if (abs_delta != k) continue; if (abs_delta == 1) verb = "stole"; else if (abs_delta < 4) verb = "took"; else if (abs_delta < 8) verb = "captured"; else verb = "seized"; if (sectors_delta > 0) { numstr(num, abs_delta); pr("%s %s %s sector%s from %s\n", cname(i), verb, num, splur(sectors_delta), cname(j)); } else if (sectors_delta < 0) { numstr(num, abs_delta); pr("%s %s %s sector%s from %s\n", cname(j), verb, num, splur(-sectors_delta), cname(i)); } } } } } if (!there_is_news) pr("\nNo news at the moment...\n"); return 0; }