Ejemplo n.º 1
0
static void start_push(HTTPCaller *caller, long i)   
{
    List *push_headers;
    Octstr *push_content;
    long *id;
    
    push_content = push_content_create();
    push_headers = push_headers_create(octstr_len(push_content));
    if (verbose) {
       debug("test.ppg", 0, "we have push content");
       octstr_dump(push_content, 0);
       debug("test.ppg", 0, "and headers");
       http_header_dump(push_headers);
    }

    id = gw_malloc(sizeof(long));
    *id = i;
    make_url(&push_url);
    debug("test.ppg", 0, "TEST_PPG: starting to push job %ld", i);
    http_start_request(caller, HTTP_METHOD_POST, push_url, push_headers, 
                       push_content, 0, id, ssl_client_certkey_file);
    debug("test.ppg", 0, "push done");
    octstr_destroy(push_content);
    http_destroy_headers(push_headers);
}
Ejemplo n.º 2
0
/* Sends REQ on socket SOCKFD. Returns the number of bytes which were sent,
 * and -1 on error. */
int kvrequest_send(kvrequest_t *kvreq, int sockfd) {
  char *method = http_method_for_request_type(kvreq->type);
  if (!method) return -1;

  struct url_params params;
  params.path = path_for_request_type(kvreq->type);
  params.key = kvreq->key;
  params.val = kvreq->val;

  char *url = url_encode(&params);
  struct http_outbound *msg = http_start_request(sockfd, method, url);
  if (!msg) return -1;
  free(url);

  http_end_headers(msg);
  return http_send_and_free(msg);
}
Ejemplo n.º 3
0
static void start_request(HTTPCaller *caller, List *reqh, long i)
{
    Octstr *url, *content = NULL;
    long *id;

    if ((i % 1000) == 0)
	info(0, "Starting fetch %ld", i);
    id = gw_malloc(sizeof(long));
    *id = i;
    url = octstr_create(urls[i % num_urls]);
    if (file) {
        octstr_append(url, octstr_imm("&text="));
        octstr_append(url, msg_text);
    }

    /* add the extra headers that have been read from the file */
    if (split != NULL)
        http_header_combine(reqh, split);

    /* 
     * if a body content file has been specified, then
     * we assume this should be a POST
     */
    if (content_file != NULL) {
        content = post_content_create();
        method = HTTP_METHOD_POST;
    }
                                
    /*
     * if this is a POST request then pass the required content as body to
     * the HTTP server, otherwise skip the body, the arguments will be
     * urlencoded in the URL itself.
     */
    http_start_request(caller, method,
                       url, reqh, content, follow_redirect, id, ssl_client_certkey_file);

    debug("", 0, "Started request %ld with url:", *id);
    octstr_url_decode(url);
    octstr_dump(url, 0);
    octstr_destroy(url);
    octstr_destroy(msg_text);
    octstr_destroy(content);
}
Ejemplo n.º 4
0
static int kannel_send_sms(SMSCConn *conn, Msg *sms)
{
    ConnData *conndata = conn->data;
    Octstr *url;
    List *headers;

    if (!conndata->no_sep) {
        url = octstr_format("%S?"
			    "username=%E&password=%E&to=%E&text=%E",
			     conndata->send_url,
			     conndata->username, conndata->password,
			     sms->sms.receiver, sms->sms.msgdata);
    } else {
        Octstr *msgdata = octstr_duplicate(sms->sms.msgdata);
        
        octstr_binary_to_hex(msgdata, HEX_NOT_UPPERCASE);
        url = octstr_format("%S?"
			    "username=%E&password=%E&to=%E&text=%S",
			     conndata->send_url,
			     conndata->username, conndata->password,
			     sms->sms.receiver, msgdata);
        octstr_destroy(msgdata);
    }   

    if (octstr_len(sms->sms.udhdata)) {
        if (!conndata->no_sep) {
            octstr_format_append(url, "&udh=%E", sms->sms.udhdata);
        } else {
            Octstr *udhdata = octstr_duplicate(sms->sms.udhdata);
            
            octstr_binary_to_hex(udhdata, HEX_NOT_UPPERCASE);
            octstr_format_append(url, "&udh=%S", udhdata);
            octstr_destroy(udhdata);
        }
    }

    if (!conndata->no_sender)
        octstr_format_append(url, "&from=%E", sms->sms.sender);
    if (sms->sms.mclass != MC_UNDEF)
        octstr_format_append(url, "&mclass=%d", sms->sms.mclass);
    if (!conndata->no_coding && sms->sms.coding != DC_UNDEF)
        octstr_format_append(url, "&coding=%d", sms->sms.coding);

    /* Obey that smsbox's sendsms HTTP interface is still expecting 
     * WINDOWS-1252 as default charset, while all other internal parts
     * use UTF-8 as internal encoding. This means, when we pass a SMS
     * into a next Kannel instance, we need to let the smsbox know which
     * charset we have in use.
     * XXX TODO: change smsbox interface to use UTF-8 as default
     * in next major release. */
    if (sms->sms.coding == DC_7BIT)
        octstr_append_cstr(url, "&charset=UTF-8");
    else if (sms->sms.coding == DC_UCS2)
        octstr_append_cstr(url, "&charset=UTF-16BE");

    if (sms->sms.mwi != MWI_UNDEF)
        octstr_format_append(url, "&mwi=%d", sms->sms.mwi);
    if (sms->sms.account) /* prepend account with local username */
        octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account);
    if (sms->sms.binfo) /* prepend billing info */
        octstr_format_append(url, "&binfo=%S", sms->sms.binfo);
    if (sms->sms.smsc_id) /* proxy the smsc-id to the next instance */
        octstr_format_append(url, "&smsc=%S", sms->sms.smsc_id);
	if (conndata->dlr_url) {
		char id[UUID_STR_LEN + 1];
		Octstr *mid;

		/* create Octstr from UUID */
		uuid_unparse(sms->sms.id, id);
		mid = octstr_create(id);

		octstr_format_append(url, "&dlr-url=%E", conndata->dlr_url);

		/* encapsulate the original DLR-URL, escape code for DLR mask
		 * and message id */
		octstr_format_append(url, "%E%E%E%E%E",
			octstr_imm("&dlr-url="), sms->sms.dlr_url != NULL ? sms->sms.dlr_url : octstr_imm(""),
			octstr_imm("&dlr-mask=%d"),
			octstr_imm("&dlr-mid="), mid);

		octstr_destroy(mid);
	} else if (sms->sms.dlr_url != NULL)
		octstr_format_append(url, "&dlr-url=%E", sms->sms.dlr_url);
    if (sms->sms.dlr_mask != DLR_UNDEFINED && sms->sms.dlr_mask != DLR_NOTHING)
        octstr_format_append(url, "&dlr-mask=%d", sms->sms.dlr_mask);

    if (sms->sms.validity != SMS_PARAM_UNDEFINED)
    	octstr_format_append(url, "&validity=%ld", (sms->sms.validity - time(NULL)) / 60);
    if (sms->sms.deferred != SMS_PARAM_UNDEFINED)
    	octstr_format_append(url, "&deferred=%ld", (sms->sms.deferred - time(NULL)) / 60);

    headers = gwlist_create();
    debug("smsc.http.kannel", 0, "HTTP[%s]: Start request",
          octstr_get_cstr(conn->id));
    http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
                       NULL, 0, sms, NULL);

    octstr_destroy(url);
    http_destroy_headers(headers);

    return 0;
}
Ejemplo n.º 5
0
/* MT related function */
static int brunet_send_sms(SMSCConn *conn, Msg *sms)
{
    ConnData *conndata = conn->data;
    Octstr *url, *tid, *xser;
    List *headers;
    char id[UUID_STR_LEN + 1];
    int dcs;

    /*
     * Construct TransactionId.
     * Beware that brunet needs an "clean" octstr representation,
     * without the dashes in the string. So remove them.
     */
    uuid_unparse(sms->sms.id, id);
    tid = octstr_create(id);
    octstr_replace(tid, octstr_imm("-"), octstr_imm(""));

    /* form the basic URL */
    url = octstr_format("%S?MsIsdn=%E&Originator=%E",
        conndata->send_url, sms->sms.receiver, sms->sms.sender);

    /*
     * We use &binfo=<foobar> from sendsms interface to encode
     * additional paramters. If a mandatory value is not set,
     * a default value is applied
     */
    if (octstr_len(sms->sms.binfo)) {
        octstr_url_decode(sms->sms.binfo);
        octstr_format_append(url, "&%S", sms->sms.binfo);
    }
    /* CustomerId */
    if (octstr_search(url, octstr_create("CustomerId="), 0) == -1) {
        octstr_format_append(url, "&CustomerId=%S", conndata->username);
    }
    /* TransactionId */
    if (octstr_search(url, octstr_create("TransactionId="), 0) == -1) {
        octstr_format_append(url, "&TransactionId=%S", tid);
    }
    /* SMSCount */
    if (octstr_search(url, octstr_create("SMSCount="), 0) == -1) {
        octstr_format_append(url, "&%s", "SMSCount=1");
    }
    /* ActionType */
    if (octstr_search(url, octstr_create("ActionType="), 0) == -1) {
        octstr_format_append(url, "&%s", "ActionType=A");
    }
    /* ServiceDeliveryType */
    if (octstr_search(url, octstr_create("ServiceDeliveryType="), 0) == -1) {
        octstr_format_append(url, "&%s", "ServiceDeliveryType=P");
    }

    /* if coding is not set and UDH exists, assume DC_8BIT
     * else default to DC_7BIT */
    if (sms->sms.coding == DC_UNDEF)
        sms->sms.coding = octstr_len(sms->sms.udhdata) > 0 ? DC_8BIT : DC_7BIT;

    if (sms->sms.coding == DC_8BIT)
        octstr_format_append(url, "&MessageType=B&Text=%H", sms->sms.msgdata);
    else
        octstr_format_append(url, "&MessageType=S&Text=%E", sms->sms.msgdata);

    dcs = fields_to_dcs(sms,
        (sms->sms.alt_dcs != SMS_PARAM_UNDEFINED ? sms->sms.alt_dcs : 0));

    /* XSer processing */
    xser = octstr_create("");
    /* XSer DCS values */
    if (dcs != 0 && dcs != 4)
        octstr_format_append(xser, "0201%02x", dcs & 0xff);
    /* add UDH header */
    if (octstr_len(sms->sms.udhdata)) {
        octstr_format_append(xser, "01%02x%H", octstr_len(sms->sms.udhdata),
                             sms->sms.udhdata);
    }
    if (octstr_len(xser) > 0)
        octstr_format_append(url, "&XSer=%S", xser);
    octstr_destroy(xser);


    headers = http_create_empty_headers();
    debug("smsc.http.brunet", 0, "HTTP[%s]: Sending request <%s>",
          octstr_get_cstr(conn->id), octstr_get_cstr(url));

    /*
     * Brunet requires an SSL-enabled HTTP client call, this is handled
     * transparently by the Kannel HTTP layer module.
     */
    http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers,
                       NULL, 0, sms, NULL);

    octstr_destroy(url);
    octstr_destroy(tid);
    http_destroy_headers(headers);

    return 0;
}
Ejemplo n.º 6
0
static void start_push(Octstr *rcpt_to, int isphonenum, MmsEnvelope *e, MmsMsg *msg)
{
     List *pheaders;
     static unsigned char ct; /* Transaction counter -- do we need it? */
     Octstr *to = NULL;
     
     Octstr *pduhdr = octstr_create("");
     
     Octstr *s = NULL;
     

     info(0, "mms2mobile.startpush: notification to %s\n", octstr_get_cstr(rcpt_to));
     
     if (!rcpt_to) {
	  error(0, "mobilesender: Queue entry %s has no recipient address!", e->xqfname);
	  goto done;
     } else
	  to = octstr_duplicate(rcpt_to);
     

     ct++;    
     octstr_append_char(pduhdr, ct);  /* Pushd id */
     octstr_append_char(pduhdr, 0x06); /* PUSH */

     
#if 1
     octstr_append_char(pduhdr, 1 + 1 + 1);
     octstr_append_char(pduhdr, 0xbe); /* content type. */     
#else
     octstr_append_char(pduhdr, 
			1 + 1 + sizeof "application/vnd.wap.mms-message"); /*header length. */     
     octstr_append_cstr(pduhdr, "application/vnd.wap.mms-message");
     octstr_append_char(pduhdr, 0x0); /* string terminator. */
#endif
     octstr_append_char(pduhdr, 0xaf); /* push application ID header and value follows. */
     octstr_append_char(pduhdr, 0x84); /* ... */

     s = mms_tobinary(msg);

     if (isphonenum) {
	  Octstr *url;
	  
	  octstr_url_encode(to);
	  octstr_url_encode(s);
#if 0
	  octstr_dump(pduhdr, 0);
#endif

	  octstr_url_encode(pduhdr);
	  
	  url = octstr_format("%S&text=%S%S&to=%S&udh=%%06%%05%%04%%0B%%84%%23%%F0",	
			      settings->sendsms_url, pduhdr, s, to);     
	  
	  pheaders = http_create_empty_headers();
	  http_header_add(pheaders, "Connection", "close");
	  http_header_add(pheaders, "User-Agent", MM_NAME "/" MMSC_VERSION);	       
	  
	  http_start_request(httpcaller, HTTP_METHOD_GET, url, 
			     pheaders, NULL, 0, e, NULL);
	  	  
	  http_destroy_headers(pheaders);
	  octstr_destroy(url);
     } else { /* An IP Address: Send packet, forget. */
	  Octstr *addr = udp_create_address(to, WAPPUSH_PORT);
	  int sock = udp_client_socket();
	  
	  if (sock > 0) {
	       MmsEnvelopeTo *xto = gwlist_get(e->to,0);
	       octstr_append(pduhdr, s);
#if 0
	       octstr_dump(pduhdr, 0);
#endif
	       udp_sendto(sock, pduhdr, addr);
	       close(sock); /* ?? */      
	       mms_log2("Notify", octstr_imm("system"), to, 
			-1, e ? e->msgId : NULL, 
			NULL, NULL, "MM1", NULL,NULL);
	       e = update_env_success(e, xto);
	  } else {
	       e = update_env_failed(e);
	       error(0, "push to %s:%d failed: %s", octstr_get_cstr(to), WAPPUSH_PORT, strerror(errno));
	  }
	  octstr_destroy(addr);
	  if (e) 
	       settings->qfs->mms_queue_free_env(e);
     }
 done:
     octstr_destroy(to);
     octstr_destroy(pduhdr);
     octstr_destroy(s);
}
Ejemplo n.º 7
0
static int sendNotify(MmsEnvelope *e)
{
     Octstr *to;
     MmsMsg *msg, *smsg = NULL;
     MmsEnvelopeTo *xto = gwlist_get(e->to, 0);
     Octstr *err = NULL;
     time_t tnow = time(NULL);
     int j, k, len;
     Octstr *phonenum = NULL, *rcpt_ip = NULL, *msgId, *from, *fromproxy;
     int mtype, msize;
     int res = MMS_SEND_OK, dlr;
     time_t expiryt;
     char *prov_notify_event = NULL;
     char *rtype = NULL;

          
     if (e->lastaccess != 0) { /* This message has been fetched at least once, no more signals. */	  
	  e->sendt = e->expiryt + 3600*24*30*12;
	  info(0, "MM1: Message [ID: %s] fetched/touched at least once. Skipping",
	       e->xqfname);
	  return settings->qfs->mms_queue_update(e);
     }

     if (!xto) {
	  error(0, "mobilesender: Queue entry %s with no recipients!", 
		e->xqfname);
	  return 0;
     }

     msg = settings->qfs->mms_queue_getdata(e);
     to = octstr_duplicate(xto->rcpt);
     expiryt = e->expiryt;
     msgId = e->msgId ? octstr_duplicate(e->msgId) : NULL;
     from = octstr_duplicate(e->from);
     fromproxy = e->fromproxy ? octstr_duplicate(e->fromproxy) : NULL;
     msize = e->msize;
     dlr = e->dlr;

     if (e->expiryt != 0 &&  /* Handle message expiry. */
	 e->expiryt < tnow) {
	  err = octstr_format("MMSC error: Message expired while sending to %S!", to);
	  res = MMS_SEND_ERROR_FATAL;
	  prov_notify_event = "failedfetch";
	  rtype = "Expired";	  
	  goto done;
     } else if (e->attempts >= settings->maxsendattempts) {
	  err = octstr_format("MMSC error: Failed to deliver to %S after %ld attempts!", 
			      to, e->attempts);
	  res = MMS_SEND_ERROR_FATAL;

	  prov_notify_event = "failedfetch";
	  rtype = "Expired";	  
	  goto done;
     }
     
     j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0);
     k = octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0);
     len = octstr_len(to);
     
     if (j > 0 && j - 1 +  sizeof "/TYPE=PLMN" == len) { /* A proper number. */
	  phonenum = octstr_copy(to, 0, j);
#if 0
	  normalize_number(octstr_get_cstr(settings->unified_prefix), &phonenum);
#else
	  mms_normalize_phonenum(&phonenum, 
				 octstr_get_cstr(settings->unified_prefix), 
				 settings->strip_prefixes);	  
#endif
     }     else if (k > 0 && k + sizeof "/TYPE=IPv" == len) 
	  rcpt_ip = octstr_copy(to, 0, k);
     else {
	  /* We only handle phone numbers here. */
	  err = octstr_format("Unexpected recipient %s in MT queue!", octstr_get_cstr(to));	  
	  res = MMS_SEND_ERROR_FATAL;	  
	  goto done;
     }
     
     mtype = mms_messagetype(msg);     
     
     /* For phone, getting here means the message can be delivered. So: 
      * - Check whether the recipient is provisioned, if not, wait (script called will queue creation req)
      * - If the recipient can't take MMS, then send SMS.
      */
     
     /* We handle two types of requests: send and delivery/read notifications. 
      * other types of messages cannot possibly be in this queue!
      */
     
     if (mtype == MMS_MSGTYPE_SEND_REQ ||
	 mtype == MMS_MSGTYPE_RETRIEVE_CONF) {
	  Octstr *url, *transid;
	  
	  if (phonenum) {
	       int send_ind = mms_ind_send(settings->prov_getstatus, phonenum);
	       
	       if (send_ind < 0 && 
		   settings->notify_unprovisioned)
		    send_ind = 0;

	       if (send_ind < 0) { /* That is, recipient is not (yet) provisioned. */
		    res = MMS_SEND_ERROR_TRANSIENT;
		    err = octstr_format("%S is not provisioned for MMS reception, delivery deferred!", 
					phonenum);
		    
		    /* Do not increase delivery attempts counter. */
		    e->lasttry = tnow;		    
		    e->sendt = e->lasttry + settings->send_back_off * (1 + e->attempts);
		    
		    if (settings->qfs->mms_queue_update(e) == 1) 
			 e = NULL; /* Queue entry gone. */	
		    else 	  
			 settings->qfs->mms_queue_free_env(e);		    		    
		    goto done;
	       } else if (send_ind == 0) { /*  provisioned but does not support */		    
		    Octstr *s = octstr_format(octstr_get_cstr(settings->mms_notify_txt),
					      from);
		    if (settings->notify_unprovisioned && s && octstr_len(s) > 0) { /* Only send if the string was set. */
			 List *pheaders;					    
			 Octstr *sto = octstr_duplicate(phonenum);
			 
			 octstr_url_encode(s);
			 octstr_url_encode(sto);
			 
			 url = octstr_format("%S&text=%S&to=%S",settings->sendsms_url,s, sto);
			 pheaders = http_create_empty_headers();
			 http_header_add(pheaders, "Connection", "close");
			 http_header_add(pheaders, "User-Agent", MM_NAME "/" VERSION);      
			 
			 http_start_request(httpcaller, HTTP_METHOD_GET, url, 
					    pheaders, NULL, 0, &edummy, NULL);			 			 
			 http_destroy_headers(pheaders);
			 octstr_destroy(url);
			 octstr_destroy(sto);		   		 
		    } else if (s)
			 octstr_destroy(s);	
		    res = MMS_SEND_OK;
		    err = octstr_imm("No MMS Ind support, sent SMS instead");
		    
		    xto->process = 0; /* No more processing. */
		    if (settings->qfs->mms_queue_update(e) == 1) 
			 e = NULL; 
		    else 	  
			 settings->qfs->mms_queue_free_env(e);		    
		    goto done;

	       }	       
	  }
	  
	  /* To get here means we can send Ind. */
	  url = mms_makefetchurl(e->xqfname, e->token, MMS_LOC_MQUEUE,
				 phonenum ? phonenum : to,
				 settings);
	  info(0, "Preparing to notify client to fetch message at URL: %s",
	       octstr_get_cstr(url));
	  transid = mms_maketransid(e->xqfname, settings->host_alias);	  
	  
	  smsg = mms_notification(msg, e->msize, url, transid, 
				  e->expiryt ? e->expiryt :
				  tnow + settings->default_msgexpiry,
				  settings->optimize_notification_size);
	  octstr_destroy(transid);
	  octstr_destroy(url);
     } else if (mtype == MMS_MSGTYPE_DELIVERY_IND ||
		mtype == MMS_MSGTYPE_READ_ORIG_IND) 
	  smsg = msg;
     else {
	  error(0, "Unexpected message type %s for %s found in MT queue!", 
		mms_message_type_to_cstr(mtype), octstr_get_cstr(to));
	  res = MMS_SEND_ERROR_FATAL;
	  goto done;
     }
     
     if (smsg)
	  start_push(phonenum ? phonenum : rcpt_ip, 
		     phonenum ? 1 : 0, 
		     e, smsg); /* Send the message. 
				* Don't touch 'e' after this point!
				* It may be freed by receive thread. 
				*/
     
     if (smsg != msg && smsg)
	  mms_destroy(smsg);
    
 done:
     if (err != NULL && 
	 res != MMS_SEND_ERROR_TRANSIENT) { /* If there was a report request and this is a legit error
					     *  queue it. 
					     */
	  
	  if (dlr) {	       
	       MmsMsg *m = mms_deliveryreport(msgId, to, tnow, 
					      rtype ? octstr_imm(rtype) : 
					      octstr_imm("Indeterminate"));
	       
	       List *l = gwlist_create();
	       Octstr *res;
	       gwlist_append(l, from);
	       
	       /* Add to queue, switch via proxy to be from proxy. */
	       res = settings->qfs->mms_queue_add(to ? to : settings->system_user, l,  err, 
						  NULL, fromproxy,  
						  tnow, tnow+settings->default_msgexpiry, m, NULL, 
						  NULL, NULL,
						  NULL, NULL,
						  NULL,
						  0,
						  octstr_get_cstr(settings->mm1_queuedir), 
						  "MM2",
						  settings->host_alias);
	       gwlist_destroy(l, NULL);
	       mms_destroy(m);
	       octstr_destroy(res);
	  }
	  
     }
     
     /* Write to log */
     info(0, "%s Mobile Queue MMS Send Notify: From=%s, to=%s, msgsize=%d, reason=%s", 
	  SEND_ERROR_STR(res),
	  octstr_get_cstr(from), octstr_get_cstr(to), msize,
	  err ? octstr_get_cstr(err) : "");
     
     
     if (res == MMS_SEND_ERROR_FATAL) {
	  xto->process = 0;  /* No more attempts to deliver, delete this. */	       
	  if (settings->qfs->mms_queue_update(e) == 1) 
	       e = NULL; /* Queue entry gone. */	
	  else 	  
	       settings->qfs->mms_queue_free_env(e);
     }    /* Else queue will be updated/freed elsewhere. */
     
     
     if (prov_notify_event)
	  notify_prov_server(octstr_get_cstr(settings->prov_notify), 
			     to ? octstr_get_cstr(to) : "unknown", 
			     prov_notify_event, 
			     rtype ? rtype : "",
			     e ? e->msgId : NULL, NULL, NULL);

     if (msg) mms_destroy(msg);       

     octstr_destroy(phonenum);
     
     octstr_destroy(rcpt_ip);
     octstr_destroy(to);
     octstr_destroy(msgId);
     octstr_destroy(fromproxy);
     octstr_destroy(from);
     octstr_destroy(err);

     return 1;
}
Ejemplo n.º 8
0
/*
 * Try log in defined number of times, when got response 401 and authentica-
 * tion info is in headers.
 */
static int receive_push_reply(HTTPCaller *caller)
{
    void *id;
    long *trid;
    int http_status,
        tries;
    List *reply_headers;
    Octstr *final_url,
           *auth_url,
           *reply_body,
           *os,
           *push_content,
           *auth_reply_body;
    WAPEvent *e;
    List *retry_headers;
    
    http_status = HTTP_UNAUTHORIZED;
    tries = 0;

    id = http_receive_result(caller, &http_status, &final_url, &reply_headers,
                             &reply_body);

    if (id == NULL || http_status == -1 || final_url == NULL) {
        error(0, "push failed, no reason found");
        goto push_failed;
    }

    while (use_headers && http_status == HTTP_UNAUTHORIZED && tries < retries) {
        debug("test.ppg", 0, "try number %d", tries);
        debug("test.ppg", 0, "authentication failure, get a challenge");
        http_destroy_headers(reply_headers);
        push_content = push_content_create();
        retry_headers = push_headers_create(octstr_len(push_content));
        http_add_basic_auth(retry_headers, username, password);
        trid = gw_malloc(sizeof(long));
        *trid = tries;
        http_start_request(caller, HTTP_METHOD_POST, final_url, retry_headers, 
                           push_content, 0, trid, NULL);
        debug("test.ppg ", 0, "TEST_PPG: doing response to %s", 
              octstr_get_cstr(final_url));

        octstr_destroy(push_content);
        http_destroy_headers(retry_headers);
        
        trid = http_receive_result(caller, &http_status, &auth_url, 
                                   &reply_headers, &auth_reply_body);

        if (trid == NULL || http_status == -1 || auth_url == NULL) {
            error(0, "unable to send authorisation, no reason found");
            goto push_failed;
        }   

        debug("test.ppg", 0, "TEST_PPG: send authentication to %s, retry %ld", 
               octstr_get_cstr(auth_url), *(long *) trid);
        gw_free(trid);
        octstr_destroy(auth_reply_body);
        octstr_destroy(auth_url);
        ++tries;
    }

    if (http_status == HTTP_NOT_FOUND) {
        error(0, "push failed, service not found");
        goto push_failed;
    }

    if (http_status == HTTP_FORBIDDEN) {
        error(0, "push failed, service forbidden");
        goto push_failed;
    }

    if (http_status == HTTP_UNAUTHORIZED) {
        if (use_headers)
            error(0, "tried %ld times, stopping", retries);
        else
	        error(0, "push failed, authorisation failure");
        goto push_failed;
    }
        
    debug("test.ppg", 0, "TEST_PPG: push %ld done: reply from,  %s", 
          *(long *) id, octstr_get_cstr(final_url));
    gw_free(id);
    octstr_destroy(final_url);

    if (verbose)
        debug("test.ppg", 0, "TEST_PPG: reply headers were");

    while ((os = gwlist_extract_first(reply_headers)) != NULL) {
        if (verbose)
            octstr_dump(os, 0); 
        octstr_destroy(os);
    }

    if (verbose) {
        debug("test.ppg", 0, "TEST_PPG: reply body was");
        octstr_dump(reply_body, 0);
    }

    e = NULL;
    if (pap_compile(reply_body, &e) < 0) {
        warning(0, "TEST_PPG: receive_push_reply: cannot compile pap message");
        goto parse_error;
    }

    switch (e->type) {
        case Push_Response:
	        debug("test.ppg", 0, "TEST_PPG: and type push response");
	    break;

        case Bad_Message_Response:
	        debug("test.ppg", 0, "TEST_PPG: and type bad message response");
        break;

        default:
            warning(0, "TEST_PPG: unknown event received from %s", 
                    octstr_get_cstr(final_url));
        break;
    }

    octstr_destroy(reply_body);
    wap_event_destroy(e);
    http_destroy_headers(reply_headers);
    return 0;

push_failed:
    gw_free(id);
    octstr_destroy(final_url);
    octstr_destroy(reply_body);
    http_destroy_headers(reply_headers);
    return -1;

parse_error:
    octstr_destroy(reply_body);
    http_destroy_headers(reply_headers);
    wap_event_destroy(e);
    return -1;
}