/*
copyright 2001-2002 Alexander Malmberg <alexander@malmberg.org>
*/

#ifndef NNTPServer_h
#define NNTPServer_h

#include <netinet/in.h>


@class NSObject;
@class NSRunLoop;
@class NSString;


@protocol NNTPServer_Receiver
-(void) nntp_serverDate: (const char *)date qid: (unsigned int)qid;

/* if num=-1 the group didn't exist */
-(void) nntp_groupInfo: (int)group : (int)num : (int)first : (int)last qid: (unsigned int)qid;


/*
order is:
'xref-number Subject Author Date Message-ID References bytes lines'
and maybe other optional headers '(header-name: data)*'
tabs between headers

This might be called several times for a single qid if the request is
large. Every call except the last call will have partial==YES
*/
/* TODO: parse and return in nicer form? */
-(void) nntp_headerRange: (int)group : (int)first : (int)last : (int)num :
	(char **)list partial: (BOOL)p qid: (unsigned int)qid;

-(void) nntp_headerId: (const char *)mid  data: (const unsigned char *)data :
	(int)length  qid: (unsigned int)qid;


-(void) nntp_articleRange: (int)group : (int)num
	data: (const unsigned char *)data : (int)length  qid: (unsigned int)qid;

-(void) nntp_articleId: (const char *)mid  data: (const unsigned char *)data :
	(int)length  qid: (unsigned int)qid;

/* name last first may-post */
-(void) nntp_groupList: (const unsigned char *)data : (int)length
	qid: (unsigned int)qid;


/* NO if the article was not accepted by the server (malformed message,
cancelled request, etc.). */
-(void) nntp_postArticle: (BOOL)success  qid: (unsigned int)qid;


-(void) nntp_fail: (NSString *)reason qid: (unsigned int)qid;

/*
Called if we can't open any connection at all to the server. should_connect
will be set to 0 before this call, so you'll have to explictly set it to 1
if you want to try connecting again.
*/
-(void) nntp_fail_connect: (NSString *)reason;
-(void) nntp_message: (NSString *)msg;

-(void) nntp_progress: (int)bytes : (unsigned int)qid;
@end


@interface NNTPServer : NSObject
{
	struct nntp_connection_s *cons;
	int num_cons;
	int num_idle,num_active,num_starting;

	struct nntp_queue_s *queue;

	int should_connect;

	char *host;
	int have_addr;
	struct sockaddr_in addr;
	int port;
	int protocol;

	NSRunLoop *runloop;
	NSArray *runmodes;

	id<NNTPServer_Receiver,NSObject> rec;

	NSString *last_error;

	NSTimeInterval last_connect_attempt,lca_delta;

	int set_timeout;
}

+(int) getGroupNum: (const char *)group;
+(const char *) getGroupName: (int)group;


-init;
-initWithHost: (const char *)host;
-initWithHost: (const char *)host port: (int)port;
-initWithAddr: (struct sockaddr_in *)addr  port: (int)port
	host: (const char *)host;

-(void) enableConnect: (int)should_connect;
-(void) enableTimeout: (int)should_connect;

-(void) setReceiver: (id<NNTPServer_Receiver>)arec;

-(void) closeAllConnections;
-(void) killAllConnections;


-(NSString *)qidDescription: (unsigned int)qid;


/* -10000 < priority < 10000
default is 0, use lower for background bulk transfers/read-ahead, higher
for 'interactive' stuff (like the article the user just clicked on)
*/

-(unsigned int) getServerDate;

-(unsigned int) getGroupList: (int)priority;
//-(unsigned int) getGroupListSince: (const char *)date;

-(unsigned int) getGroupInfo: (int)group;

-(unsigned int) getHeaderRange: (int)low : (int)high  group: (int)group
	priority: (int)pri;
-(unsigned int) getHeaderById: (const char *)msg_id  priority: (int)pri;

-(unsigned int) getArticleRange: (int)low : (int)high  group: (int)group
	priority: (int)pri;
-(unsigned int) getArticleById: (const char *)msg_id  priority: (int)priority;
-(unsigned int) getArticleById: (const char *)msg_id  size: (int)bytes
	priority: (int)pri;

/* a copy is made of the data, so the caller does not have to keep it
around */
-(unsigned int) postArticle: (unsigned char *)data  length: (int)length
	priority: (int)priority;

/* If kill is YES, try _really_ hard to cancel (ie. if the request is
already in progress on a connection, kill the connection; this is not
nice on the server, so use only when really necessary). */
-(BOOL) cancelQid: (unsigned int)qid  kill: (BOOL)kill;

@end

#endif

