Logo Search packages:      
Sourcecode: pan version File versions  Download package

task-bodies.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Pan - A Newsreader for Gtk+
 * Copyright (C) 2002  Charles Kerr <charles@rebelbase.com>
 *
 * 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
 */

/*********************
**********************  Includes
*********************/

#include <config.h>

#include <stdlib.h>
#include <string.h>

#include <glib.h>

#include <pan/base/acache.h>
#include <pan/base/article.h>
#include <pan/base/debug.h>
#include <pan/base/log.h>
#include <pan/base/pan-glib-extensions.h>
#include <pan/base/pan-i18n.h>

#include <pan/nntp.h>
#include <pan/queue.h>
#include <pan/task-bodies.h>

/*********************
**********************  Defines / Enumerated types
*********************/

/*********************
**********************  Macros
*********************/

/*********************
**********************  Structures / Typedefs
*********************/

/*********************
**********************  Private Function Prototypes
*********************/

static void task_bodies_run (Task* item, PanSocket * sock);

static char* task_bodies_describe (const StatusItem* item);

/*********************
**********************  Variables
*********************/

/***********
************  Extern
***********/

/***********
************  Public
***********/

/***********
************  Private
***********/

/*********************
**********************  BEGINNING OF SOURCE
*********************/

static void
task_bodies_destructor (PanObject * obj)
{
      TaskBodies * task;
      gpointer p;
      debug_enter ("task_bodies_destructor");

      /* sanity clause */
      g_return_if_fail (obj!=NULL);

      /* task-bodies dtor */
      {
            GPtrArray * mids = TASK(obj)->identifiers;
            const PString ** ids = message_identifiers_get_id_array ((const MessageIdentifier**)mids->pdata, mids->len);
            acache_checkin (ACACHE_DEFAULT_KEY, ids, mids->len);
            g_free (ids);
      }
      task = TASK_BODIES(obj);
      while ((p = g_queue_pop_head (task->download_mids)))
            g_object_unref (G_OBJECT(p));
      g_queue_free (task->download_mids);

      /* destroy parent class */
      task_destructor (obj);

      debug_exit ("task_bodies_destructor");
}

/************
*************  PUBLIC ROUTINES
************/

PanObject*
task_bodies_new (Server               * server,
                 MessageIdentifier   ** mids,
                 int                    mid_qty)
{
      int i;
      int lines_total = 0;
      int lines_cached = 0;
      TaskBodies * bodies = NULL;
      const PString ** ids;
      debug_enter ("task_bodies_new");

      /* sanity clause */
      g_return_val_if_fail (mids!=NULL, NULL);
      g_return_val_if_fail (mid_qty!=0, NULL);

      /* check out all the articles */
      ids = message_identifiers_get_id_array ((const MessageIdentifier**)mids, mid_qty);
      acache_checkout (ACACHE_DEFAULT_KEY, ids, mid_qty);
      g_free (ids);

      /* create the object */
            bodies = g_new0 (TaskBodies, 1);
        debug1 (DEBUG_PAN_OBJECT, "task_bodies_new: %p", mids);

      /* initialize the parent class' bits */
      task_constructor (TASK(bodies), task_bodies_destructor, task_bodies_describe, server, TRUE);
      TASK(bodies)->gets_bodies = TRUE;
      TASK(bodies)->type = TASK_TYPE_BODIES;
      task_add_identifiers (TASK(bodies), mids, mid_qty);

      /* initialize the task_bodies bits */
      bodies->download_mids = g_queue_new ();
      for (i=0; i<mid_qty; ++i) {
            lines_total += mids[i]->line_qty;
            if (acache_has_message (ACACHE_DEFAULT_KEY, &mids[i]->message_id))
                  lines_cached += mids[i]->line_qty;
            else {
                  g_queue_push_tail (bodies->download_mids, mids[i]);
                  g_object_ref (mids[i]);
            }
      }
      bodies->download_mids_qty = bodies->download_mids->length;

      /* set the state */
      if (g_queue_is_empty (bodies->download_mids))
            task_state_set_work_completed (&TASK(bodies)->state);
      else
            task_state_set_work_need_socket (&TASK(bodies)->state, server, task_bodies_run);

      /* init the status-item */
      status_item_emit_init_steps (STATUS_ITEM(bodies), lines_total);
      status_item_emit_set_step (STATUS_ITEM(bodies), lines_cached);
      if (mid_qty > 1)
            status_item_emit_status_va (STATUS_ITEM(bodies), _("Downloading %d"), mid_qty);
      else
            status_item_emit_status_va (STATUS_ITEM(bodies), _("\"%s\""), message_identifier_get_readable_name (mids[0]));

      /* return the task */
      debug_exit ("task_bodies_new");
      return PAN_OBJECT(bodies);
}

PanObject*
task_bodies_new_from_articles (const Article       ** articles,
                               int                    article_qty)
{
      int i;
      MessageIdentifier ** mids;
      PanObject * retval;

      /* sanity clause */
      g_return_val_if_fail (articles!=NULL, NULL);
      g_return_val_if_fail (article_qty>0, NULL);
      g_return_val_if_fail (articles_are_valid (articles, article_qty), NULL);

      /* build the task */
      mids = g_newa (MessageIdentifier*, article_qty);
      for (i=0; i<article_qty; ++i)
            mids[i] = message_identifier_new_from_article (articles[i]);
      retval = task_bodies_new (articles[0]->group->server, mids, article_qty);
      for (i=0; i<article_qty; ++i)
            g_object_unref (mids[i]);

      /* cleanup */
      return retval;
}

/*****
******
*****/

static char*
task_bodies_describe (const StatusItem* si)
{
      char * retval;
      GPtrArray * mids = TASK(si)->identifiers;

      if (mids->len != 1u)
            retval = g_strdup_printf (_("Downloading %u articles"), mids->len);
      else {
            MessageIdentifier * mid = MESSAGE_IDENTIFIER (g_ptr_array_index (mids, 0));
            retval = g_strdup (message_identifier_get_readable_name (mid));

            if (!g_utf8_validate (retval, -1, NULL))
                  replace_gstr (&retval, g_strdup (_("Downloading 1 article")));
      }

      return retval;
}

/*****
******
*****/

static void
task_bodies_run (Task * task, PanSocket * sock)
{
      TaskStateEnum val;
      TaskBodies * bodies = TASK_BODIES(task);
      MessageIdentifier * mid;
      debug_enter ("task_bodies_run");

      mid = g_queue_pop_head (bodies->download_mids);

      /* before we do work, let the queue know if we need another socket */
      if (!g_queue_is_empty (bodies->download_mids)) {
            task_state_set_work_need_socket (&task->state, task->server, task_bodies_run);
            queue_wakeup ();
      }

      /* download the article */    
      val = nntp_article_download (STATUS_ITEM(task), sock, mid, &task->hint_abort, NNTP_VERBOSE_NEXT_STEP);

      task_state_set_health (&task->state, val);


      if (val != TASK_OK) {
            /* if we got it, remove it from the list. */
            g_queue_push_tail (bodies->download_mids, mid);
            task_state_set_work_need_socket (&task->state, task->server, task_bodies_run);
      } else {
            /* save the mid for a future attempt */
            g_object_unref (G_OBJECT(mid));
            if (!--bodies->download_mids_qty)
                  task_state_set_work_completed (&task->state);
      }

      debug_exit ("task_bodies_run");
}

Generated by  Doxygen 1.6.0   Back to index