/*$Copyright:
 * Copyright (C) 1992.5.22. Recruit Co.,Ltd. 
 * Institute for Supercomputing Research
 * All rights reserved.
 * NewsBase  by ISR, Kazuto MIYAI, Gary ARAKAKI, Katsunori SUZUKI, Kok-meng Lue
 *
 * You may freely copy, distribute and reuse the code in this program under 
 * following conditions.
 * - to include this notice in the source code, if it is to be distributed 
 *   with source code.
 * - to add the file named "COPYING" within the code, which shall include 
 *   GNU GENERAL PUBLIC LICENSE(*).
 * - to display an acknowledgement in binary code as follows: "This product
 *   includes software developed by Recruit Co.,Ltd., ISR."
 * - to display a notice which shall state that the users may freely copy,
 *   distribute and reuse the code in this program under GNU GENERAL PUBLIC
 *   LICENSE(*)
 * - to indicate the way to access the copy of GNU GENERAL PUBLIC LICENSE(*)
 *
 *   (*)GNU GENERAL PUBLIC LICENSE is stored in the file named COPYING
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
$*/

// This exists as a Class only no instances. Provides support routines for
// io with the NNTP server.  Really just an object-oriented interface to
// an NNTP io library.


#import "INewsD.h"
#import <c.h>
#import <libc.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <sys/dir.h>
#import "IConvertMIME.h"
#import "IArticleD.h"
#import "InfoD.h"
#import "ITextD.h"
#import "IMediaTable.h"
#import "IMediaD.h"
#import "IBinaryD.h"
#import "data_types.h"
#import "IAppDelegate.h"
#import "IReceiveSpeaker.h"
#import <appkit/NXImage.h>
#import <appkit/Pasteboard.h>
#import "Localization.h"
#import "errdebug.h"

// All communication with the NNTP Server should flow through this class.
// This is a class only.  There are no instances.  Really just an object-
// oriented interface to the NNTP server.

@implementation INewsD

static NXAtom domain;
static NXAtom fileExtension;

+ initialize
{
    domain = NXUniqueStringNoCopy("X-news");
    fileExtension = NXUniqueStringNoCopy("X-news");
    return(self);
}

+ (NXAtom)domain
{
    return(domain);
}

+ (NXAtom)fileExtension
{
    return(fileExtension);
}
+ (NXAtom)pasteboardType
{
    return(NULL);
}
//*****************************************************************************
// post article to NNTP server
//*****************************************************************************

+ (BOOL)saveWithoutPrompt:(IArticleD *)saveArticle
{
    return([self save:saveArticle]);
}

+ (BOOL)save:(IArticleD *)article
// really post to NNTP server  (save: is the generic method name for external
// domain method for output)
{
    NXStream *articlestream;
    id conv;
    int len,max,size;
    char *buff;

    // convert to MIME
    conv = [[IConvertMIME alloc] init];
    articlestream = NXOpenMemory(NULL, 0, NX_READWRITE);
    [conv convertToMIME:article stream:articlestream];
    [conv free];

    // send to NNTP
    NXSeek(articlestream, (long)0,NX_FROMEND);
    (long)size = NXTell(articlestream);
     NXSeek(articlestream, (long)0,NX_FROMSTART);
     NXGetMemoryBuffer(articlestream,&buff, &len,  &max);
    [[NXApp delegate] postArticle:(const char *)buff length:(int)size];
     NXCloseMemory(articlestream,NX_FREEBUFFER);

    // link NNTP article to IExternalD for object
    [[article external] setDomain:domain
        andPath:[[article dataForKey:HEADER_INFO] infoForKey:MESSAGE_ID]];
    return(YES);
}

+ setSaveDomainAndPath:(IArticleD *)article
{
    [[article external] setDomain:domain
        andPath:[[article dataForKey:HEADER_INFO] infoForKey:MESSAGE_ID]];
    return(self);
}

//*****************************************************************************
// receive article from NNTP server
//*****************************************************************************

// receive article from NNTP and open viewer/editor
+ (BOOL)openArticle:(const char *)articleBuffer length:(int)length
{
    NXStream *stream;
    IConvertMIME *conv;
    IArticleD *article;
    IExternalD *external;
    const char *path;
    NXZone *zone;

    DBG(1, ;)

    // convert from MIME
    stream = NXOpenMemory(articleBuffer, length, NX_READONLY);
    conv = [[IConvertMIME allocFromZone:NXCreateZone(vm_page_size, vm_page_size,
        YES)] init];
    article = [conv convertToItem:stream];
    [conv free];

    // make IExternalD and create appropriate links
    path = [[article dataForKey:HEADER_INFO] infoForKey:MESSAGE_ID];
    zone = [article zone];
    external = [[IExternalD allocFromZone:zone] initWithDomain:domain
        andPath:path];
    if ([external zone] != zone) {
        // article created in wrong zone so recreate it in right zone
        conv = [[IConvertMIME allocFromZone:[external zone]] init];
        article = [conv convertToItem:stream];
        [conv free];
    }
    if ([external objectExists] == nil) {
        [external setObject:article];
        [article setExternal:external];
    } else {
        // article already exists (from earlier read)
        [article free];
        article = [external object];
    }
    // INewsD will temporarily reference this external
    [external incrementReferenceCount];
//    [article referenceAllObjects];

    // create viewer if it doesn't exists
    [article openEditor];
    // remove temporary reference
    [external decrementReferenceCount];
//    [article unreferenceAllObjects];
    NXCloseMemory(stream, NX_FREEBUFFER);
    return(YES);
}

// loadFromName:inZone: is done asynchronously.  i.e., the article
// will be defined some time AFTER the return.

+ (IArticleD *)loadFromName:(const char *)path inZone:(NXZone *)zone
{
    port_t      port;
    int         returnCode;

    if ((port = NXPortFromName(NEWSBASE, NULL)) == PORT_NULL) {
        NXRunAlertPanel(MMEDITOR, LoStr("Cannot find port %s"),
            LoStr("OK"), NULL, NULL, NEWSBASE);
        return(nil);
    }
    [[NXApp appSpeaker] setSendPort:port];
    if ((returnCode = [[NXApp appSpeaker]
        sendArticleWithMessageID:path]) != 0) {
        NXRunAlertPanel(MMEDITOR, LoStr("Cannot contact %s"),
            LoStr("OK"), NULL, NULL, NEWSBASE);
    }
    return(nil);
}

@end



