void TcpClient::CRecv(char *buf_, size_t length_, long timeout_) { int retval; fd_set read_fds; size_t recv_bytes = 0; struct timeval timeout; struct timeval* ptimeout; while( recv_bytes != length_ ) { FD_ZERO(&read_fds); FD_SET(this->sock_fd, &read_fds); // 超时设置 ptimeout= TranslateTime(timeout_, &timeout); // 等待套接字可读 while((retval = select(this->sock_fd + 1, &read_fds, NULL, NULL, ptimeout)) == -1 && errno == EINTR); // select 成功返回 if ( retval > 0 ) { if (FD_ISSET(this->sock_fd, &read_fds)) { int bytes; while( (bytes = recv(this->sock_fd, buf_ + recv_bytes, length_ - recv_bytes, MSG_DONTWAIT)) == -1 && errno == EINTR); if(bytes == -1 && errno == EAGAIN) { continue; } else if (bytes == 0) // 连接被关闭 { Throw("socket closed by client", 0); } else if (bytes < 0) { Throw("socket error",errno); } recv_bytes += bytes; } } else if( retval == 0 ) { Throw("socket time out", 0); } else { Throw("select failed", errno); } } return; }
int TcpClient::Send(const char *buf_, size_t length_, long timeout_) { int retval; int bytes; fd_set write_fds; struct timeval timeout; struct timeval* ptimeout; size_t tol = 0; while(tol < length_) { FD_ZERO(&write_fds); FD_SET(this->sock_fd, &write_fds); // 设置超时 ptimeout= TranslateTime(timeout_, &timeout); // 等待套接字可写 while((retval = select(this->sock_fd + 1, NULL, &write_fds, NULL, ptimeout)) == -1 && errno == EINTR); // select 成功返回 if( retval > 0 ) { if (FD_ISSET(this->sock_fd, &write_fds)) { // 发送数据 while( (bytes = send(this->sock_fd, buf_+tol, length_-tol, MSG_DONTWAIT)) == -1 && errno == EINTR ); if(bytes == -1 && errno == EAGAIN) { continue; } else if (bytes < 0) { Throw("socket error",errno); } else { tol += bytes; //break; } } } else if( retval == 0 ) { Throw("Socket time out", 0); } else { Throw("Select failed", errno); } } return tol; }
void TcpClient::CSend(const char *buf_, size_t length_, long timeout_) { int retval; fd_set write_fds; size_t sent_bytes = 0; struct timeval timeout; struct timeval* ptimeout; while(sent_bytes != length_) { FD_ZERO(&write_fds); FD_SET(this->sock_fd, &write_fds); // 超时设置 ptimeout= TranslateTime(timeout_, &timeout); // 等待套接字可写 while((retval = select(this->sock_fd + 1, NULL, &write_fds, NULL, ptimeout)) == -1 && errno == EINTR); if( retval > 0 ) { if (FD_ISSET(this->sock_fd, &write_fds)) { int bytes; while( (bytes = send(this->sock_fd, buf_ + sent_bytes, length_ - sent_bytes, MSG_DONTWAIT)) == -1 && errno == EINTR ); if(bytes == -1 && errno == EAGAIN) { continue; } else if (bytes < 0) { Throw("socket error",errno); } sent_bytes += bytes; } } else if( retval == 0 ) { Throw("Socket time out", 0); } else { Throw("Select failed", errno); } } return; }
/*********************************************************************** * * FUNCTION: SelectTime * * DESCRIPTION: Display a form showing a start and end time. * Allow the user to change the time and then * return them. * pTimeDiff. * * PARAMETERS: pStartTime - pointer to TimeType * pEndTime - pointer to TimeType * untimed - true if there isn't a time. * title - string containing the title * startOfDay - used when "All Day" button selected. * endOfDay - our used when "All Day" button selected. * startOfDisplay - first hour initially visible * * RETURNED: True if the time was changed by the user. * The first three parameters may change. * * REVISION HISTORY: * Name Date Description * ---- ---- ----------- * roger 12/2/94 Initial Revision * trev 08/12/97 made non modified passed variables constant * css 06/08/99 added new parameter & "All Day" button for gromit change. * ***********************************************************************/ Boolean SelectTime (TimeType * startTimeP, TimeType * endTimeP, Boolean untimed, const Char * titleP, Int16 startOfDay, Int16 endOfDay, Int16 startOfDisplay) { Int16 firstHour; Char startTimeText [timeStringLength]; Char endTimeText [timeStringLength]; Char timeChars [timeStringLength]; TimePtr timeP; FormType *originalForm, *frm; ListPtr hoursLst, minutesLst; ControlPtr startTimeCtl, endTimeCtl; EventType event; Boolean confirmed = false; MemHandle hoursItems; TimeType startTime, endTime, timeDiff; TimeFormatType timeFormat; ChangingTimeType changingTime; // Get the time format from the system preerances; timeFormat = (TimeFormatType)PrefGetPreference(prefTimeFormat); // Because this routine only deals with minutes in five minute // intervals we convert the proposed times from those passed. startTime.hours = startTimeP->hours; startTime.minutes = startTimeP->minutes; endTime.hours = endTimeP->hours; endTime.minutes = endTimeP->minutes; TimeDifference (&endTime, &startTime, &timeDiff); // Make sure the end time is displayable (clips at 11:55 pm) AdjustTimes (&startTime, &endTime, &timeDiff, changingStartTime); // Clear the buffer that holds written characters. *timeChars = 0; startOfDisplay = min (startOfDisplay, 12); originalForm = FrmGetActiveForm(); frm = (FormType *) FrmInitForm (TimeSelectorForm); FrmSetActiveForm (frm); hoursLst = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorHourList)); minutesLst = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorMinuteList)); startTimeCtl = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorStartTimeButton)); endTimeCtl = FrmGetObjectPtr (frm, FrmGetObjectIndex (frm, TimeSelectorEndTimeButton)); // Set list to use either 12 or 24 hour time hoursItems = SysFormPointerArrayToStrings ( ((timeFormat == tfColon24h) || (timeFormat == tfDot24h)) ? (Char *) Hours24Array() : (Char *) Hours12Array(), 24); LstSetListChoices (hoursLst, MemHandleLock(hoursItems), 24); LstSetTopItem (hoursLst, startOfDisplay); // Used to do LstMakeItemVisible (hoursLst, startTime.hours); no longer. if (! untimed) { LstSetSelection (hoursLst, startTime.hours); LstSetSelection (minutesLst, startTime.minutes / 5); CtlSetValue (startTimeCtl, true); changingTime = changingStartTime; } else { // The hour list is dynamically created and doesn't have a selection LstSetSelection (minutesLst, noListSelection); changingTime = changingNoTime; } // Set the start and end time buttons to the current times or blank them // if No Time is selected. SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, untimed); // This needs to be taken out when SelectTimeV33 goes away. It allows for backward // compatibility for this change of adding the end of day variable as a parameter. if (endOfDay != noDisplayOfAllDay) { FrmShowObject (frm, FrmGetObjectIndex (frm, TimeSelectorAllDayButton)); } FrmSetTitle (frm, (Char *) titleP); FrmDrawForm (frm); while (true) { EvtGetEvent (&event, evtWaitForever); if (SysHandleEvent ((EventType *)&event)) continue; if (event.eType == appStopEvent) { // Cancel the dialog and repost this event for the app EvtAddEventToQueue(&event); confirmed = false; break; } // Handle these before the form does to overide the default behavior if (changingTime == changingNoTime && event.eType == lstEnterEvent && event.data.lstEnter.listID == TimeSelectorMinuteList) { SndPlaySystemSound(sndError); continue; } FrmHandleEvent (frm, &event); // If the start or end time buttons are pressed then change // the time displayed in the lists. if (event.eType == ctlSelectEvent) { // "Ok" button pressed? if (event.data.ctlSelect.controlID == TimeSelectorOKButton) { confirmed = true; } // "Cancel" button pressed? else if (event.data.ctlSelect.controlID == TimeSelectorCancelButton) { break; } // Start time button pressed? else if (event.data.ctlSelect.controlID == TimeSelectorStartTimeButton) { if (changingTime != changingStartTime) { if (changingTime == changingNoTime) { SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, false); } CtlSetValue (endTimeCtl, false); LstSetSelection (hoursLst, startTime.hours); LstSetSelection (minutesLst, startTime.minutes / 5); changingTime = changingStartTime; } else CtlSetValue(startTimeCtl, true); } // End time button pressed? else if (event.data.ctlSelect.controlID == TimeSelectorEndTimeButton) { if (changingTime != changingEndTime) { if (changingTime == changingNoTime) { SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, false); } CtlSetValue(startTimeCtl, false); LstSetSelection (hoursLst, endTime.hours); LstSetSelection (minutesLst, endTime.minutes / 5); changingTime = changingEndTime; } else CtlSetValue(endTimeCtl, true); } // No time button pressed? else if (event.data.ctlSelect.controlID == TimeSelectorNoTimeButton) { if (changingTime != changingNoTime) { if (changingTime == changingStartTime) CtlSetValue(startTimeCtl, false); else CtlSetValue(endTimeCtl, false); SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, true); LstSetSelection (hoursLst, noListSelection); LstSetSelection (minutesLst, noListSelection); changingTime = changingNoTime; } // Get us out of this form display now. confirmed = true; } // All day button pressed? else if (event.data.ctlSelect.controlID == TimeSelectorAllDayButton) { if (changingTime != changingNoTime) { if (changingTime == changingStartTime) CtlSetValue(startTimeCtl, false); else CtlSetValue(endTimeCtl, false); LstSetSelection (hoursLst, noListSelection); LstSetSelection (minutesLst, noListSelection); changingTime = changingNoTime; } // No matter what, the minutes are 0 for both because only the hour is registered for start/end // times. startTime.minutes = 0; endTime.minutes = 0; startTime.hours = startOfDay; endTime.hours = endOfDay; // Set the times to the new times. SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, true); // Get us out of this form display now. First set the changing time to anything but the changingNoTime value // so that the pointers at the end of this function get set correctly. changingTime = changingStartTime; confirmed = true; } // Clear the buffer that holds written characters. *timeChars = 0; } // If either list is changed then get the new time. If the // start time is changed then change the end time so that the // the time difference remains the same. If the end time is // changed then make sure the end time isn't before the start // time. Also calculate a new time difference. else if (event.eType == lstSelectEvent) { // First, get the info from the list which has changed. if (event.data.lstSelect.listID == TimeSelectorHourList) { if (changingTime == changingStartTime) startTime.hours = (UInt8) LstGetSelection (hoursLst); else if (changingTime == changingEndTime) endTime.hours = (UInt8) LstGetSelection (hoursLst); else if (changingTime == changingNoTime) { startTime.hours = (UInt8) LstGetSelection (hoursLst); SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, false); CtlSetValue (endTimeCtl, false); LstSetSelection (minutesLst, startTime.minutes / 5); changingTime = changingStartTime; } } else if (event.data.lstSelect.listID == TimeSelectorMinuteList) { if (changingTime == changingStartTime) startTime.minutes = (UInt8) LstGetSelection (minutesLst) * 5; else if (changingTime == changingEndTime) endTime.minutes = (UInt8) LstGetSelection (minutesLst) * 5; else if (changingTime == changingNoTime) { ErrNonFatalDisplay("lstEnterEvent not being filtered."); } } if (AdjustTimes (&startTime, &endTime, &timeDiff, changingTime)) { if (changingTime == changingStartTime) { TimeToAscii (startTime.hours, startTime.minutes, timeFormat, startTimeText); CtlSetLabel (startTimeCtl, startTimeText); } else if (changingTime == changingEndTime) { LstSetSelection (hoursLst, startTime.hours); LstSetSelection (minutesLst, startTime.minutes / 5); } } TimeToAscii(endTime.hours, endTime.minutes, timeFormat, endTimeText); CtlSetLabel(endTimeCtl, endTimeText); // Clear the buffer that holds written characters. *timeChars = 0; } // Handle character written in the time picker. else if (event.eType == keyDownEvent) { if (changingTime == changingEndTime) { timeP = &endTime; firstHour = startTime.hours; } else { timeP = &startTime; firstHour = startOfDisplay; } // If a backspace character was written, change the time picker's // current setting to "no-time". if (event.data.keyDown.chr == backspaceChr) { *timeChars = 0; if (changingTime != changingNoTime) { if (changingTime == changingStartTime) CtlSetValue (startTimeCtl, false); else CtlSetValue (endTimeCtl, false); SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, true); LstSetSelection (hoursLst, noListSelection); LstSetSelection (minutesLst, noListSelection); changingTime = changingNoTime; } } // A linefeed character confirms the dialog box. else if (event.data.keyDown.chr == linefeedChr) { confirmed = true; } // If next-field character toggle between start time in end // time. else if (event.data.keyDown.chr == nextFieldChr) { *timeChars = 0; if (changingTime == changingStartTime) { CtlSetValue (startTimeCtl, false); CtlSetValue (endTimeCtl, true); changingTime = changingEndTime; } else { CtlSetValue (endTimeCtl, false); CtlSetValue (startTimeCtl, true); changingTime = changingStartTime; } } // If a valid time character was written, translate the written // character into a time and update the time picker's UI. else if (TranslateTime (timeFormat, event.data.keyDown.chr, firstHour, timeChars, timeP)) { if (changingTime == changingNoTime) { changingTime = changingStartTime; CtlSetValue (startTimeCtl, true); } AdjustTimes (&startTime, &endTime, &timeDiff, changingTime); SetTimeTriggers (startTime, endTime, startTimeText, endTimeText, timeFormat, false); LstSetSelection (hoursLst, timeP->hours); LstSetSelection (minutesLst, timeP->minutes / 5); } } // Has the dialog been confirmed. if (confirmed) { if (changingTime != changingNoTime) { *startTimeP = startTime; *endTimeP = endTime; } else { TimeToInt(*startTimeP) = noTime; TimeToInt(*endTimeP) = noTime; } break; } } FrmEraseForm (frm); FrmDeleteForm (frm); MemHandleFree (hoursItems); FrmSetActiveForm(originalForm); return (confirmed); }
int SslClient:: RecvCLRF(std::string& str_, long timeout_) { char buf[2]; std::string::size_type pos_clrf; int retval; fd_set read_fds; fd_set write_fds; struct timeval timeout; struct timeval *ptimeout; str_ = ""; buf[1] = '\0'; // 如果将缓冲区设置为一个较大值 // 则有可能导致当前读取的数据越过第一个CLRF符,读取到多余的数据 // 在这种情况下,如果要使程序正常运行,则需要开辟全局的存储空间,存储CLRF后的数据 // 这将导致前后两个RecvCLRF调用失去独立性,增加编程的复杂度 // 权衡效率与复杂度,选择牺牲效率 while(1) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); bool need_io; do { need_io = false; int bytes; bytes = SSL_read(this->ssl_m, buf, 1); switch(SSL_get_error(ssl_m, bytes)) { case SSL_ERROR_NONE: // 没有错误,把这个字节加到目标字符串上 str_ += buf; break; case SSL_ERROR_ZERO_RETURN: Throw("socket closed by client", 0); break; case SSL_ERROR_WANT_READ: #ifdef SslClient_DEBUG printf("SSL_ERROR_WANT_READ\n"); #endif FD_SET(this->sock_fd, &read_fds); need_io = true; break; case SSL_ERROR_WANT_WRITE: #ifdef SslClient_DEBUG printf("SSL_ERROR_WANT_WRITE\n"); #endif FD_SET(this->sock_fd, &write_fds); need_io = true; break; case SSL_ERROR_SYSCALL: Throw("ssl I/O error occurred", MException::ME_RUNTIME); break; default: Throw("SSL_read() failed", MException::ME_RUNTIME); } // 测试是否读取到了CLRF if( (pos_clrf = str_.find("\r\n")) == std::string::npos ) { // 没有,继续 continue; } else { // 有,赋给传入参数 str_.erase(pos_clrf); } } while(need_io == false && pos_clrf == std::string::npos); // 跳出外层循环 if(pos_clrf != std::string::npos) { break; } ptimeout= TranslateTime(timeout_, &timeout); while((retval = select(FD_SETSIZE, &read_fds, &write_fds, NULL, ptimeout)) == -1 && errno == EINTR); if(retval > 0) { continue; } else if(retval == 0) { Throw("Socket timeout",0); } else { Throw("Select on socket failed", errno); } } return 0; }
void SslClient:: CSend(const void *buf_, size_t length_, long timeout_) { int retval; fd_set write_fds; fd_set read_fds; size_t sent_bytes = 0; struct timeval timeout; struct timeval* ptimeout; do { FD_ZERO(&write_fds); FD_ZERO(&read_fds); bool need_io; do { int bytes; need_io = false; bytes = SSL_write(this->ssl_m, (char *)buf_ + sent_bytes, length_ - sent_bytes); if(bytes > 0) { sent_bytes += bytes; continue; } // 测试错误 switch(SSL_get_error(ssl_m, bytes)) { case SSL_ERROR_NONE: break; case SSL_ERROR_ZERO_RETURN: Throw("socket closed by client", 0); break; case SSL_ERROR_WANT_READ: #ifdef SslClient_DEBUG printf("SSL_ERROR_WANT_READ\n"); #endif FD_SET(this->sock_fd, &read_fds); need_io = true; break; case SSL_ERROR_WANT_WRITE: #ifdef SslClient_DEBUG printf("SSL_ERROR_WANT_WRITE\n"); #endif FD_SET(this->sock_fd, &write_fds); need_io = true; break; case SSL_ERROR_SYSCALL: Throw("ssl I/O error occurred", MException::ME_RUNTIME); break; default: Throw("SSL_read() failed", MException::ME_RUNTIME); } } while(need_io == false && sent_bytes != length_); if( sent_bytes == length_ ) { break; } ptimeout= TranslateTime(timeout_, &timeout); // 等待数据到来 while((retval = select(FD_SETSIZE, &read_fds, &write_fds, NULL, ptimeout)) == -1 && errno == EINTR); if( retval > 0 ) { continue; } else if( retval == 0 ) { Throw("Socket time out", 0); } else { Throw("Select failed", errno); } } while(sent_bytes != length_); return; }
int SslClient:: Recv(void *buf_, size_t length_, long timeout_) { int retval; int bytes; fd_set read_fds; fd_set write_fds; struct timeval timeout; struct timeval* ptimeout; // 由于ssl在用户与内核之间保留了一块缓冲区存放数据 // 如果一开始就进行select,有可能遇到这样的情况: // 1、上一次调用后,ssl缓冲区内的数据还没有读完 // 2、对方主机的数据已经发送完毕 // 这时在SSL_read之前使用select,将会导致当前线程始终阻塞 // 导致程序僵死 while(1) { FD_ZERO(&read_fds); FD_ZERO(&write_fds); bool need_io; bool shutdown; do { need_io = false; shutdown = false; // 读取数据 if( ( bytes = SSL_read(this->ssl_m, (char *)buf_, length_) ) > 0) { break; } // 检查错误 switch(SSL_get_error(ssl_m, bytes)) { case SSL_ERROR_NONE: break; case SSL_ERROR_ZERO_RETURN: bytes = 0; shutdown = true; break; // ssl缓冲区已经为空,需要读取数据 case SSL_ERROR_WANT_READ: #ifdef SslClient_DEBUG printf("SSL_ERROR_WANT_READ\n"); #endif FD_SET(this->sock_fd, &read_fds); need_io = true; break; // 需要写数据 // 注意:即使是SSL_read,也可能返回SSL_ERROR_WANT_WRITE // 因为ssl中涉及到一些握手与校验信息,通信始终是双向的 // 所以不光要设置读套接字集(read_fds),还要设置写套接字集(write_fds) case SSL_ERROR_WANT_WRITE: #ifdef SslClient_DEBUG printf("SSL_ERROR_WANT_WRITE\n"); #endif FD_SET(this->sock_fd, &write_fds); need_io = true; break; case SSL_ERROR_SYSCALL: Throw("ssl I/O error occurred", MException::ME_RUNTIME); break; default: Throw("SSL_read() failed", MException::ME_RUNTIME); } } while(need_io == false && shutdown == false); // 跳出最外层的循环 if(bytes >= 0) { break; } ptimeout= TranslateTime(timeout_, &timeout); while((retval = select(FD_SETSIZE, &read_fds, &write_fds, NULL, ptimeout)) == -1 && errno == EINTR); if ( retval > 0 ) { // FIXME // 这里是否要调用FD_ISSET(this->sock_fd, &read_fds) ? continue; } else if( retval == 0 ) { Throw("Socket time out", 0); } else { Throw("Select failed", errno); } } return bytes; }
int TcpClient::Recv(char *buf_, size_t length_, long timeout_) { int retval; int bytes; fd_set read_fds; struct timeval timeout; struct timeval* ptimeout; while(1) { FD_ZERO(&read_fds); FD_SET(this->sock_fd, &read_fds); ptimeout = TranslateTime(timeout_, &timeout); // 等待数据到来 /* while((retval = select(FD_SETSIZE, &read_fds, NULL, NULL, ptimeout)) == -1 && errno == EINTR); // xian add 2011-9-26 15:16:23 由 FD_SETSIZE ==> this->sock_fd + 1 */ while((retval = select(this->sock_fd + 1, &read_fds, NULL, NULL, ptimeout)) == -1 && errno == EINTR); // select 成功返回 if ( retval > 0 ) { if (FD_ISSET(this->sock_fd, &read_fds)) { // 接收数据 while( (bytes = recv(this->sock_fd, buf_, length_, MSG_DONTWAIT)) == -1 && errno == EINTR); // 套接字有可能在select返回到recv读取的这段时间内又不可用 // 重新回去等待 // FIXME 是否会导致忙等? if(bytes == -1 && errno == EAGAIN) { continue; } else if (bytes == 0) // 连接被关闭 { break; } else if (bytes < 0) { Throw("Socket error",errno); } else { break; } } } else if( retval == 0 ) { Throw("Socket time out", 0); } else { Throw("Select failed", errno); } } return bytes; }
int TcpClient::RecvCLRF(std::string& str_, long timeout_) { char buf[BUFSIZE + 1]; std::string::size_type pos_clrf; fd_set read_fds; int retval; struct timeval timeout; struct timeval *ptimeout; str_.clear(); // buf[1] = '\0'; while(1) { FD_ZERO(&read_fds); FD_SET(this->sock_fd, &read_fds); ptimeout= TranslateTime(timeout_, &timeout); // 等待套接字可读 while((retval = select(this->sock_fd + 1, &read_fds, NULL, NULL, ptimeout)) == -1 && errno == EINTR); if(retval > 0) { if (FD_ISSET(this->sock_fd, &read_fds)) { int bytes; while( (bytes = recv(this->sock_fd, buf, BUFSIZE, MSG_DONTWAIT)) == -1 && errno == EINTR); if( bytes == -1 && errno == EAGAIN) { continue; } else if (bytes == 0) { Throw("socket closed by client", 0); } else if(bytes < 0) { Throw("recv data failed", errno); } buf[bytes] = 0; str_ += buf; // 如果没有clrf字符串,继续读取 if( (pos_clrf = str_.find("\r\n")) == std::string::npos ) { continue; } else // 找到clrf字符串,提取并跳出循环 { str_.erase(pos_clrf); break; } } } else if(retval == 0) { Throw("Socket timeout",0); } else { Throw("Select failed", errno); } } return 0; }
void CWorldSocket::OnClose(int nErrorCode) { bool bWasClosed = m_pDoc->m_iConnectPhase == eConnectNotConnected; TRACE1 ("CWorldSocket::OnClose, error code %i\n", nErrorCode); m_pDoc->m_iConnectPhase = eConnectDisconnecting; m_pDoc->UpdateAllViews (NULL); m_pDoc->MXP_Off (true); // turn off MXP now // update button bar - make button red if (m_pDoc->m_view_number >= 1 && m_pDoc->m_view_number <= 10) Frame.OnUpdateBtnWorlds (m_pDoc->m_view_number, NULL); // execute "disconnect" script if (m_pDoc->m_ScriptEngine) { if (m_pDoc->SeeIfHandlerCanExecute (m_pDoc->m_strWorldDisconnect)) { DISPPARAMS params = { NULL, NULL, 0, 0 }; long nInvocationCount = 0; m_pDoc->ExecuteScript (m_pDoc->m_dispidWorldDisconnect, m_pDoc->m_strWorldDisconnect, eWorldAction, "world disconnect", "disconnecting from world", params, nInvocationCount); } } // end of executing disconnect script m_pDoc->SendToAllPluginCallbacks (ON_PLUGIN_DISCONNECT); // close log file if we auto-opened it if (!m_pDoc->m_strAutoLogFileName.IsEmpty ()) m_pDoc->CloseLog (); if (m_pDoc->m_bShowConnectDisconnect && !bWasClosed) { CTime theTime; theTime = CTime::GetCurrentTime(); CString strConnected; strConnected = theTime.Format (TranslateTime ("--- Disconnected on %A, %B %d, %Y, %#I:%M %p ---")); m_pDoc->Note (strConnected); // find time spent connected CTimeSpan ts = CTime::GetCurrentTime() - m_pDoc->m_tConnectTime; CString strDuration = TFormat ("--- Connected for %i day%s, %i hour%s, %i minute%s, %i second%s. ---", PLURAL ((long) ts.GetDays()), PLURAL ((long) ts.GetHours()), PLURAL ((long) ts.GetMinutes()), PLURAL ((long) ts.GetSeconds())); m_pDoc->Note (strDuration); // and a horizontal rule m_pDoc->m_pCurrentLine->flags = HORIZ_RULE; m_pDoc->StartNewLine (true, 0); } // end of message in world window wanted CString strInfo = TFormat ("--- Received %i line%s, sent %i line%s.", PLURAL (m_pDoc->m_nTotalLinesReceived), PLURAL (m_pDoc->m_nTotalLinesSent) ); m_pDoc->Note (strInfo); strInfo = TFormat ("--- Output buffer has %i/%i line%s in it (%.1f%% full).", m_pDoc->m_LineList.GetCount (), m_pDoc->m_maxlines, (m_pDoc->m_LineList.GetCount ()) == 1 ? "" : "s", (double) m_pDoc->m_LineList.GetCount () / (double) m_pDoc->m_maxlines * 100.0 ); m_pDoc->Note (strInfo); strInfo = TFormat ("--- Matched %i trigger%s, %i alias%s, and %i timer%s fired.", PLURAL (m_pDoc->m_iTriggersMatchedThisSessionCount), PLURALES (m_pDoc->m_iAliasesMatchedThisSessionCount), PLURAL (m_pDoc->m_iTimersFiredThisSessionCount) ); m_pDoc->Note (strInfo); CString str; str = TFormat ("The \"%s\" server has closed the connection", (const char *) m_pDoc->m_mush_name); if (App.m_bNotifyOnDisconnect && !m_pDoc->m_bDisconnectOK) { if (App.m_bErrorNotificationToOutputWindow) m_pDoc->Note (str); else ::UMessageBox (str, MB_ICONEXCLAMATION); } else Frame.SetStatusMessage (str); m_pDoc->m_iConnectPhase = eConnectNotConnected; m_pDoc->UpdateAllViews (NULL); // force window title to be redrawn } // end of OnClose