/* Created: Wed Nov 10 13:25:17 1993 too
 * Last modified: Mon Nov 15 23:42:39 1993 too
 */

  while (applcbcur != applcbpos) {
    struct Message * msg;
    struct ApplPort * applport;
    
    applport = directIndex(struct ApplPort *, applcbbuf, applcbcur);

    DP("posp %ld, curp %ld, applp %ld\n", applcbpos, applcbcur, applport);

    applcbcur += sizeof (struct ApplPort *);
    applcbcur &= 0x3f * sizeof (struct ApplPort *);
    /*
     * packets have arrived to application msgport
     * (signalled by interrupt)
     */
    if ((msg = GetMsg(&applport->ap_AMP.amp_Msgport)) != NULL) {
      struct DosPacket * packet = msgToPkt(msg);
      
      DP("sd: %ld packet: %lx type: %ld",
	 applport->ap_Sd, packet, packet->dp_Type);
      
      switch (packet->dp_Type) {
      case ACTION_WRITE:
	if (applport->ap_Pw)
	  ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
	else {
	  int sent;
	  int len = packet->dp_Arg3; /*Side Note: no less code generated
				       without len declared */
	  /*
	   * Send message to socket.
	   */
	  if ((sent = send(applport->ap_Sd, (char *)packet->dp_Arg2,
			   len , 0)) == len)
	    ReplyPkt(packet, sent, 0);
	  else {
	    /*
	     * The whole message could not be sent. Keep rest and set
	     * write flag to select.
	     */
	    struct PendingWrites * pw;
	    
	    if ((pw = getBuffer((struct List *)&freewritelist,
				sizeof (struct PendingWrites))) == NULL)
	      ReplyPkt(packet, sent, 0);
	    else {
	      /*
	       */
	      pw->pw_Applport = applport;
	      applport->ap_Pw = pw;
	      FD_SET(applport->ap_Sd, &writefds);
	      writespending++;
	      /*
	       */
	      pw->pw_Start = (char *)packet->dp_Arg2 + sent;
	      pw->pw_Left = len - sent;
	      pw->pw_Len = len;
	      pw->pw_Packet = packet;
	      AddTail((struct List *)&writelist, &pw->pw_Link);
	    }
	  }
	}
	break;
      case ACTION_READ:
	/*
	 * Check that there is no ACTION_READ or ACTION_WAIT_CHAR
	 * packets already received.
	 */
	if (applport->ap_Packet != NULL)
	  ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
	
	else if (applport->ap_Disb == TRUE) {
	  /*
	   * Data already in socket buffer. reply it and enable
	   * notification of arriving data to this socket 
	   * (unless EOF)
	   */
	  int len;
	  len = recv(applport->ap_Sd, (char *)packet->dp_Arg2,
		     packet->dp_Arg3, 0);
	  /*
	   * len == 0? -> EOF. *Don't* reset operation...
	   */
	  if (len > 0) {
	    FD_SET(applport->ap_Sd, &readfds);
	    applport->ap_Disb = FALSE;
	  }
	  ReplyPkt(packet, len, 0);
	}
	else
	  applport->ap_Packet = packet;
	
	break;
      case ACTION_WAIT_CHAR:
	/*
	 * WaitForChar. same check as in ACTION_READ.
	 */
	if (applport->ap_Packet != NULL)
	  ReplyPkt(packet, DOSFALSE, ERROR_OBJECT_IN_USE);
	else if (applport->ap_Disb == TRUE) {
	  /*
	   * Data already in socket buffer... it it not read here.
	   */
	  LONG size;
	  
	  IoctlSocket(applport->ap_Sd, FIONREAD, (char *)&size);
	  ReplyPkt(packet, size, 0);
	}
	else if (packet->dp_Arg1 == 0)
	  /*
	   * No timeout. Reply there is 0 characters available
	   */
	  ReplyPkt(packet, 0, 0);
	else {
	  /*
	   * No data and timeout: send timerequest and leave packet
	   * waiting for data to arrive or timeout expire.
	   */
	  applport->ap_Packet = packet;
	  Send_Timeout(&applport->ap_Tr, packet->dp_Arg1);
	}
	break;
      case ACTION_END:  /* should we do this if packets in ? */
	if (--applport->ap_OpenCnt == 0) {
	  int sd = applport->ap_Sd;

	  if (sd == lastsd)
	    lastmask = 0;	/* lastappl won't exist anymore */

	  nfds--;
	  if (sd < nfds) {
	    Dup2Socket(nfds, sd);
	    applarray[sd] = applarray[nfds];
	    applarray[sd]->ap_Sd = sd;
	    if (FD_ISSET(nfds, &readfds))
	      FD_SET(sd, &readfds);
	    else
	      FD_CLR(sd, &readfds);
	    DP("socket %ld now %ld", nfds, sd);
	  }
	  CloseSocket(nfds);
	  FD_CLR(nfds, &readfds);
	  
	  if (applport->ap_Packet) {
	    if (applport->ap_Packet->dp_Type == ACTION_WAIT_CHAR)
	      Abort_Timeout(&applport->ap_Tr);
	    ReplyPkt(applport->ap_Packet, 0, 0);
	  }
	  
	  if (applport->ap_Pw) {
	    ReplyPkt(applport->ap_Pw->pw_Packet, applport->ap_Pw->pw_Len, 0);
	    writespending--;  /* identical code 2 times */
	    FD_CLR(sd, &writefds);
	    AddTail((struct List *)&freewritelist, &applport->ap_Pw->pw_Link);
	  }
	  AddTail((struct List *)&freeappllist,
		  &applport->ap_AMP.amp_Msgport.mp_Node);
	}
	ReplyPkt(packet, DOSTRUE, 0);
	break;
      case ACTION_FINDINPUT:
      case ACTION_FINDOUTPUT:
      case ACTION_FINDUPDATE:
	{
	  struct FileHandle * fh =
	    (struct FileHandle *)BADDR(packet->dp_Arg1);
	  /*
	   * Same FileHandle information as in open packet.
	   */
	  fh->fh_Arg1 = (LONG)applport >> 2;
	  fh->fh_Port = (struct MsgPort *)DOSTRUE;  /* IsInteractive() */
	  fh->fh_Type = &applport->ap_AMP.amp_Msgport;
	}
	applport->ap_OpenCnt++;
	ReplyPkt(packet, DOSTRUE, packet->dp_Res2);
	break;
      default:
	ReplyPkt(packet, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
	break;
      }
    }
  }
