#include <NServer.h>
Inheritance diagram for RServer:

Public Member Functions | |
| RServer (MPList *serverlist) | |
| virtual | ~RServer () |
| void | setserverlist (MPList *serverlist) |
| MPList * | getserverlist (void) |
| virtual ActiveDB * | active () |
| virtual GroupInfo * | groupinfo (const char *name) |
| virtual Newsgroup * | getgroup (const char *name) |
| virtual int | post (Article *article) |
| virtual void | listgroup (const char *gname, char *lstgrp, unsigned int f, unsigned int l) |
| virtual void | overviewdb (Newsgroup *ng, unsigned int fst, unsigned int lst) |
| virtual void | article (const char *gname, unsigned int nb, Article *artr) |
| virtual void | article (const char *id, Article *art) |
Protected Member Functions | |
| RServer () | |
| void | init (MPList *serverlist) |
| void | connect () |
| void | disconnect () |
| Disconnect from the current news server. | |
| std::string | issue (const char *command, const char *expresp=NULL) |
| void | setserver (MPListEntry *server) |
| int | is_connected () |
| void | selectgroup (const char *name, int force=0) |
Protected Attributes | |
| MPList * | _ServerList |
| MPListEntry * | _CurrentServer |
| GroupInfo | _CurrentGroup |
| sstream * | _pServerStream |
Private Member Functions | |
| void | post (MPListEntry *srvr, Article *article) |
Definition at line 205 of file NServer.h.
|
|
Definition at line 243 of file NServer.h. References _CurrentServer, _pServerStream, and _ServerList.
00243 :NServer() { 00244 _ServerList = NULL; 00245 _CurrentServer = NULL; 00246 _pServerStream = NULL; 00247 } void init(MPList * serverlist); |
|
|
Initialize the new RServer class. Sets up the server list and the default number of retries.
Definition at line 197 of file NServer.cc. References init(), Logger::p(), slog, and VERB.
|
|
|
Definition at line 203 of file NServer.cc. References Logger::p(), setserverlist(), slog, and VERB.
00204 {
00205 VERB(slog.p(Logger::Debug) << "RServer::~RServer()\n");
00206 setserverlist(NULL);
00207 }
|
|
|
Retrieves the active database from the news servers and returns a pointer to it. If an error occurs while retrieving the database from a server, the active database will not be retrieved from this server.
Implements NServer. Reimplemented in CServer. Definition at line 575 of file NServer.cc. References _CurrentServer, _pServerStream, _ServerList, ASSERT, connect(), Logger::Error, ERROR_LOCATION, issue(), MAXGROUPNAMELEN, MPListEntry::nntpflags, Logger::p(), Logger::print(), ActiveDB::read(), MPListEntry::read, setserver(), slog, and VERB. Referenced by CServer::active().
00576 {
00577 VERB(slog.p(Logger::Debug) << "RServer::active()\n");
00578 unsigned int i, flags;
00579 char cgroup[MAXGROUPNAMELEN + 1], *cgp, buf[1024];
00580 const char *sp;
00581 char c;
00582
00583 ASSERT(if (!_ServerList) {
00584 throw
00585 AssertionError
00586 ("RServer::active: _ServerList is a null-pointer",
00587 ERROR_LOCATION);}
00588 );
00589
00590 for (i = 0; i < _ServerList->entries.size(); i++) {
00591 if (!_ServerList->entries[i].hostname[0])
00592 continue;
00593 // Connect to ith news server
00594 try {
00595 setserver(&(_ServerList->entries[i]));
00596 if (_CurrentServer->
00597 flags & (MPListEntry::F_OFFLINE | MPListEntry::
00598 F_SEMIOFFLINE))
00599 continue;
00600 flags =
00601 ((_CurrentServer->
00602 nntpflags & MPListEntry::F_POST)
00603 || !(_CurrentServer->
00604 flags & MPListEntry::
00605 F_SETPOSTFLAG)) ? 0 : ActiveDB::
00606 F_STORE_READONLY;
00607
00608 connect();
00609 if (_CurrentServer->
00610 nntpflags & MPListEntry::
00611 F_LIST_ACTIVE_WILDMAT) {
00612 try {
00613 sp = _CurrentServer->read;
00614 do {
00615 // Extract a newsgroup-expression
00616 cgp = cgroup;
00617 while ((c = *sp++) != ','
00618 && c)
00619 *cgp++ = c;
00620 *cgp = '\0';
00621 sprintf(buf,
00622 "list active %s\r\n",
00623 cgroup);
00624 issue(buf, "215");
00625 // read active database and filter unwanted groups
00626 _ActiveDB->
00627 read(*_pServerStream,
00628 _ServerList->
00629 makeFilter(i,
00630 cgroup),
00631 flags);
00632 } while (c);
00633 }
00634 catch(ResponseError & re) {
00635 slog.p(Logger::Notice)
00636 <<
00637 "list active [wildmat] failed for "
00638 << _ServerList->entries[i].
00639 hostname << ":" <<
00640 _ServerList->entries[i].
00641 servicename << "\n";
00642 _CurrentServer->nntpflags &=
00643 ~MPListEntry::
00644 F_LIST_ACTIVE_WILDMAT;
00645 }
00646 }
00647 if (!
00648 (_CurrentServer->
00649 nntpflags & MPListEntry::
00650 F_LIST_ACTIVE_WILDMAT)) {
00651 issue("list active\r\n", "215");
00652 _ActiveDB->read(*_pServerStream,
00653 _ServerList->makeFilter(i,
00654 "*"),
00655 flags);
00656 }
00657 }
00658 catch(ResponseError & re) {
00659 slog.p(Logger::Error)
00660 << "retrieval of activedb failed for "
00661 << _ServerList->entries[i].hostname << ":"
00662 << _ServerList->entries[i].servicename << "\n";
00663 }
00664 catch(SystemError & se) {
00665 slog.p(Logger::Warning)
00666 << "connection to "
00667 << _ServerList->entries[i].hostname << ":"
00668 << _ServerList->entries[i].
00669 servicename << " failed\n";
00670 }
00671 catch(Error & e) {
00672 slog.p(Logger::Alert)
00673 <<
00674 "UNEXPECTED EXCEPTION WHILE RETRIEVING ACTIVEDB FROM "
00675 << _ServerList->entries[i].
00676 hostname << ":" << _ServerList->entries[i].
00677 servicename <<
00678 "\nPLEASE REPORT TO h.straub@aon.at\n";
00679 e.print();
00680 }
00681 }
00682 return _ActiveDB;
00683 }
|
|
||||||||||||
|
Return a given article of a given newsgroup
Reimplemented in CServer. Definition at line 834 of file NServer.cc. References _CurrentServer, _pServerStream, _ServerList, connect(), MPList::entries, ERROR_LOCATION, issue(), Logger::p(), Article::read(), Article::setnbr(), setserver(), slog, and VERB.
00835 {
00836 VERB(slog.p(Logger::Debug) << "RServer::article(" << id << ")\n");
00837 char buf[1024];
00838 const char *p;
00839 string resp;
00840
00841 sprintf(buf, "article %s\r\n", id);
00842 if (_CurrentServer) {
00843 resp = issue(buf, NULL);
00844 p = resp.c_str();
00845 if (strncmp(p, "220", 3) == 0) {
00846 art->read(*_pServerStream);
00847 art->setnbr(-1);
00848 return;
00849 }
00850 // 412 cannot happen since we specified the article id
00851 // 420 -"- since we specified the article id
00852 // 423 -"- since we specified the article id, not the art nbr
00853 if (strncmp(p, "430", 3) != 0) {
00854 slog.p(Logger::Notice)
00855 <<
00856 "illegal response code to <artcile <id>> request\n"
00857 << p;
00858 }
00859 }
00860 // check whether the article can be found at one of the other
00861 // news servers
00862 MPListEntry *cs = _CurrentServer;
00863
00864 for (unsigned int i = 0; i < _ServerList->entries.size(); i++) {
00865 if (cs == &(_ServerList->entries[i]) ||
00866 !_ServerList->entries[i].hostname[0])
00867 continue;
00868 setserver(&(_ServerList->entries[i]));
00869 connect();
00870 resp = issue(buf, NULL);
00871 p = resp.c_str();
00872 if (strncmp(p, "220", 3) == 0) {
00873 art->read(*_pServerStream);
00874 art->setnbr(-1);
00875 return;
00876 }
00877 if (strncmp(p, "430", 3) != 0) {
00878 slog.p(Logger::Notice)
00879 <<
00880 "illegal response code to <artcile <id>> request\n"
00881 << p;
00882 }
00883 }
00884 throw NoSuchArticleError(resp, ERROR_LOCATION);
00885 }
|
|
||||||||||||||||
|
Return a given article of a given newsgroup
Reimplemented in CServer. Definition at line 809 of file NServer.cc. References _pServerStream, ERROR_LOCATION, issue(), Logger::p(), Article::read(), selectgroup(), Article::setnbr(), slog, and VERB. Referenced by CServer::article(), RNewsgroup::getarticle(), RNewsgroup::printarticle(), and CNewsgroup::retrievearticle().
00810 {
00811 VERB(slog.p(Logger::Debug) << "RServer::article(" << nbr << ")\n");
00812 char buf[513];
00813 const char *p;
00814 string resp;
00815
00816 selectgroup(gname);
00817
00818 sprintf(buf, "article %u\r\n", nbr);
00819 resp = issue(buf, NULL);
00820 p = resp.c_str();
00821 if (strncmp(p, "220", 3) != 0) {
00822 // 412 cannot happen since we have already selected the newsgroup
00823 // 420 -"- since we specified the article nbr
00824 // 430 -"- since we specified the article nbr, not the art-id
00825 if (strncmp(p, "423", 3) == 0)
00826 throw NoSuchArticleError(resp, ERROR_LOCATION);
00827 string c(buf), e("220");
00828 throw ResponseError(c, e, resp);
00829 }
00830 art->read(*_pServerStream);
00831 art->setnbr(nbr);
00832 }
|
|
|
Connect to the news server. Stores whether posting is allowed in _CurrentServer->flags.
Definition at line 233 of file NServer.cc. References _CurrentGroup, _CurrentServer, _pServerStream, MPListEntry::bindFrom, sstream::connectTo(), ERROR_LOCATION, MPListEntry::hostname, is_connected(), issue(), GroupInfo::name(), nlreadline(), MPListEntry::nntpflags, Logger::p(), MPListEntry::passwd, OverviewFmt::readxoin(), MPListEntry::retries, RSERVER_CONNECT_CHECK_CONNECTION, selectgroup(), MPListEntry::servicename, slog, MPListEntry::user, and VERB. Referenced by active(), CServer::article(), article(), issue(), and post().
00234 {
00235 VERB(slog.p(Logger::Debug) << "RServer::connect()\n");
00236 if (is_connected())
00237 return;
00238
00239 string grt, resp;
00240 char buf[1024];
00241 int i = _CurrentServer->retries;
00242 _pServerStream = new sstream;
00243
00244 for (;;) {
00245 // Open connection
00246 if (strcmp(_CurrentServer->bindFrom, "") == 0) {
00247 slog.
00248 p(Logger::
00249 Debug) << "RServer::connect: Connecting to "
00250 << _CurrentServer->
00251 hostname <<
00252 " from DEFAULT interface to servicename " <<
00253 _CurrentServer->servicename << "\n";
00254 _pServerStream->connectTo(_CurrentServer->hostname,
00255 _CurrentServer->
00256 servicename);
00257 } else {
00258 slog.
00259 p(Logger::
00260 Debug) << "RServer::connect: Connecting to "
00261 << _CurrentServer->
00262 hostname << " from interface " <<
00263 _CurrentServer->
00264 bindFrom << " to servicename " <<
00265 _CurrentServer->servicename << "\n";
00266 _pServerStream->connectTo(_CurrentServer->hostname,
00267 _CurrentServer->
00268 servicename,
00269 _CurrentServer->
00270 bindFrom);
00271 }
00272 if (!_pServerStream->good()) {
00273 delete _pServerStream;
00274 _pServerStream = NULL;
00275 throw
00276 SystemError
00277 ("RServer::connect: cannot connect to news server",
00278 errno, ERROR_LOCATION);
00279 }
00280 _pServerStream->unsetf(ios::skipws);
00281
00282 //FIXME! repl nlreadline by nntpreadline that transparently
00283 //FIXME! provides auth? use a authenticator callback class, that
00284 //FIXME! supplies all the negotiation between client/server. Will
00285 //FIXME! get a server and a client handle as well as server and
00286 //FIXME! groupname to send correct passwd to correct server/group
00287 //FIXME! RECONNECT/RETRY? HOW IMPLEMENT? What happens if module
00288 //FIXME! cannot handle this?!?
00289 nlreadline(*_pServerStream, grt, 0);
00290 slog.p(Logger::Info) << grt << "\n";
00291
00292 RSERVER_CONNECT_CHECK_CONNECTION
00293 ("Connection to %s:%s failed");
00294 if (grt[0] != '2' || grt[1] != '0'
00295 || (grt[2] != '0' && grt[2] != '1')) {
00296 string c("_connect_"), e("20[01]");
00297 delete _pServerStream;
00298 _pServerStream = NULL;
00299 throw ResponseError(c, e, grt);
00300 }
00301
00302 if (_CurrentServer->user[0]) {
00303 sprintf(buf, "authinfo user %s\r\n",
00304 _CurrentServer->user);
00305 resp = issue(buf, NULL);
00306 if (resp[0] == '3') {
00307 sprintf(buf, "authinfo pass %s\r\n",
00308 _CurrentServer->passwd);
00309 resp = issue(buf, NULL);
00310 }
00311 if (resp[0] != '2') {
00312 string c("_authenticate_"), e("[23]..");
00313 delete _pServerStream;
00314 _pServerStream = NULL;
00315 throw ResponseError(c, e, resp);
00316 }
00317 }
00318
00319 if (_CurrentServer->nntpflags & MPListEntry::F_MODE_READER) {
00320 // mode reader
00321 resp = issue("mode reader\r\n", NULL);
00322 RSERVER_CONNECT_CHECK_CONNECTION
00323 ("Cannot read data from %s:%s");
00324 if (resp[0] != '2' || resp[1] != '0'
00325 || (resp[2] != '0' && resp[2] != '1')) {
00326 slog.
00327 p(Logger::
00328 Warning) <<
00329 "mode reader failed, ignored\n";
00330 _CurrentServer->nntpflags &=
00331 ~MPListEntry::F_MODE_READER;
00332 }
00333 grt = resp;
00334 }
00335 if (grt[2] == '1') {
00336 _CurrentServer->nntpflags &= ~MPListEntry::F_POST;
00337 }
00338
00339 if (_CurrentServer->
00340 nntpflags & MPListEntry::F_LIST_OVERVIEW_FMT) {
00341 resp = issue("list overview.fmt\r\n", "215");
00342 _OverviewFormat->readxoin(*_pServerStream);
00343 if (resp[0] != '2' || resp[1] != '1'
00344 || resp[2] != '5') {
00345 slog.
00346 p(Logger::
00347 Warning) <<
00348 "list overview.fmt failed, ignored\n";
00349 _CurrentServer->nntpflags &=
00350 ~MPListEntry::F_LIST_OVERVIEW_FMT;
00351 goto rserver__connect_no_list_overview_fmt;
00352 }
00353 } else {
00354 rserver__connect_no_list_overview_fmt:
00355 #ifdef HAVE_SSTREAM
00356 istringstream standardOverviewFmt
00357 #else
00358 istrstream standardOverviewFmt
00359 #endif
00360 ("Subject:\nFrom:\nDate:\nMessage-ID:\nReferences:\nBytes:\nLines:\n");
00361 _OverviewFormat->readxoin(standardOverviewFmt);
00362 }
00363
00364 if (_CurrentGroup.name()[0] != '\0') {
00365 selectgroup(_CurrentGroup.name(), 1);
00366 }
00367 return;
00368 }
00369 }
|
|
|
Disconnect from the current news server.
Definition at line 373 of file NServer.cc. References _pServerStream, Logger::p(), slog, and VERB. Referenced by issue(), post(), setserver(), and setserverlist().
00374 {
00375 VERB(slog.p(Logger::Debug) << "RServer::disconnect()\n");
00376 if (_pServerStream != NULL) {
00377 *_pServerStream << "quit\r\n";
00378 // Who is interested in this return code?
00379 delete _pServerStream;
00380 _pServerStream = NULL;
00381 }
00382 }
|
|
|
Return the newsgroup with name >name<. If the newsgroup does not exist, NULL will be returned.
Implements NServer. Reimplemented in CServer. Definition at line 707 of file NServer.cc. References _CurrentGroup, GroupInfo::first(), GroupInfo::last(), selectgroup(), RNewsgroup::setsize(), slog, and VERB.
00708 {
00709 VERB(slog.
00710 p(Logger::Debug) << "RServer::getgroup(" << name << ")\n");
00711
00712 selectgroup(name);
00713 RNewsgroup *grp = new RNewsgroup(this, _OverviewFormat, name);
00714 grp->setsize(_CurrentGroup.first(), _CurrentGroup.last());
00715 return grp;
00716 }
|
|
|
Return the currently installed list of news servers.
Definition at line 336 of file NServer.h. References _ServerList.
00336 {
00337 return _ServerList;
00338 }
|
|
|
Returns the GroupInfo object of a given newsgroup.
Implements NServer. Reimplemented in CServer. Definition at line 685 of file NServer.cc. References _CurrentGroup, ASSERT, ERROR_LOCATION, ActiveDB::get(), selectgroup(), slog, and VERB. Referenced by CNewsgroup::sUpdateGroupInfo().
00686 {
00687 VERB(slog.
00688 p(Logger::Debug) << "RServer::groupinfo(" << name << ")\n");
00689 static GroupInfo agroup;
00690
00691 ASSERT(if (strlen(name) > 510) {
00692 throw
00693 AssertionError
00694 ("RServer::groupinfo: name of newsgroup too long\n",
00695 ERROR_LOCATION);}
00696 );
00697
00698 // If the newsgroup cannot be found within the active database
00699 // reload the database from the news server and try again.
00700 if (_ActiveDB->get(name, &agroup) < 0) {
00701 selectgroup(name, 1);
00702 agroup = _CurrentGroup;
00703 }
00704 return &agroup;
00705 }
|
|
|
Definition at line 209 of file NServer.cc. References _CurrentServer, _ServerList, Logger::p(), slog, and VERB. Referenced by CServer::CServer(), and RServer().
00210 {
00211 VERB(slog.p(Logger::Debug) << "RServer::init/1\n");
00212
00213 _ServerList = serverlist;
00214 _CurrentServer = NULL;
00215
00216 if (!_OverviewFormat)
00217 _OverviewFormat = new OverviewFmt();
00218 if (!_ActiveDB)
00219 _ActiveDB = NULL;
00220 }
|
|
|
Definition at line 296 of file NServer.h. References _pServerStream. Referenced by connect(), and issue().
00296 {
00297 return (_pServerStream != NULL) ? 1 : 0;
00298 }
|
|
||||||||||||
|
Send a command to the remote news server and return its response.
Definition at line 384 of file NServer.cc. References _CurrentServer, _pServerStream, connect(), disconnect(), ERROR_LOCATION, is_connected(), nlreadline(), Logger::p(), MPListEntry::retries, and slog. Referenced by active(), CServer::article(), article(), connect(), listgroup(), overviewdb(), post(), and selectgroup().
00385 {
00386 string req, resp;
00387 int rs;
00388 int i = _CurrentServer->retries + 1;
00389
00390 req = "issue ";
00391 req.append(command, strlen(command) - 2);
00392 req.append("\n");
00393 slog.p(Logger::Info) << "RServer::issue: " << req.c_str();
00394 if (!is_connected())
00395 connect();
00396 // Send command
00397 for (;;) {
00398 try {
00399 *_pServerStream << command << flush;
00400 }
00401 catch(...) {
00402 slog.
00403 p(Logger::
00404 Error) <<
00405 "RServer::issue: error in command sending, good: "
00406 << _pServerStream->good() << "\n";
00407 }
00408 try {
00409 rs = nlreadline(*_pServerStream, resp, 0);
00410 }
00411 catch(...) {
00412 slog.
00413 p(Logger::
00414 Error) <<
00415 "RServer::issue: error in command readline\n";
00416 }
00417 // If the remote server closed the connection (400), reconnect
00418 if (!_pServerStream->good()) {
00419 slog.
00420 p(Logger::
00421 Warning) <<
00422 "RServer::issue: no connection to news server\n";
00423 } else if (strncmp(resp.c_str(), "400", 3) == 0
00424 || strncmp(resp.c_str(), "503", 3) == 0) {
00425 slog.
00426 p(Logger::
00427 Warning) <<
00428 "RServer::issue: server closed connection---reconnecting\n";
00429 }
00430 /*
00431 else if(strncmp(resp.c_str(),"480",3)==0) {
00432 slog.p(Logger::Warning) << "server requests authentication\n";
00433 req="authinfo user ";
00434 req.append(_CurrentServer->Username);
00435 slog.p(Logger::Debug) << req.c_str();
00436 req.append("\r\n");
00437 _ServerStream << req;
00438 rs=nlreadline(_ServerStream,resp,0);
00439 } */
00440 else {
00441 break;
00442 }
00443
00444 // If we have lost the connection to the news server, we try
00445 // to reconnect to the server and reissue the command.
00446 for (;;) {
00447 i--;
00448 if (i == 0)
00449 throw
00450 SystemError
00451 ("maximum number of retries reached",
00452 -1, ERROR_LOCATION);
00453 disconnect();
00454 try {
00455 connect();
00456 break;
00457 }
00458 catch(SystemError & se) {
00459 }
00460 }
00461 }
00462
00463 // Check the response code
00464 if ((rs < 3)
00465 || (expresp
00466 && strncmp(expresp, resp.data(), strlen(expresp)))) {
00467 string c(command), e(expresp);
00468 throw ResponseError(c, e, resp);
00469 }
00470
00471 return resp;
00472 }
|
|
||||||||||||||||||||
|
Return a list of article available in a newsgroup.
Reimplemented in CServer. Definition at line 718 of file NServer.cc. References _pServerStream, ERROR_LOCATION, issue(), nlreadline(), NNTP_ISCODE, selectgroup(), slog, and VERB. Referenced by CServer::listgroup(), and CNewsgroup::listgroup().
00720 {
00721 VERB(slog.
00722 p(Logger::
00723 Debug) << "RServer::listgroup(" << gname << ",...)\n");
00724 const char *p;
00725 unsigned int i;
00726 string resp, line;
00727
00728 selectgroup(gname);
00729 resp = issue("listgroup\r\n", NULL);
00730 p = resp.c_str();
00731 if (!NNTP_ISCODE(p, "211")) {
00732 string c("listgroup\r\n"), e("211");
00733 throw ResponseError(c, e, resp);
00734 }
00735
00736 for (;;) {
00737 nlreadline(*_pServerStream, line);
00738 if (line == ".\r\n")
00739 break;
00740 if (!_pServerStream->good())
00741 throw
00742 SystemError("error while reading from server",
00743 errno, ERROR_LOCATION);
00744 i = atoi(line.data());
00745 if (f <= i && i <= l)
00746 lstgrp[i - f] = 1;
00747 }
00748 }
|
|
||||||||||||||||
|
Return the overviewdatabase of the newsgroup >ng<. This function should not be called by the user. Instead it should be called via a Newsgroup object.
Reimplemented in CServer. Definition at line 750 of file NServer.cc. References _CurrentServer, _pServerStream, ASSERT, ERROR_LOCATION, issue(), NNTP_ISCODE, MPListEntry::nntpflags, Logger::p(), selectgroup(), slog, and VERB. Referenced by CServer::overviewdb(), RNewsgroup::setsize(), and CNewsgroup::sUpdateOverview().
00752 {
00753 VERB(slog.p(Logger::Debug) << "RServer::overviewdb(*ng,"
00754 << fst << "-" << lst << ")\n");
00755 ASSERT(if (!ng) {
00756 throw
00757 AssertionError
00758 ("RServer::overviewdb: ng parameter is a null-pointer",
00759 ERROR_LOCATION);}
00760 );
00761
00762 char buf[513];
00763 string resp;
00764 const char *p;
00765 const char *fmt = "over %d-%d\r\n";
00766
00767 selectgroup(ng->name());
00768 for (;;) {
00769 if (!(_CurrentServer->nntpflags & MPListEntry::F_OVER))
00770 fmt = "xover %d-%d\r\n";
00771 if (!(_CurrentServer->nntpflags & MPListEntry::F_XOVER)) {
00772 slog.
00773 p(Logger::
00774 Critical) <<
00775 "remote news server neither implements OVER nor XOVER\n";
00776 throw
00777 NSError
00778 ("news server neither implements OVER nor XOVER",
00779 ERROR_LOCATION);
00780 }
00781
00782 sprintf(buf, fmt, fst, lst);
00783 resp = issue(buf, NULL);
00784 p = resp.c_str();
00785 if (NNTP_ISCODE(p, "224")) {
00786 ng->readoverdb(*_pServerStream);
00787 return;
00788 }
00789 if (NNTP_ISCODE(p, "502")) {
00790 throw NotAllowedError(resp, ERROR_LOCATION);
00791 }
00792 if (NNTP_ISCODE(p, "412")) {
00793 slog.
00794 p(Logger::
00795 Warning) <<
00796 "newsgroup disappeared while working on it\n";
00797 throw NoSuchGroupError("no such group",
00798 ERROR_LOCATION);
00799 }
00800 if (NNTP_ISCODE(p, "420"))
00801 throw ResponseError(buf, "224", resp);
00802 if (fmt[0] == 'o')
00803 _CurrentServer->nntpflags &= ~MPListEntry::F_OVER;
00804 else
00805 _CurrentServer->nntpflags &= ~MPListEntry::F_XOVER;
00806 }
00807 }
|
|
|
Post an article.
Implements NServer. Reimplemented in CServer. Definition at line 976 of file NServer.cc. References _ServerList, MPList::entries, ERROR_LOCATION, MPListEntry::flags, Article::getfield(), Article::has_field(), newsgroups, nntp_hostname, nntp_posting_host, Logger::p(), post(), MPList::postserver(), Article::setfield(), slog, TOBASE36, and VERB.
00977 {
00978 VERB(slog.p(Logger::Debug) << "RServer::post(Article)\n");
00979
00980 // do some sanity checks
00981 string newsgroups;
00982 try {
00983 if (!article->has_field("from:"))
00984 throw InvalidArticleError("no from field",
00985 ERROR_LOCATION);
00986 if (!article->has_field("subject:"))
00987 throw InvalidArticleError("no subject field",
00988 ERROR_LOCATION);
00989 newsgroups = article->getfield("newsgroups:");
00990 }
00991 catch(NoSuchFieldError & n) {
00992 throw InvalidArticleError("no newsgroups field",
00993 ERROR_LOCATION);
00994 }
00995
00996 static int pc = 1;
00997 const char *p, *q;
00998 string cgroup;
00999 char buf[MAXHOSTNAMELEN + 256];
01000 char msgid[MAXHOSTNAMELEN + 256];
01001 MPListEntry **mpe;
01002 MPListEntry *c;
01003 int sc = 0, i;
01004
01005 //FIXME! We should use the path field here, or introduce a
01006 //FIXME! new field that shows the cache-posting-chain
01007 if (nntp_posting_host[0]) {
01008 sprintf(buf, "X-NNTP-Posting-Host: %s\r\n",
01009 nntp_posting_host);
01010 article->setfield("X-NNTP-Posting-Host:", buf);
01011 }
01012
01013 if (!article->has_field("message-id:")) {
01014 struct timeval tv;
01015 int j;
01016 char mid[768];
01017 char *p;
01018 p = mid;
01019 gettimeofday(&tv, NULL);
01020 TOBASE36(i, tv.tv_sec, p);
01021 *p++ = '$';
01022
01023 j = getpid();
01024 TOBASE36(i, j, p);
01025 *p++ = '$';
01026
01027 TOBASE36(i, pc, p);
01028 *p++ = '@';
01029 strcpy(p, nntp_hostname);
01030 pc++;
01031
01032 sprintf(msgid, "Message-ID: <newscache$%s>\r\n", mid);
01033 article->setfield("Message-ID:", msgid);
01034 }
01035
01036 if ((mpe =
01037 (MPListEntry **) malloc(_ServerList->entries.size() *
01038 sizeof(MPListEntry *))) == NULL) {
01039 throw
01040 SystemError("cannot allocate buffer for post servers",
01041 errno, ERROR_LOCATION);
01042 }
01043
01044 q = newsgroups.c_str();
01045 while (isspace(*q) || *q == ',')
01046 q++;
01047 do {
01048 p = q;
01049 while (*q && *q != ',' && !isspace(*q))
01050 q++;
01051 cgroup.assign(p, q - p);
01052 c = _ServerList->postserver(cgroup.c_str());
01053 if (c) {
01054 i = 0;
01055 while (i < sc && c != mpe[i])
01056 i++;
01057 if (i == sc) {
01058 mpe[sc] = c;
01059 sc++;
01060 }
01061 } else {
01062 slog.p(Logger::Info)
01063 << "posting to unknown newsgroup: " << cgroup
01064 << "\n";
01065 }
01066 while (isspace(*q) || *q == ',')
01067 q++;
01068 } while (*q);
01069
01070 if (!sc) {
01071 slog.p(Logger::Info) << "no news server configured for "
01072 << msgid << "\n";
01073 free(mpe);
01074 throw InvalidArticleError("no valid newsgroup",
01075 ERROR_LOCATION);
01076 }
01077
01078 int posts = 0, spool = 0, err = 0;
01079 i = 0;
01080 // Error classification:
01081 // * Duplicate Articles ... Since we use our hostname and people should
01082 // be forbidden to use wrong hostnames, we assume that a duplicate
01083 // article means that the article arrived already somehow on that
01084 // server.
01085 // * NotAllowed ... user wants to post to a private newsgroup
01086 // * PostingFailed ... user submitted badly formatted article
01087 // * Response, System ... problem on remote site occurred
01088 //
01089 //FIX! If this library should be used for other purposes than just
01090 //FIX! for NewsCache, errors should be resolved using a callback
01091 //FIX! class!
01092 do {
01093 try {
01094 if (mpe[i]->flags & MPListEntry::F_OFFLINE) {
01095 ++spool;
01096 } else {
01097 post(mpe[i], article);
01098 ++posts;
01099 }
01100 }
01101 catch(DuplicateArticleError & dae) {
01102 ++posts;
01103 }
01104 catch(NotAllowedError & nae) {
01105 err |= 1;
01106 }
01107 catch(PostingFailedError & pfe) {
01108 err |= 2;
01109 }
01110 catch(ResponseError & re) {
01111 ++spool;
01112 }
01113 catch(SystemError & se) {
01114 ++spool;
01115 }
01116 catch(Error & e) {
01117 err |= 4;
01118 }
01119 ++i;
01120 } while (i < sc);
01121
01122 free(mpe);
01123 if (!err)
01124 return spool ? -1 : 0;
01125 if (err && !posts) {
01126 throw
01127 InvalidArticleError
01128 ("illegaly formatted article or no post permission",
01129 ERROR_LOCATION);
01130 }
01131 // Hm, on some news servers posting succeeded on others not.
01132 // What should we do now? Spool it to the error-log?
01133 //FIXME! Report posting as OK and send mail to posting indicating the
01134 //FIXME! failure.
01135 return -2;
01136 }
|
|
||||||||||||
|
Definition at line 887 of file NServer.cc. References _CurrentServer, _pServerStream, connect(), disconnect(), ERROR_LOCATION, Article::getfield(), MPListEntry::hostname, issue(), nlreadline(), Logger::p(), MPListEntry::retries, MPListEntry::servicename, setserver(), slog, and VERB. Referenced by CServer::post(), post(), and CServer::postspooled().
00888 {
00889 string resp;
00890 const char *p;
00891 char buf[513];
00892
00893 VERB(slog.p(Logger::Debug) << "RServer::post({"
00894 << srvr->hostname << "," << srvr->servicename << "}\n");
00895
00896 setserver(srvr); // clears current group selection
00897 connect();
00898
00899 // Before posting an article, we should check whether the article
00900 // exists already on the upstream news server. (Since the post
00901 // command does not indicate duplicates, we have to check this
00902 // manually beforehand.
00903
00904 try {
00905 resp = article->getfield("message-id:");
00906 sprintf(buf, "stat %s\r\n", resp.c_str());
00907 resp = issue(buf, NULL);
00908 p = resp.c_str();
00909 if (strncmp(p, "223", 3) == 0)
00910 throw DuplicateArticleError("Response 223",
00911 ERROR_LOCATION);
00912 else
00913 if (strncmp(p, "430", 3) != 0) {
00914 string c(buf), e("223|430");
00915 throw ResponseError(c, e, resp);
00916 }
00917 }
00918 catch(NoSuchFieldError e) {
00919 VERB(slog.
00920 p(Logger::
00921 Debug) << "RServer::post message-id not found\n");
00922 }
00923
00924 for (int i = _CurrentServer->retries + 1;;) {
00925 resp = issue("post\r\n", NULL);
00926 p = resp.c_str();
00927 if (strncmp(p, "340", 3) != 0) {
00928 if (strncmp(p, "440", 3) == 0)
00929 throw NotAllowedError(resp,
00930 ERROR_LOCATION);
00931 throw ResponseError("post\r\n", "[34]40", resp);
00932 }
00933 *_pServerStream << *article << ".\r\n" << flush;
00934 nlreadline(*_pServerStream, resp);
00935 if (_pServerStream->good())
00936 break;
00937
00938 // If we have lost the connection to the news server, we try
00939 // to reconnect to the server and reissue the command.
00940 slog.
00941 p(Logger::
00942 Warning) <<
00943 "lost connection to news server unexpectedly\n";
00944 for (;;) {
00945 i--;
00946 if (i == 0)
00947 throw
00948 SystemError
00949 ("maximum number of retries reached while trying to post an article",
00950 -1, ERROR_LOCATION);
00951 disconnect();
00952 try {
00953 connect();
00954 break;
00955 }
00956 catch(SystemError & se) {
00957 }
00958 }
00959 }
00960
00961 p = resp.c_str();
00962 if (strncmp("240", p, 3) != 0) {
00963 if (strncmp("440", p, 3) == 0)
00964 throw NotAllowedError(resp, ERROR_LOCATION);
00965 if (strncmp("441", p, 3) == 0)
00966 throw PostingFailedError(resp, ERROR_LOCATION);
00967 throw ResponseError("post\r\n", "[23]40,44[01]", resp);
00968 }
00969 }
|
|
||||||||||||
|
Select a newsgroup on the remote news server. Remarks: group: 211 nflsg selected 411 no group
Definition at line 489 of file NServer.cc. References _CurrentGroup, _ServerList, ASSERT, Logger::Error, ERROR_LOCATION, ActiveDB::get(), issue(), GroupInfo::name(), NNTP_ISCODE, Logger::p(), MPList::server(), ActiveDB::set(), GroupInfo::set(), setserver(), slog, and VERB. Referenced by article(), connect(), getgroup(), CServer::groupinfo(), groupinfo(), listgroup(), and overviewdb().
00490 {
00491 VERB(slog.
00492 p(Logger::Debug) << "RServer::selectgroup(" << name << ")\n");
00493 ASSERT(if (strlen(name) > 512) {
00494 throw
00495 AssertionError
00496 ("RServer::selectgroup: name of newsgroup too long\n",
00497 ERROR_LOCATION);}
00498 );
00499
00500 if (!force && strcmp(_CurrentGroup.name(), name) == 0)
00501 return;
00502
00503 char buf[MAXPATHLEN];
00504 const char *ep, *p;
00505 int nbr, fst, lst;
00506 MPListEntry *mpe;
00507 string resp;
00508
00509 // Find the server responsible for this newsgroup
00510 if ((mpe = _ServerList->server(name)) == NULL) {
00511 throw NoSuchGroupError("no such group", ERROR_LOCATION);
00512 }
00513
00514 setserver(mpe);
00515 sprintf(buf, "group %s\r\n", name);
00516 resp = issue(buf, NULL);
00517
00518 p = resp.c_str();
00519 if (!NNTP_ISCODE(p, "211")) {
00520 if (NNTP_ISCODE(p, "411"))
00521 throw NoSuchGroupError("no such group",
00522 ERROR_LOCATION);
00523 string c(buf), e("211");
00524 throw ResponseError(c, e, resp);
00525 }
00526
00527 p += 3;
00528 nbr = strtol(p, (char **) &p, 10);
00529 fst = strtol(p, (char **) &p, 10);
00530 lst = strtol(p, (char **) &ep, 10);
00531
00532 if (ep == resp) {
00533 //THROW!?! _Response_should_be_
00534 // 211 $n $f $l $g selected
00535 // $n Nbr. of articles in group
00536 // $f Nbr. of first article
00537 // $l Nbr. of last article
00538 // $g Name of newsgroup
00539 slog.p(Logger::Error)
00540 <<
00541 "response from news server not in >>211 n f l g ...<< format\n";
00542 // If we cannot parse the response code, use the first/last number
00543 // and number of articles from the active database
00544 if (_ActiveDB->get(name, &_CurrentGroup) < 0) {
00545 // If the above call fails, _ActiveDB will be updated with a
00546 // probably inconsistent posting flag ('y')
00547 _CurrentGroup.set(name, 0, 0, 0);
00548 _ActiveDB->set(_CurrentGroup);
00549 }
00550 } else {
00551 _ActiveDB->get(name, &_CurrentGroup);
00552 // If the above call fails, _ActiveDB will be updated with a
00553 // probably inconsistent posting flag ('y')
00554 _CurrentGroup.set(name, fst, lst, nbr);
00555 _ActiveDB->set(_CurrentGroup);
00556 }
00557 }
|
|
|
Disconnect from the current news server and set a new news server as the current one, if the new one is different to the current.
Definition at line 475 of file NServer.cc. References _CurrentGroup, _CurrentServer, disconnect(), MPListEntry::hostname, GroupInfo::init(), Logger::p(), MPListEntry::servicename, slog, and VERB. Referenced by active(), CServer::article(), article(), post(), and selectgroup().
00476 {
00477 VERB(slog.p(Logger::Debug) << "RServer::setserver({"
00478 << server->hostname << "," << server->servicename << "})\n");
00479
00480 if (_CurrentServer == server)
00481 return;
00482
00483 if (_CurrentServer)
00484 disconnect();
00485 _CurrentGroup.init();
00486 _CurrentServer = server;
00487 }
|
|
|
Delete all previously allocated data and install a new list of news servers and newsgroups.
Definition at line 559 of file NServer.cc. References _CurrentGroup, _CurrentServer, _ServerList, disconnect(), GroupInfo::init(), Logger::p(), slog, and VERB. Referenced by ~RServer().
00560 {
00561 VERB(slog.p(Logger::Debug) << "RServer::setserverlist()\n");
00562 // Disconnect
00563 disconnect();
00564
00565 // Clean up
00566 _CurrentGroup.init();
00567 if (_ActiveDB) {
00568 delete _ActiveDB;
00569 _ActiveDB = NULL;
00570 }
00571 _CurrentServer = NULL;
00572 _ServerList = serverlist;
00573 }
|
|
|
Definition at line 239 of file NServer.h. Referenced by connect(), getgroup(), groupinfo(), selectgroup(), setserver(), and setserverlist(). |
|
|
Definition at line 238 of file NServer.h. Referenced by active(), article(), connect(), init(), issue(), overviewdb(), post(), RServer(), setserver(), and setserverlist(). |
|
|
Definition at line 241 of file NServer.h. Referenced by active(), article(), connect(), disconnect(), is_connected(), issue(), listgroup(), overviewdb(), post(), and RServer(). |
|
|
Definition at line 237 of file NServer.h. Referenced by active(), article(), getserverlist(), init(), post(), RServer(), selectgroup(), and setserverlist(). |
1.3.6-20040222