⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 emnntp.c

📁 C语言实现的简易的NNTP Client源代码
💻 C
字号:
/* *  Embedded NNTP Client API * *  ./software/ch11/emnntp/emnntp.c * *  mtj@cogitollc.com * */#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <string.h>#include <stdio.h>#include <time.h>#include <unistd.h>#include "emnntp.h"#include "parsers.h"#define MAX_LINE	512static int sock=-1;char buffer[MAX_LINE+1];char curGroup[MAX_LINE+1];/* curMessage is the index of the next message index that can be retrieved * from the currently defined group. */static int curMessage = -1;/* firstMessage is the first available message index that can be retrieved * from the currently defined group. */static int firstMessage = -1;/* lastMessage is the last available message index that can be retrieved * from the currently defined group.  */static int lastMessage=-1;/* *  dialog() * *  Perform a dialog transaction with the connected NNTP server.  In this *  dialog, a command may be sent and a response may be returned. * *  The user passes in the character buffer containing an optional command *  (null string if no command is to be sent) and then the same string is *  used to collect the response. * *  The function returns 0 on success, -1 on error. * */int dialog( int sd, char *buffer, char *resp ){  int ret, len;  if ((sd == -1) || (!buffer)) return -1;  if (strlen(buffer) > 0) {    len = strlen( buffer );    if ( write( sd, buffer, len ) != len ) return -1;  }  if (resp != NULL) {    ret = read( sd, buffer, MAX_LINE );     if (ret >= 0) {      buffer[ret] = 0;      if (strncmp( buffer, resp, 3 )) return -1;    } else {      return -1;    }  }  return 0;}/* *  nntpConnect() * *  Connect to an NNTP server using the server provided to this function. * *  Returns 0 on success, -1 on error. * */int nntpConnect ( char *nntpServer ){  int result = -1;  struct sockaddr_in servaddr;  if (!nntpServer) return -1;  curGroup[0] = 0;  sock = socket( AF_INET, SOCK_STREAM, 0 );  bzero( &servaddr, sizeof(servaddr) );  servaddr.sin_family = AF_INET;  servaddr.sin_port = htons( 119 );  servaddr.sin_addr.s_addr = inet_addr( nntpServer );  if ( servaddr.sin_addr.s_addr == 0xffffffff ) {    struct hostent *hptr = (struct hostent *)gethostbyname( nntpServer );    if ( hptr == NULL ) {      return -1;    } else {      struct in_addr **addrs;      addrs = (struct in_addr **)hptr->h_addr_list;      memcpy( &servaddr.sin_addr, *addrs, sizeof(struct in_addr) );    }  }  result = connect( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) );  if ( result >= 0 ) {    buffer[0] = 0;    result = dialog( sock, buffer, "200" );    if (result < 0) nntpDisconnect();  }  return ( result );}/* *  nntpSetGroup() * *  Makes the defined group the active group for the NNTP connection.  Also *  defines the last message read (through lastRead) to define which messages *  should be ignored.  If the lastRead argument is -1, then the first *  available message is defined as the next message to read. * *  Returns the number of messages available, or -1 on error. * */int nntpSetGroup( char *group, int lastRead ){  int result = -1;  int numMessages = -1;  if ((!group) || (sock == -1)) return -1;  snprintf( buffer, 80, "group %s\n", group );  result = dialog( sock, buffer, "211" );  if (result == 0) {    sscanf( buffer, "211 %d %d %d ",              &numMessages, &firstMessage, &lastMessage );    if (lastRead == -1) {      curMessage = firstMessage;    } else {      curMessage = lastRead+1;      numMessages = lastMessage - lastRead;    }    if (result == 0) {      strcpy( curGroup, group );    }  }  return( numMessages );}/* *  nntpPeek() * *  This function peeks at the next message to be read, defined by the *  curMessage internal variable (defined by nntpSetGroup, not updated by *  this function). * *  The 'news' argument is filled with the current message headers, where  *  the user passes in the totalLen argument to define the maximum length *  of the message body with the 'news' structure. * *  Returns the size of the message read, or -1 on error. * */int nntpPeek ( news_t *news, int totalLen ){  int result = -1, i, len=0, stop, state, bufIdx=0;  if ((!news) || (sock == -1)) return -1;  if ((curMessage == -1) || (curMessage > lastMessage)) return -1;  /* Save the message id for this particular message */  news->msgId = curMessage;  snprintf( buffer, 80, "head %d\n", curMessage );  result = dialog( sock, buffer, "221" );  if (result < 0) return -1;  state = stop = 0;   while (!stop) {    if (bufIdx+len > totalLen - 80) break;    len = read( sock, &news->msg[bufIdx], (totalLen-bufIdx) );    /* Search for the end-of-mail indicator in the current buffer */    for ( i = bufIdx ; i < bufIdx+len ; i++ ) {      if      ( (state == 0) && (news->msg[i] == 0x0d) ) state = 1;      else if ( (state == 1) && (news->msg[i] == 0x0a) ) state = 2;      else if ( (state == 2) && (news->msg[i] == 0x0d) ) state = 1;      else if ( (state == 2) && (news->msg[i] ==  '.') ) state = 3;      else if ( (state == 3) && (news->msg[i] == 0x0d) ) state = 4;      else if ( (state == 4) && (news->msg[i] == 0x0a) ) { stop = 1; break; }      else state = 0;    }    bufIdx += len;  }  bufIdx -= 3;  news->msg[bufIdx] = 0;  news->msgLen = bufIdx;  return bufIdx;}/* *  nntpSkip() * *  This function skips the current message and sets the message index to *  the next message. * */void nntpSkip( void ){  curMessage++;}/* *  nntpRetrieve() * *  This function retrieves the next message to be read, defined by the *  curMessage internal variable (defined by nntpSetGroup, updated by *  this function). * *  The 'news' argument is filled with the current message, where the *  user passes in the totalLen argument to define the maximum length *  of the message body with the 'news' structure. * *  Returns the size of the message read, or -1 on error. * */int nntpRetrieve ( news_t *news, int totalLen ){  int result = -1, i, len=0, stop, state, bufIdx=0;  if ((!news) || (sock == -1)) return -1;  if ((curMessage == -1) || (curMessage > lastMessage)) return -1;  /* Save the message id for this particular message */  news->msgId = curMessage;  snprintf( buffer, 80, "article %d\n", curMessage++ );  result = dialog( sock, buffer, "220" );  if (result < 0) return -1;  len = strlen(buffer);  for ( i = 0 ; i < len-1 ; i++ ) {    if ( (buffer[i] == 0x0d) && (buffer[i+1] == 0x0a) ) {      len -= i-2;      memmove( news->msg, &buffer[i+2], len );      break;    }  }  state = stop = 0;   while (!stop) {    if (bufIdx+len > totalLen - 80) break;    /* Search for the end-of-mail indicator in the current buffer */    for ( i = bufIdx ; i < bufIdx+len ; i++ ) {      if      ( (state == 0) && (news->msg[i] == 0x0d) ) state = 1;      else if ( (state == 1) && (news->msg[i] == 0x0a) ) state = 2;      else if ( (state == 2) && (news->msg[i] == 0x0d) ) state = 1;      else if ( (state == 2) && (news->msg[i] ==  '.') ) state = 3;      else if ( (state == 3) && (news->msg[i] == 0x0d) ) state = 4;      else if ( (state == 4) && (news->msg[i] == 0x0a) ) { stop = 1; break; }      else state = 0;    }    bufIdx += (i-bufIdx);    if (!stop) {      len = read( sock, &news->msg[bufIdx], (totalLen-bufIdx) );      if ( (len <= 0) || (bufIdx+len > totalLen) ) {        break;      }    }  }  bufIdx -= 3;  news->msg[bufIdx] = 0;  news->msgLen = bufIdx;  return bufIdx;}/* *  nntpParse() * *  This function parses the subject, sender and physical message from the *  news message (stored within the parameters in the 'news' structure). * *  Note that while the msg element of news contains the entire nntp message, *  the parsed message contains not the headers but instead only the  *  physical message.  The findBody routine identifies the physical message *  and initializes the 'bodyStart' element of the 'news' structure. * *  Returns 0 on success, or -1 on error. * */int nntpParse( news_t *news, unsigned int flags ){  int result;  if (!news) return -1;  result = parseEntry( news, "Subject:", news->subject );  if (result < 0) return result;  result = parseEntry( news, "Date:", news->msgDate );  if (result < 0) return result;  result = parseEntry( news, "From:", news->sender );  if (result < 0) return result;  fixAddress( news->sender );  if (flags == FULL_PARSE) {    result = findBody( news );  }  return result;}/* *  nntpPost() * *  The nntpPost function posts a message to the currently defines newsgroup. *  The caller must define the sender, subject and message (as contained in *  news->msg and referenced by news->bodyStart). * *  This function returns 0 on success, -1 on error. * */int nntpPost( news_t *news ){  int result = -1;  if (sock == -1) return -1;  strcpy( buffer, "POST\n" );  result = dialog( sock, buffer, "340" );  if (result == 0) {    /* Emit the header elements */    if (strlen(news->sender) > 0) {      snprintf( buffer, MAX_LINE, "From: %s\n", news->sender );      if (dialog( sock, buffer, NULL )) return -1;    }    snprintf( buffer, MAX_LINE, "Newsgroups: %s\n", curGroup );    if (dialog( sock, buffer, NULL )) return -1;    if (strlen(news->subject) > 0) {      snprintf( buffer, MAX_LINE, "Subject: %s\n", news->subject );      if (dialog( sock, buffer, NULL )) return -1;    }#ifdef ORGANIZATION    if (strlen(ORGANIZATION)) {      snprintf( buffer, MAX_LINE, "Organization: %s\n", ORGANIZATION );      if (dialog( sock, buffer, NULL )) return -1;    }#endif    strcpy(buffer, "Content-Type: text/html\n");    if (dialog( sock, buffer, NULL )) return -1;    /* Emit the blank line separating the header and body */    if (dialog( sock, "\n\r", NULL)) return -1;    /* Emit the body of the message */    if (dialog( sock, news->bodyStart, NULL)) return -1;    /* Emit the final end of message indicator */    strcpy(buffer, "\n\r.\n\r");    if (dialog( sock, buffer, "240")) return -1;  }  return result;}/* *  nntpDisconnect() * *  This function closes an active NNTP connection and initializes the *  internal state variables to  * * */int nntpDisconnect ( void ){  if (sock == -1) return -1;  close(sock);  sock = curMessage = firstMessage = lastMessage = -1;  curGroup[0] = 0;  return 0;}/* *  Copyright (c) 2002 Charles River Media.  All rights reserved. *  *  Redistribution and use in source and binary forms, with or  *  without modification, is hereby granted without fee provided  *  that the following conditions are met: *  *    1.  Redistributions of source code must retain the above  *        copyright notice, this list of conditions and the  *        following disclaimer. *    2.  Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the  *        following disclaimer in the documentation and/or other  *        materials provided with the distribution. *    3.  Neither the name of Charles River Media nor the names of  *        its contributors may be used to endorse or promote products  *        derived from this software without specific prior  *        written permission. *  * THIS SOFTWARE IS PROVIDED BY CHARLES RIVER MEDIA AND CONTRIBUTERS  * 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CHARLES * RIVER MEDIA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,  * INCIDENTAL, SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  * POSSIBILITY OF SUCH DAMAGE. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -