//! //! @brief get module config, by parsing config file. //! //! @param filename Input. file to read into. //! @param pcField Input. field to find in file. //! @param pcValue Output. value read for this field, as string. //! //! @return short 0 if success, -1 otherwise. //! signed short config_file_get_value(char * filename, char * pcField, char *pcValue) { int ErrorConfig = -1; int size; portCHAR * pcDataRead = NULL; portCHAR * current; portCHAR * end; int fd; if ((fd = open(filename, O_RDONLY)) >= 0) { /* get the file size */ size = fsaccess_file_get_size(fd); /* if size is consistent */ if ((size > 0) && (size <= MAX_CONFIG_FILE_SIZE)) { #ifdef FREERTOS_USED if ((pcDataRead = pvPortMalloc(size+1)) != NULL) #else if ((pcDataRead = malloc(size+1)) != NULL) #endif { if (read(fd,pcDataRead,size) == size) { pcDataRead[size] = '\0'; // Look for the requested field. current = strstr(pcDataRead, pcField ); if (current != NULL) { /* goto = */ current = strpbrk(current, "=" ); if( NULL != current ) { // The equal sign was found current++; // Goto just after the = sign. // Look for the end of line // (Well-formed config file rule is : one param=value pair per line) end = strpbrk(current, "\r\n" ); if( NULL != end ) *end = '\0'; // Else the param is the last one in the config file and we'll use // the '\0' of pcDataRead). strcpy(pcValue, current); ErrorConfig = 0; } // else '=' sign not found => the config file is not well-formed. // (Well-formed config file rule is, per line: param=value). } }// read succeeds /* free buffer */ #ifdef FREERTOS_USED vPortFree(pcDataRead); #else free(pcDataRead); #endif }// alloc succeeds }// size is OK close(fd); }// open OK return (ErrorConfig); }
/*! \brief parse the file request and send the requested file to the host * * \param pxNetCon Input. The netconn to use to send and receive data. * \param filename Input. The incoming filename. * */ static void prvweb_SendFile( struct netconn *pxNetCon, char* filename ) { portLONG size, header_size; portLONG fd = -1; portCHAR *resp_data; unsigned portSHORT i; err_t error; pf_read_src pfread = read; // Set the default read to a file read. // NAKED_TRACE_COM2( "SendFile(): %s", filename ); /* allocate response */ resp_data = (portCHAR *)pvPortMalloc(webMAX_DATA_TO_SEND); if (resp_data != NULL) { /* add the header */ header_size = prulweb_BuildHeaders(resp_data, 200, "OK", "", "", "text/html"); if ((fd = open((const char *)filename, O_RDONLY)) < 0) { // Set the read function to read from the pcDefaultPage pfread = prv_read_default_page; size = x_default_page_len; NAKED_TRACE_COM2( "SendFile(): file not found. Default page len:%d", x_default_page_len ); } else /* get the file size */ { size = fsaccess_file_get_size(fd); } /* check if file should be sent in a single frame */ if ( size <= (webMAX_DATA_TO_SEND - header_size)) { /* get the data from filesystem */ if( pfread(fd,&resp_data[header_size],size) != size) { NAKED_TRACE_COM2( "SendFile(): short file read access error" ); prvweb_SendErrorPage( pxNetCon, 404, filename, "Error during read access." ); goto quit_send_page; } /* send the response to network */ error = netconn_write(pxNetCon, resp_data, (u16_t)(header_size + size), NETCONN_COPY ); if (error != 0) { NAKED_TRACE_COM2( "SendFile(): short file nw write error" ); goto quit_send_page; } } else { /* send the header */ error = netconn_write(pxNetCon, resp_data, header_size, NETCONN_COPY ); if (error != 0) { NAKED_TRACE_COM2( "SendFile(): long file hdr nw write error" ); goto quit_send_page; } /* try to send the biggest frame contained in the file */ for (i = webNB_SECTOR_TO_SEND ; i > 0 ; i--) { /* get sectors of maximum size */ while(size > i * FS_SIZE_OF_SECTOR) { /* get the data from filesystem */ if( pfread(fd,resp_data, i * FS_SIZE_OF_SECTOR) != i * FS_SIZE_OF_SECTOR) { NAKED_TRACE_COM2( "SendFile(): long file read access error" ); prvweb_SendErrorPage( pxNetCon, 404, filename, "Error during read access." ); goto quit_send_page; } /* send the response to network */ error = netconn_write(pxNetCon, resp_data, (u16_t)(i * FS_SIZE_OF_SECTOR), NETCONN_COPY ); if (error != 0) { NAKED_TRACE_COM2( "SendFile(): long file nw write error" ); goto quit_send_page; } size -= (i * FS_SIZE_OF_SECTOR); } } /* finish with the few data remaining (less than 1 sector)*/ if ( size > 0 ) { /* get the data from filesystem */ if( pfread(fd,resp_data,size) != size) { NAKED_TRACE_COM2( "SendFile(): long file end read access error" ); prvweb_SendErrorPage( pxNetCon, 404, filename, "Error during read access." ); goto quit_send_page; } /* send the response to network */ error = netconn_write(pxNetCon, resp_data, (u16_t)size, NETCONN_COPY ); if (error != 0) { NAKED_TRACE_COM2( "SendFile(): long file end nw write error" ); goto quit_send_page; } } } }// end if response != NULL else { NAKED_TRACE_COM2( "SendFile(): mem alloc failed" ); __asm__ __volatile__ ("nop"); } quit_send_page: // vPortFree() handles the case where resp_data==NULL vPortFree(resp_data); /* close the file */ // close() handles the case where fd is an invalid file descriptor. close(fd); }
/*! * \brief Open the current log file. * * \return the file descriptor or -1 if open failed. */ static int prv_xopen_current_logfile( void ) { int fd_current_logfile; struct tm *pxDate; // TRACE_COM2( "open logfile begin==%d", xcptime_LocalTime ); while( 1 ) { fd_current_logfile = -1; // Init to default value. /* Open the log file. */ if( '\0' != *acLogFileName ) { // If we have an active current log file, simply open it in append mode. fd_current_logfile = open( acLogFileName, O_APPEND ); // Check if the max file size has been reached. if( -1 != fd_current_logfile ) { if( DATALOG_LOGFILE_MAXSIZE <= fsaccess_file_get_size( fd_current_logfile ) ) { // The current log file has reached the max size. // Get the current time in the "YYYYMMDDHHMMSSMS" string format. v_cptime_GetDateInFatStringFormat( pcTempoDate ); // Set the file date. nav_file_dateset( (FS_STRING)pcTempoDate, FS_DATE_LAST_WRITE ); close( fd_current_logfile ); // Close the file. *acLogFileName = '\0'; // Reset the current log file name. continue; // Do another loop to create/open a new file. } } else { // The file has been removed. *acLogFileName = '\0'; // Reset the current log file name. continue; // Do another loop to create/open a new file. } } else { // Create a new log file. // Get the broken-down representation of the current date. pxDate = gmtime( &xcptime_LocalTime ); // Build the filename: mmddyy_hhmm.log // WARNING: pxDate->tm_year == number of years since 1900. // For years >= 2000, we'll display the last 2 digits only. if( pxDate->tm_year >= 100 ) pxDate->tm_year -= 100; sprintf( acLogFileName, "%s/%.2d%.2d%.2d_%.2d%.2d.log", pcStringCurrentLogDirectoryName, pxDate->tm_mon +1, pxDate->tm_mday, pxDate->tm_year, pxDate->tm_hour, pxDate->tm_min ); NAKED_TRACE_COM2( "Creating log file %s", acLogFileName ); // Create the log file only if the /LOG directory exists. if( true == fsaccess_IsDirPresent( (const char *)pcStringCurrentLogDirectoryName ) ) { // The LOG/ directory exists. // Create and open the file. // if the file already exists, then the file size is reset. fd_current_logfile = open( acLogFileName, (O_CREAT|O_WRONLY) ); // previous file is closed, send a mail if ( *acPreviousLogFileName != '\0' ) { // post alarm to SMTP task v_SMTP_Post(acPreviousLogFileName, acPreviousLogFileName); } strncpy(acPreviousLogFileName, acLogFileName, strlen(acLogFileName)); } } if( -1 == fd_current_logfile ) { // The open failed. We're not in maintenance mode. // Just remove the oldest log file: TODO NAKED_TRACE_COM2( "Failed opening the current log file %s", acLogFileName ); /*########### TEMPORARY #############*/ break; /*###################################*/ } else break; } return( fd_current_logfile ); }
/*! * \brief Task for SMTP management */ portTASK_FUNCTION( vBasicSMTPClient, pvParameters ) { struct sockaddr_in stServeurSockAddr; portLONG lRetval; portLONG lSocket = -1; portLONG ulResponseCode = 0; xMailDef * pxMail; int Size, SizeRead; portCHAR * pcRespData; int fd; portCHAR cToken[6]; // Just to stop compiler warnings. ( void ) pvParameters; // Create the xMailsQueue capable of containing DATALOG_LOGSQUEUE_SIZE ptrs // to xLogDef structures. xMailsQueue = xQueueCreate( SMTP_MAILS_QUEUE_SIZE, sizeof( xMailDef * ) ); // SMTP configuration. // Get the xCFGMutex. if( pdFALSE == x_supervisor_SemaphoreTake( xCFGMutex, 500 ) ) { // Failed to get the CFG mutex, use the default HTTP config. uiSMTPPort = SMTP_PORT; cMailTo[0] = '\0'; cMailFrom[0] = '\0'; cServerName[0] = '\0'; } // Mutex has been taken else { // get the field value for port number if (config_file_get_value(SMTP_CONFIG_FILE, "port" , cToken) >= 0) { sscanf(cToken, "%u", &uiSMTPPort); } // if it does not exist, use the default value else { uiSMTPPort = SMTP_PORT; } // try to get the mailto field if (config_file_get_value(SMTP_CONFIG_FILE, "mailto", cMailTo) < 0) { cMailTo[0] = '\0'; // can't find field in config file, warn user NAKED_TRACE_COM2("Warning : No mailto configured !!Please fill mailto= field in %s\r\n", SMTP_CONFIG_FILE); } // try to get the mailfrom field if (config_file_get_value(SMTP_CONFIG_FILE, "mailfrom", cMailFrom) < 0) { cMailFrom[0] = '\0'; // can't find field in config file, warn user NAKED_TRACE_COM2("Warning : No mailfrom configured !!Please fill mailfrom= field in %s\r\n", SMTP_CONFIG_FILE); } // try to get the server field if (config_file_get_value(SMTP_CONFIG_FILE, "server", cServerName) < 0) { cServerName[0] = '\0'; // can't find field in config file, warn user NAKED_TRACE_COM2("Warning : No server name configured !! Please fill server= field in %s\r\n", SMTP_CONFIG_FILE); } // Release the xCFGMutex. x_supervisor_SemaphoreGive( xCFGMutex ); } for(;;) { // NOTE: the task should be resumed when it is necessary to send a mail // Get the oldest mail from the queue. // NOTE: we are sure there is an item to get => no block time. if( pdTRUE == xQueueReceive( xMailsQueue, &pxMail, ( portTickType )1000 ) ) { if (cServerName[0] == '\0') { // can't find field in config file, warn user NAKED_TRACE_COM2("Warning : No server name configured !! Please fill server= field in %s\r\n", SMTP_CONFIG_FILE); } else if (cMailTo[0] == '\0') { // can't find field in config file, warn user NAKED_TRACE_COM2("Warning : No mailto configured !!Please fill mailto= field in %s\r\n", SMTP_CONFIG_FILE); } else if (cMailFrom[0] == '\0') { // can't find field in config file, warn user NAKED_TRACE_COM2("Warning : No mailfrom configured !!Please fill mailfrom= field in %s\r\n", SMTP_CONFIG_FILE); } else { // Set up port memset(&stServeurSockAddr, 0, sizeof(stServeurSockAddr)); stServeurSockAddr.sin_len = sizeof(stServeurSockAddr); stServeurSockAddr.sin_addr.s_addr = inet_addr(cServerName); stServeurSockAddr.sin_port = htons(uiSMTPPort); stServeurSockAddr.sin_family = AF_INET; // socket as a stream if ( (lSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { // socket failed NAKED_TRACE_COM2("Socket Failed\r\n"); } // connect to the server if(connect(lSocket,(struct sockaddr *)&stServeurSockAddr,sizeof(stServeurSockAddr)) < 0) { // connect failed NAKED_TRACE_COM2("Connect Failed\r\n"); } else { eSMTPCurrentState = eSMTPIdle; while ( eSMTPCurrentState != eSMTPMailSent ) { // wait for SMTP Server answer do { lRetval = recv(lSocket, cTempBuffer, sizeof(cTempBuffer), 0); }while (lRetval <= 0); cTempBuffer[3] = '\0'; // Get the response code from server ulResponseCode = atoi(cTempBuffer); switch (ulResponseCode) { case 220: { // send helo send(lSocket, "HELO ", 5, 0); send(lSocket, cServerName, strlen(cServerName), 0); send(lSocket, "\r\n", 2, 0); eSMTPCurrentState = eSMTPHeloSent; break; } case 221: { // QUIT sequence has been acknowledged by server if (eSMTPCurrentState == eSMTPQuitSent) { eSMTPCurrentState = eSMTPMailSent; } break; } case 250: { if (eSMTPCurrentState == eSMTPHeloSent) { // send MAIL FROM send(lSocket, "MAIL FROM: <", 12, 0); ; send(lSocket, cMailFrom, strlen(cMailFrom), 0); send(lSocket, ">\r\n", 3, 0); eSMTPCurrentState = eSMTPMailFromSent; } else if (eSMTPCurrentState == eSMTPMailFromSent) { // send MAIL TO send(lSocket, "RCPT TO: <", 10, 0); ; send(lSocket, cMailTo, strlen(cMailTo), 0); send(lSocket, ">\r\n", 3, 0); eSMTPCurrentState = eSMTPMailToSent; } else if (eSMTPCurrentState == eSMTPMailToSent) { // send DATA send(lSocket, SMTP_DATA_STRING, 6, 0); eSMTPCurrentState = eSMTPDataSent; } else if (eSMTPCurrentState == eSMTPContentSent) { // send QUIT send(lSocket, SMTP_QUIT_STRING, 6, 0); eSMTPCurrentState = eSMTPQuitSent; } break; } case 354: { if (eSMTPCurrentState == eSMTPDataSent) { // set Subject field send(lSocket, "Subject:", 8, 0); // add subject send(lSocket, pxMail->Subject, strlen(pxMail->Subject), 0); send(lSocket, "\r\nFROM:", 7, 0); send(lSocket, cMailFrom, strlen(cMailFrom), 0); send(lSocket, "\r\nTO:", 5, 0); send(lSocket, cMailTo, strlen(cMailTo), 0); send(lSocket, "\r\n\r\n", 4, 0); // if a file has been specified, copy the content in the mail body if (pxMail->File != NULL) { // allocate response pcRespData = (portCHAR *)pvPortMalloc(SMTP_PACKET_SIZE); if (pcRespData != NULL) { if ((fd = open((const char *)pxMail->File, O_RDONLY)) >= 0) { Size = fsaccess_file_get_size(fd); // get sectors of maximum size while(Size > 0) { // get the data from filesystem SizeRead = read(fd, pcRespData, SMTP_PACKET_SIZE); // if error occurs during the read if (SizeRead <= 0) { // end the loop and send what has already been added break; } // sned data to the socket send(lSocket, pcRespData, SizeRead, 0); // decrease remaing size Size -= SizeRead; } // close the file close(fd); // free the buffer vPortFree(pcRespData); } else { // warn user : can't open the file NAKED_TRACE_COM2("Open file fails\r\n"); } } else { // warn user : can't malloc the file buffer NAKED_TRACE_COM2("SMTP : Malloc fails\r\n"); } } // add "<CRLF>.<CRLF>" send(lSocket, SMTP_MAIL_END_STRING, 5, 0); eSMTPCurrentState = eSMTPContentSent; } break; } default: { // unknown SMTP code NAKED_TRACE_COM2("Unimplented %l SMTP response from server\r\n",ulResponseCode); // break loop and reset state machine eSMTPCurrentState = eSMTPMailSent; break; } } } // close the socket close(lSocket); } // if the item was not posted from ISR if (pxMail->NeedFree == pdTRUE) { // if a file has been specified if ( pxMail->File != NULL ) { // free the item vPortFree(pxMail->File); } // free the items vPortFree(pxMail->Subject); vPortFree(pxMail); } } } } }
//! //! @brief This function replace a (or many) line(s) in a file. //! Syntax of the line should be : \verbatim field=value\r\n \endverbatim //! //! @param filename Input. The filename to write into. //! @param ac Input. The argument counter. For this command, should be 1. //! @param av Input. The argument vector. //! //! @return short : 0 if success or -1 else //! signed short config_file_set_value(char * filename, int ac, signed char *av[]) { int size, i; char * pcDataToWrite = NULL; char * pcDataTemp = NULL; char * pcBegin = NULL; char * pcEnd = NULL; char * pcEq = NULL; signed short xreturn = -1; size_t FileLen; int fd; char pcTempoDate[17]; #ifdef FREERTOS_USED pcDataToWrite = pvPortMalloc(MAX_CONFIG_FILE_SIZE); #else pcDataToWrite = malloc(MAX_CONFIG_FILE_SIZE); #endif if (pcDataToWrite != NULL) { if ((fd = open(filename, (O_RDONLY))) >= 0) { if ((size = fsaccess_file_get_size(fd)) > 0) { /* get data from file */ if (read(fd, pcDataToWrite, size) > 0) { pcDataToWrite[size] = '\0'; for (i = 0 ; i < ac ; i+=2) { /* search the field in the file */ pcBegin = strstr(pcDataToWrite, (char *)av[i]); if( NULL == pcBegin ) { // The field is not yet in the file. strcat( pcDataToWrite, CRLF ); // Add a new line for this field. strcat( pcDataToWrite, (char *)av[i] ); // Add the field. strcat( pcDataToWrite, "=" ); // Add the = strcat( pcDataToWrite, (char *)av[i+1] ); // Add the value. strcat( pcDataToWrite, CRLF ); // Add the CRLF. } else { /* Search for the = sign. */ pcEq = strpbrk(pcBegin, "="); /* search for end of line */ pcEnd = strpbrk(pcBegin, "\n"); if( NULL == pcEnd ) { // no crlf, we're at the end of the file. pcEq++; // WARNING NOTE: we assume the cfg file is well-formed, // i.e. there must be an equal sign after the field name then a value. strcpy( pcEq, (char *)av[i+1] ); // Add the value. } else { pcEnd++; if( ( pcEnd - pcDataToWrite ) < size ) { // There are other fields after this one. #ifdef FREERTOS_USED if ((pcDataTemp = pvPortMalloc(MAX_CONFIG_FILE_SIZE)) != NULL) #else if ((pcDataTemp = malloc(MAX_CONFIG_FILE_SIZE)) != NULL) #endif { strcpy( pcDataTemp, pcEnd ); } } pcEq++; // WARNING NOTE: we assume the cfg file is well-formed, // i.e. there must be an equal sign after the field name then a value. strcpy( pcEq, (char *)av[i+1] ); // Add the value. strcat( pcEq, CRLF ); if (pcDataTemp != NULL) { /* add old data to the buffer */ strcat( pcEq, pcDataTemp ); #ifdef FREERTOS_USED vPortFree(pcDataTemp); #else free(pcDataTemp); #endif } } } }// for number of args }//read succeeds }// size > 0 close(fd); }// open succeeds if ((fd = open(filename, O_WRONLY)) >= 0) { FileLen = strlen( pcDataToWrite ); if( write( fd, pcDataToWrite, FileLen ) == FileLen ) { xreturn = 0; } // Get the current time in the "YYYYMMDDHHMMSSMS" string format. v_cptime_GetDateInFatStringFormat( pcTempoDate ); // Set the file date. nav_file_dateset( (FS_STRING)pcTempoDate, FS_DATE_LAST_WRITE ); close(fd); } #ifdef FREERTOS_USED vPortFree(pcDataToWrite); #else free(pcDataToWrite); #endif }// malloc succeeds return( xreturn ); }