[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Pan-devel] Pan 0.91 issues
From: |
Charles Kerr |
Subject: |
Re: [Pan-devel] Pan 0.91 issues |
Date: |
Wed, 05 Apr 2006 13:01:59 -0500 |
User-agent: |
Mozilla Thunderbird 1.0.7-1.4.1 (X11/20050929) |
Christophe Lambin wrote:
- For some reason, certain rows in the articlelist appear underscored. This
happens when I read an article that has collapsed articles below it. If
I expand the row, the underscore disappears. Reading articles that do not
have collapsed articles doesn't show the underscores.
Underscores are stolen from Thunderbird et al. to denote there are
unread messages underneath the collapsed thread.
- Posting did not work yet. I ran pan in debug mode (pan --debug) and saw
the following:
(socket-impl-gio.cc:299:do_write) socket 0x90be6a0 channel 0x9060c90
maybe wrote [From: "Christophe Lambin" <address@hidden>
Subject: test
Newsgroups: easynet.test
User-Agent: pan 0.91 (I'm lost. I'm drunk. I'm impure. What a life!)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
test.^M
.^M
]; status was 1
[...]
(socket-impl-gio.cc:247:do_read) read [441 Article has no body --
just headers^M]
I telnetted to the newsserver and POSTed the stream directly and it
worked. Since the log says 'maybe wrote', perhaps the full stream
wasn't written to the server (since we're using non-blocking I/O).
Could you rebuild with the attached nntp.cc and see if that fixes it?
Charles
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* Pan - A Newsreader for Gtk+
* Copyright (C) 2002-2006 Charles Kerr <address@hidden>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <config.h>
#include <cassert>
#include <stdarg.h>
#include <glib.h>
#include <pan/general/debug.h>
#include <pan/general/i18n.h>
#include <pan/general/log.h>
#include <pan/general/messages.h>
#include "nntp.h"
using namespace pan;
namespace
{
std::string
build_command (const char * fmt, ...)
{
std::string cmd;
if (fmt)
{
va_list args;
va_start (args, fmt);
char * str = g_strdup_vprintf (fmt, args);
va_end (args);
cmd = str;
g_free (str);
}
return cmd;
}
};
namespace
{
enum
{
AUTH_REQUIRED = 480,
AUTH_NEED_MORE = 381,
AUTH_ACCEPTED = 281,
AUTH_REJECTED = 482,
SERVER_READY = 200,
SERVER_READY_NO_POSTING = 201,
GOODBYE = 205,
GROUP_RESPONSE = 211,
GROUP_NONEXISTENT = 411,
INFORMATION_FOLLOWS = 215,
XOVER_FOLLOWS = 224,
XOVER_NO_ARTICLES = 420,
ARTICLE_FOLLOWS = 220,
NEWGROUPS_FOLLOWS = 231,
ARTICLE_POSTED_OK = 240,
SEND_ARTICLE_NOW = 340,
NO_POSTING = 440,
POSTING_FAILED = 441,
TOO_MANY_CONNECTIONS = 400,
NO_GROUP_SELECTED = 412,
NO_SUCH_ARTICLE_NUMBER = 423,
NO_SUCH_ARTICLE = 430,
ERROR_CMD_NOT_UNDERSTOOD = 500,
ERROR_CMD_NOT_SUPPORTED = 501,
NO_PERMISSION = 502,
ERROR_TIMEOUT = 503
};
}
void
NNTP :: fire_done_func (Health health)
{
if (_listener)
{
Listener * l = _listener;
debug ("I (" << (void*)this << ") am setting my _listener to 0");
_listener = 0;
l->on_nntp_done (this, health);
}
}
/***
**** WRITING
***/
void
NNTP :: onSocketOpen (Socket * sock)
{
}
bool
NNTP :: onSocketResponse (Socket * sock, const StringView& line_in)
{
enum State { CMD_FAIL, CMD_DONE, CMD_MORE, CMD_NEXT, CMD_RETRY };
State state;
StringView line (line_in);
// strip off trailing \r\n
if (line.len>=2 && line.str[line.len-2]=='\r' && line.str[line.len-1]=='\n')
line.truncate (line.len-2);
//debug ("_nntp_response_text: " << _nntp_response_text);
if (_nntp_response_text)
{
if (line.len==1 && line.str[0]=='.') // end-of-list
{
state = CMD_DONE;
_nntp_response_text = false;
}
else
{
state = CMD_MORE;
if (line.len>=2 && line.str[0]=='.' && line.str[1]=='.') // rfc 977:
2.4.1
line.rtruncate (line.len-1);
assert (_listener != 0);
if (_listener)
_listener->on_nntp_line (this, line);
}
}
else switch (atoi (line.str))
{
case SERVER_READY:
case SERVER_READY_NO_POSTING:
if (_username.empty())
state = CMD_DONE;
else {
_socket->write_command_va (
this, "AUTHINFO USER %s\r\n", _username.c_str());
state = CMD_NEXT;
}
break;
case ARTICLE_POSTED_OK:
case GOODBYE:
case XOVER_NO_ARTICLES:
state = CMD_DONE;
break;
case AUTH_REQUIRED:
// must send username
_commands.push_front (_previous_command);
_socket->write_command_va (
this, "AUTHINFO USER %s\r\n", _username.c_str());
state = CMD_NEXT;
break;
case AUTH_NEED_MORE:
// must send password
_socket->write_command_va (
this, "AUTHINFO PASS %s\r\n", _password.c_str());
state = CMD_NEXT;
break;
case AUTH_ACCEPTED:
// logged in ok; now retry request
if (_commands.empty())
state = CMD_DONE;
else {
write_next_command ();
state = CMD_NEXT;
}
break;
case AUTH_REJECTED:
state = CMD_FAIL;
break;
case GROUP_RESPONSE: {
// response is of form "211 qty low high group_name"
StringView tok, myline (line);
myline.pop_token (tok, ' ');
myline.pop_token (tok, ' ');
const unsigned long aqty (strtoul (tok.str, NULL, 10));
myline.pop_token (tok, ' ');
const unsigned long alo (strtoul (tok.str, NULL, 10));
myline.pop_token (tok, ' ');
const unsigned long ahi (strtoul (tok.str, NULL, 10));
myline.pop_token (tok, ' ');
const pan::Quark group (tok);
if (_listener)
_listener->on_nntp_group (this, group, aqty, alo, ahi);
const bool do_command (!_commands.empty());
_group = group;
if (!do_command)
state = CMD_DONE;
else { // now that we're in the right group, send the command.
write_next_command ();
state = CMD_NEXT;
}
break;
}
case SEND_ARTICLE_NOW:
// ready to get article; send it now
_socket->write_command (_post, this);
state = CMD_NEXT;
break;
case NO_POSTING:
case POSTING_FAILED:
state = CMD_FAIL;
break;
case GROUP_NONEXISTENT:
Log::add_err_va (_("Unable to set group: %s"),
line.to_string().c_str());
state = CMD_FAIL;
break;
case XOVER_FOLLOWS:
case ARTICLE_FOLLOWS:
case NEWGROUPS_FOLLOWS:
case INFORMATION_FOLLOWS:
state = CMD_MORE;
_nntp_response_text = true;
break;
case NO_GROUP_SELECTED:
case ERROR_CMD_NOT_UNDERSTOOD:
case ERROR_CMD_NOT_SUPPORTED:
case NO_PERMISSION:
Log::add_err_va (_("Error: %s"), line.to_string().c_str());
case NO_SUCH_ARTICLE_NUMBER:
case NO_SUCH_ARTICLE:
state = CMD_FAIL;
break;
case ERROR_TIMEOUT:
case TOO_MANY_CONNECTIONS:
state = CMD_RETRY;
break;
default:
g_message ("I don't know how to handle this: [%s]",
line.to_string().c_str());
state = CMD_FAIL;
break;
}
bool more;
switch (state) {
case CMD_FAIL: fire_done_func (FAIL); more = false; break;
case CMD_DONE: if (_commands.empty()) fire_done_func (OK); more = false;
break;
case CMD_MORE: more = true; break; // keep listining for more on this
command
case CMD_NEXT: more = false; break; // no more responses on this command;
wait for next...
case CMD_RETRY: fire_done_func (RETRY); more = false; break;
default: abort(); break;
}
return more;
}
void
NNTP :: onSocketAbort (Socket * sock)
{
fire_done_func (FAIL);
}
void
NNTP :: onSocketError (Socket * sock)
{
_socket_error = true;
fire_done_func (RETRY);
}
namespace
{
void
ensure_trailing_crlf (GString * g)
{
if (g->len<2 || g->str[g->len-2]!='\r' || g->str[g->len-1]!='\n')
g_string_append (g, "\r\n");
}
};
void
NNTP :: write_next_command ()
{
assert (!_commands.empty());
//for (strings_t::const_iterator it=_commands.begin(), end=_commands.end();
it!=end; ++it)
// debug ("command [" << *it << ']');
_previous_command = _commands.front ();
_commands.pop_front ();
debug ("nntp " << this << " writing to socket " << _socket << " on server "
<< _server << " this command: [" << _previous_command << ']');
_socket->write_command (_previous_command, this);
}
/***
****
***/
void
NNTP :: xover (const Quark & group,
unsigned long low,
unsigned long high,
Listener * l)
{
_listener = l;
if (group != _group)
_commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
_commands.push_back (build_command ("XOVER %lu-%lu\r\n", low, high));
write_next_command ();
}
void
NNTP :: list_newsgroups (Listener * l)
{
_listener = l;
_commands.push_back ("LIST NEWSGROUPS\r\n");
write_next_command ();
}
void
NNTP :: list (Listener * l)
{
_listener = l;
_commands.push_back ("LIST\r\n");
write_next_command ();
}
void
NNTP :: article (const Quark & group,
unsigned long article_number,
Listener * l)
{
_listener = l;
if (group != _group)
_commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
_commands.push_back (build_command ("ARTICLE %lu\r\n", article_number));
write_next_command ();
}
void
NNTP :: article (const Quark & group,
const char * message_id,
Listener * l)
{
_listener = l;
if (group != _group)
_commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
_commands.push_back (build_command ("ARTICLE %s\r\n", message_id));
write_next_command ();
}
void
NNTP :: group (const Quark & group,
Listener * l)
{
_listener = l;
_commands.push_back (build_command ("GROUP %s\r\n", group.c_str()));
debug ("_commands.size(): " << _commands.size());
write_next_command ();
}
void
NNTP :: goodbye (Listener * l)
{
_listener = l;
_commands.push_back ("QUIT\r\n");
write_next_command ();
}
void
NNTP :: handshake (Listener * l)
{
_listener = l;
_commands.push_back ("");
write_next_command ();
}
void
NNTP :: noop (Listener * l)
{
_listener = l;
_commands.push_back ("MODE READER\r\n");
write_next_command ();
}
namespace
{
// non-recursive search and replace.
void replace_linear (std::string& s, const char* old_text, const char *
new_text)
{
std::string::size_type pos (0);
while (((pos = s.find (old_text, pos))) != std::string::npos) {
s.replace (pos, strlen(old_text), new_text);
pos += strlen(new_text);
}
}
}
void
NNTP :: post (const StringView & msg,
Listener * l)
{
_listener = l;
std::string s (msg.str, msg.len);
replace_linear (s, "\n.", "\n..");
replace_linear (s, "\n", "\r\n");
replace_linear (s, "\r\r\n.", "\r\n");
s += ".\r\n";
// if we're in mute mode, don't post
if (0)
{
std::cerr << LINE_ID
<< "Mute: Your Message won't be posted." << std::endl
<< "Your Message:" << std::endl
<< s << std::endl
<< "<end of message>" << std::endl;
}
else
{
_post = s;
_commands.push_back ("POST\r\n");
write_next_command ();
}
}
#if 0
void
nntp_cancel (GIOChannel * channel,
const PString * message_id,
nntp_done_func done_func,
gpointer done_func_user_data)
{
const char * newsgroups;
const char * author;
GMimeMessage * message;
debug_enter ("nntp_cancel");
/* sanity checks */
pan_return_if_fail (channel != NULL);
pan_return_if_fail (pstring_is_set (message_id));
pan_return_if_fail (acache_has_message(ACACHE_DEFAULT_KEY, message_id));
/* get info */
message = acache_get_message (ACACHE_DEFAULT_KEY, &message_id, 1);
newsgroups = g_mime_message_get_header (message, HEADER_NEWSGROUPS);
author = g_mime_message_get_sender (message);
if (is_nonempty_string(newsgroups) && is_nonempty_string(author))
{
char * buf = g_strdup_printf (
"From: %s\r\n"
"Newsgroups: %s\r\n"
"Subject: cancel %s\r\n"
"Control: cancel %s\r\n"
"\r\n"
"Ignore\r\n"
"Article canceled by Pan %s\r\n",
author,
newsgroups,
message_id->str,
message_id->str,
VERSION);
/* post the cancel message */
nntp_post (channel, buf, done_func, done_func_user_data);
/* cleanup */
g_free (buf);
}
/* cleanup */
g_object_unref (message);
debug_exit ("nntp_cancel");
}
#endif
- [Pan-devel] Pan 0.91 issues, Christophe Lambin, 2006/04/04
- Re: [Pan-devel] Pan 0.91 issues,
Charles Kerr <=
- Re: [Pan-devel] Pan 0.91 issues, Christophe Lambin, 2006/04/05
- Re: [Pan-devel] Pan 0.91 issues, Charles Kerr, 2006/04/05
- Re: [Pan-devel] Pan 0.91 issues, Christophe Lambin, 2006/04/05
- Re: [Pan-devel] Pan 0.91 issues, Charles Kerr, 2006/04/05
- [Pan-devel] newsrc corruption theory (Was: Pan 0.91 issues), Charles Kerr, 2006/04/06
- Re: [Pan-devel] newsrc corruption theory (Was: Pan 0.91 issues), Christophe Lambin, 2006/04/06
- Re: [Pan-devel] newsrc corruption theory (Was: Pan 0.91 issues), Charles Kerr, 2006/04/06
- Re: [Pan-devel] newsrc corruption theory (Was: Pan 0.91 issues), Christophe Lambin, 2006/04/06
- Re: [Pan-devel] newsrc corruption theory (Was: Pan 0.91 issues), Christophe Lambin, 2006/04/07
- Re: [Pan-devel] Pan 0.91 issues, K. Haley, 2006/04/06