TweetFollow Us on Twitter

MacSockets
Volume Number:7
Issue Number:12
Column Tag:Com Workshop

Related Info: Device Manager

Library for UNIX-based Clients

By Frank Storbeck, The Netherlands

Introduction.

From the moment that Apple Computer, Inc. came with its UDP-TCP/IP driver for the Macintosh, there was suddenly an increased potential for use of client-server programs as developed in the UNIX-world. Alas, Apple came with its own calls for addressing their UDP-TCP/IP driver (“.IPP”). The calls are essentially the standard low level PBOpen, PBControl and PBClose calls from the DeviceManager. The software includes a file named “TCPPB.h”, in which one finds the definitions for the various DeviceManager calls for the .IPP-driver. However it would be easy if one could use the standard UNIX calls for socket-based communication instead. This gives you the opportunity to port the UNIX software to the Mac. So I started to write a small library with the .IPP equivalents for the client-functions close, connect, recv, recvfrom, recvmsg, send, sendto, sendmsg, shutdown, and socket. To use the Mac as a server, you also need the equivalents of the functions accept, bind, listen and select, but, as I only needed the client-software, I left them out of the project. There are also some other constraints. These will be addressed in the next paragraph. To use the MacTCP software you need a Mac-512E or better and the appropriate LocalTalk- or Ethernet-compatible hardware.

The MacTCP package is available as a single-user developer kit (APDA™ # M0230LL/D). It contains the MacTCP software, a programmers guide and an administrator guide. A licence is required to redistribute the software.

Sockets.

In the manual titled “Network Programming Guide” from SUN®-microsystems (part number 800-3850-10) you can find a good explanation of the in’s and out’s of “Socket-Based Interprocess Communication”. Here only a short summary will follow.

Normally some host sets up a particular service. A client that wants to communicate with this server has to know the address of the host and what is called the port-number of the service. For the standard UNIX-services these port-numbers are “well known” (here I quoted from the manual pages), but if you want to start to offer a new service there is a range of numbers from which you can choose. In the example given here for the use of the code I choose the value 31768 (in a UNIX-system these values for the port-numbers can be found in the file /etc/services).

A socket-pair is a “two way communication channel between two processes”. Each of these processes has a socket that can be used both for sending and receiving of data to and from the other process. The processes may reside on the same or different hosts, but they have to use the same address domains, the same communication method and the same protocol. As I had to use the software for a special project for communication on board of a research vessel, I allowed some more constraints to the software: only internet addressing mode (AF_INET), stream-sockets (SOCK_STREAM) and of course the TCP-IP protocol are supported.

Normally a server-program runs on a host for as long as possible (i.e. between start-up and shut-down). It then waits for the action of some client-program. The client tries to connect to the server, sends a message that it wants some service and then waits for the answer from the server. This can go on for as long as the service is needed. Then the connection is closed down and the server waits for the next client to be served. It is also possible that a server works for more than one client simultaneously. In this case it has a socket for each of the various clients to be served.

The client and server programs

This scheme shows up in the sample code for client.c and server.c that can be found in the listing. They are examples of how to use the calls to the functions for the socket-based communication. After the server has been activated, the client can be started, and it sends the following message to the server:

From: client

To: server

Mssg: Hello server!

Then the server replies with another message:

From: server

To: client

Mssg: Hello client!\n

The server has to be run on some SUN workstation (because of the call bcopy, replace it eventually with the ANSI-C call memcpy, but beware, the order of the parameters is different; also there is a function bzero to clear the memory locations over some range - if not present, deactivate it: the locations will be overwritten by the message anyhow!) The client has been compiled with THINK-C (4.0) compiler. The THINK-C project must also contain the ANSI, MacTraps and UNIX libraries.

The client-program can also be run on a SUN workstation. Just activate the SUN_C macro.

Of course you can change client and server as you like. You can maintain the connection until the client sends some bye-bye message, messages can be sent in chunks etc. etc. Do as you like.

Diagram 1: Sequence for communication between some server and one or more clients.

Some notes on the library

MacTCP provides the use of an asynchronous notification routine. This means that when some exception occurs, a user specified function can be activated. This is here implemented by the function SockNotify, which is hidden to the user. It calls the function DoAlert that draws an alert box on the screen displaying the appropriate massage for some time. The default showing time is 4 seconds, but can be changed with the function SetDialogShowTime. When the time is zero or negative, no DialogBox will be shown. The function DoAlert is also used by the function perror. In this case a stopIcon and an OK-button are added. The DialogBox shows the error message until the user clicks on the OK-button. As the function cannot be sure that a resource for the DialogBox and its DialogItemList is available, it is built up in memory. Note that to use it, you must initialize the DialogManager etc., otherwise your Mac behaves like the mother of all field-battles. All this can be switched off by deactivating the MAC_APPL macro. In this case the messages will be shown on stderr, using the console-library from THINK-C.

There are some extra routines added: close_MacSocket, exit_MacSocket, perror_MacSocket, and strerror_MacSocket,. They are used to prevent direct calls to their UNIX and ANSI-C equivalents close, exit, perror and strerror. In the file MacSocket.h there are macros that make sure that these calls will be diverted to their equivalents in the MacSocket library. e.g., if you call close, close_MacSocket first tries to close a socket-based connection. If the socket doesn’t exist, it calls the standard function close. This is a particular noteworthy example: you might have a file descriptor with number 5 and a socket with number 5. The only way to close the file with file-descriptor 5 while keeping the socket with number 5 in good shape is calling close directly:

/* 1 */

#undef close /* to dactivate a call to close_MacSocket */
close(5);
#define close close_MacSocket /* to reactivate it */

The program includes some files that are not provided here: “types.h”, “socket.h, “in.h”, “netdb.h” and “TCPPB.h”. The first four come from the SUNOS 4.1 operating system and are copyrighted by the Regents of the University of California I am not sure if I can redistribute them, so they are not included. But if you want to port software from a UNIX-platform to the Mac, you must have access to them anyhow. The file “TCPPB.h” is copyrighted by Apple Computer, Inc.

Last note: the program was written using SUNOS 4.0. Now we are using version 4.1. There they don’t speak about “address families” but about “address protocols”. Hence the macro AF_INET has been renamed to AP_INET, but AF_INET still works.

Listings server.c:
/***
 ***
 *** To send data between stream sockets (having communication 
 *** style SOCK_STREAM)
 *** Code based on an example taken from SUN® Network Program
 *** ming Guide,chapter 10, A Socket-Based Interprocess 
 *** Communications Tutorial,Revision A, of 27 March 1990, 
 *** Fig. 10-11, pp. 270-271.
 ***/
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/time.h>
#include<netinet/in.h>
#include<netdb.h>
#include<stdio.h>
#define TRUE(1)
#define DATA“\nFrom: server\nTo:   client\nMssg: Hello client!\n”
#define Port(31768)

main()
{
 int    sock, length;
 struct sockaddr_in server;
 int    msgsock;
 char buf[1024];
 fd_set ready;
 struct timeval  to;

 /* Create socket. */
 sock = socket(AF_INET, SOCK_STREAM, 0);
 if (sock < 0)
 {
 perror(“Server--> opening stream socket”);
 exit(1);
 }
 /* Name socket using wildcards. */
 server.sin_family = AF_INET;
 server.sin_addr.s_addr = INADDR_ANY;
 server.sin_port = Port;
 if (bind(sock, (struct sockadd *)&server, sizeof server) < 0)
 {
 perror(“Server--> getting socket name”);
 exit(1);
 }
 printf(“Server--> Socket port #%d\n”, ntohs(server.sin_port));

 /* Start accepting connections. */
 listen(sock, 5);
 do
 {
 FD_ZERO(&ready);
 FD_SET(sock, &ready);
 to.tv_sec = 5;
 if (select(sock + 1, &ready, (fd_set *)0, (fd_set *)0, &to) < 0)
 {
 perror(“Server--> select”);
 continue;
 }
 if (FD_ISSET(sock, &ready))
 {
 msgsock = accept(sock, (struct sockaddr *) 0, (int *) 0);
 if (msgsock == -1)
 {
 perror(“Server--> accept”);
 }
 else
 {
 bzero(buf, sizeof buf);
 if ((length = recv(msgsock, buf, 1024, 0)) < 0)
 {
 perror(“Server--> reading stream message”);
 }
 else
 {
 buf[length] = ‘\0’;
 printf(“Server-->%s\n”, buf);
 }
 if (send(msgsock, DATA, sizeof DATA, 0) < 0)
 {
 perror(“Server--> sending steam message”);
 }
 }
 close(msgsock);
 }
 else
 {
 /* Do something else. */
 }
 } while (TRUE);
 exit(0);
}
Listing:  socket.h
/***
 *** Copyright (c) 1990 Rijksinstituut voor Visserijonderzoek.
 *** All rights reserved.
 ***
 *** Redistribution and use in source and binary forms are 
 *** permitted provided that this notice is preserved and that 
 *** due credit is given to the Rijksinstituut voor Visserijonderzoek 
at IJmuiden.
 *** This software is provided “as is” without express or implied warranty.
 ***
 *** @(#)MacSocket.h 1.2 91/01/25
 ***/

#ifndef _MacSocket_H_
#define _MacSocket_H_

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unix.h>
#include<DeviceMgr.h>

#include“types.h”
#include“socket.h”
#include“in.h”
#include“netdb.h”
#include“TCPPB.h”

#ifdef  LAB_VIEW

/* to prevent the use of the malloc() call in a LabVIEW CIN */
#define SockElmnttheSockElmnt
#define SizeOf(x)x
#define malloc(x)&x

#else

#define SizeOf sizeof

#endif  LAB_VIEW

#ifndef NIL
#define NIL ((void*) 0L)
#endif  NIL
#ifndef InFrontOfAll
#define InFrontOfAll ((Ptr) -1L)
#endif  InFrontOfAll
#ifndef True
#define True(1)
#endif  True
#ifndef False
#define False    (0)
#endif  False
#define Abort    True
#define ReportIt False
#define Asynchronous True
#define SynchronousFalse
#define ConnectTimeout  (15)
#define SendTimeout(15)
#define RecvTimeout(15)
#define CloseTimeout (15)
#define SockBufSize(16384)
#define UserDataSize (128)

#define noTCPDriver(-1)
#define invalidArgument (2)
#define nonSOCK_STREAM  (13)
#define nonSocket(38)
#define nonAF_INET (43)
#define noBufSpace (55)
#define commandInProgress (1)

/* to force the application first to use the MacSocket versions */
#define perror   perror_MacSocket
#define exitexit_MacSocket
#define close    close_MacSocket
#define strerror strerror_MacSocket

/* Prototypes */
intaccept(int s, struct sockaddr *addr, int addrlen);
intbind(int s, struct sockaddr *name, int namelen);
intclose_MacSocket(int s);
intconnect(int s, struct sockaddr_in *name, int namelen);
void  exit_MacSocket(int status);
intlisten(int s, int backlog);
void  perror_MacSocket(char *s);
intrecv(int s, char *msg, int len, int flags);
intrecvfrom(int s, char *msg, int len, int flags, struct sockaddr_in 
*from,
 int *fromlen);
intrecvmsg(int s, struct msghdr *msg, int flags);
intsend(int s, char *msg, int len, int flags);
intsendto(int s, char *msg, int len, int flags, struct sockaddr_in *to,
 int tolen);
intsendmsg(int s, struct msghdr *msg, int flags);
intshutdown(int s, int how);
#ifdef  MAC_APPL
void  SetDialogShowTime(int sec);
#endif  MAC_APPL
intsocket(int domain, int type, int protocol);
char* strerror_MacSocket(int errnum);

#endif _MacSocket_H_
Listing:  client.c
/***
 ***
 *** To send data between stream sockets (having communication style
 *** SOCK_STREAM)
 *** Code based on an example taken from SUN® Network Programming Guide,
 *** chapter 10, A Socket-Based Interprocess Communications Tutorial,
 *** Revision A, of 27 March 1990, Fig. 10-9, pp. 266-267.
 ***
 ***/

#ifdef  SUN_C
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<stdio.h>
#else SUN_C
/*
#define MAC_APPL
*/
#include<console.h>
#include“MacSocket.h”
#define bcopy(s1, s2, n)  memcpy((s2), (s1), (n))
#endif  SUN_C

#define Port(31768)
#define DATA“\nFrom: client\nTo:   server\nMssg: Hello server!\n”

main()
{
 int    sock, mssgSize;
 struct sockaddr_in server;
 union
 {
 long   address;
 unsigned char domain[4];
 } host;
 char buf[1024];
 
#ifdef  MAC_APPL
 /* prevent showing informative MacTCP/IP messages */
 SetDialogShowTime(0);
#endif  MAC_APPL
 
 /* Create socket. */
 sock = socket(AF_INET, SOCK_STREAM, 0);
 if (sock < 0)
 {
 perror(“opening stream socket”);
 exit(1);
 }
 /* Connect socket using address 192.6.1.30 and port# */
 server.sin_family = AF_INET;
 host.domain[0] = 192;
 host.domain[1] = 6;
 host.domain[2] = 1;
 host.domain[3] = 30;
 bcopy((char*)&host.address, (char*)&server.sin_addr, 4);
 server.sin_port = Port;

 if (connect(sock, (struct sockaddr_in *)&server, sizeof server) < 0)
 {
 perror(“connecting stream socket”);
 exit(1);
 }
 if (send(sock, DATA, sizeof DATA, 0) < 0)
 {
 perror(“writing on stream socket”);
 exit(1);
 }
 if ((mssgSize = recv(sock, buf, sizeof buf, 0)) < 0)
 {
 perror(“reading on stream socket”);
 exit(1);
 }
 buf[mssgSize] = ‘\0’;
 printf(“Client--> %s\n”, buf);
 close(sock);
 exit(0);
}
Listing:  MacSocket.c
/***
 *** Copyright (c) 1990 Rijksinstituut voor Visserijonderzoek, IJmuiden.
 *** All rights reserved.
 ***
 *** Redistribution and use in source and binary forms are permitted
 *** provided that this notice is preserved and that due credit is given
 *** to the Rijksinstituut voor Visserijonderzoek at IJmuiden.
 *** This software is provided “as is” without express or implied warranty.
 ***
 *** @(#)MacSocket.c 1.7 91/04/04
 ***/

/*
#define MAC_APPL
*/
#include“MacSocket.h”

#define Connected(0x01)

typedef struct SockElmnt
{
 int    number;
 struct SockElmnt*next;
 TCPiopbthePB;
 char   sockBuf[SockBufSize];
} SockElmnt, *SockElmntPtr, **SockElmntHdl;

#ifdef  MAC_APPL

#define LineLength (350)
#define AMargin  (13)
#define BMargin  (23)
#define IconSize (32)
#define DlogTop  (66)
#define DlogLeft (50)
#define ButtonHeight (22)
#define ButtonLength (59)

typedef struct AlertDitl
{
 unsigned short  nItems;
 Handle textHandle;
 Rect   textRect;
 unsigned char text;
 unsigned char textSize;
 char   textString[8];
 Handle buttonHandle;
 Rect   buttonRect;
 unsigned char button;
 unsigned char buttonSize;
 char   buttonString[2];
 Handle iconHandle;
 Rect   iconRect;
 unsigned char icon;
 unsigned char iconSize;
 unsigned short  iconId;
 Handle outlineHandle;
 Rect   outlineRect;
 unsigned char outline;
 unsigned char outlineSize;
} AlertDitl, *AlertDitlPtr, **AlertDitlHdl;

#endif  MAC_APPL

#ifdef  close
#undef  close
#endif  close

#ifdef  exit
#undef  exit
#ifdef  MAC_APPL
#define exit(s)  ExitToShell()
#endif  MAC_APPL
#endif  exit

#ifdef  perror
#undef  perror
#endif  perror

#ifdef  strerror
#undef  strerror
#endif  strerror

/**
 **
 ** local prototypes
 **
 **/
static  voidDoAlert(int alertId, char* s1, char* s2, char* s3, char* 
s4);
static  SockElmntPtr CreateSocketStruct(void);
static  SockElmntPtr FindSocketStruct(int);
static  int OpenTCPDriver(void);
static  pascal voidOutlineProc(DialogPtr thePtr, int theItem);
static  voidPollTCPDriver(TCPiopb *thePB);
static  int RemoveSocketStruct(int);
static  pascal voidSockNotify(StreamPtr tcpStream,
 unsigned short eventCode,
 Ptr userDataPtr,
 unsigned short terminReason,
 struct ICMPReport *icmpMsg);

/**
 **
 ** local variables
 **
 **/
static  int errno_MacSocket = noErr;
static  int ioRefNumTCP;
static  charmacSocketErrorMssg[128] = “no error!”;
static  int showTime = 4;
static  int sockNumber = 4;
static  SockElmntPtr theHeadPtr = NIL;
static  charTCPDriverName[] = “\p.IPP”;
static  chartheUserData[UserDataSize];
static  charTCPDriverNotOpened = True;

#ifdef  LAB_VIEW

static  SockElmnttheSockElmnt;

#endif  LAB_VIEW

/***
 ***
 *** Mac versions the standard Socket-based internet communication protocol:
 ***
 ***/

/**
 **
 ** Local functions
 **
 **/

/*
 *
 * CreateSocketStruct - creates a data structure for a particular socket 
into a
 * linked list
 *
 */
static  SockElmntPtr CreateSocketStruct()
{
 register SockElmntPtr  theSockPtr;
 
 if ((theSockPtr = (SockElmntPtr)malloc(SizeOf(SockElmnt))) == NIL)
 {
 errno_MacSocket = noBufSpace;
 return (NIL);
 }
 theSockPtr->next = theHeadPtr;
 theHeadPtr = theSockPtr;
 theSockPtr->number = ++sockNumber;
 return (theSockPtr);
}

#ifdef  MAC_APPL
/*
 *
 * DoAlert - shows an alert message on the screen. When alertId is negative,
 * no icon and OK-button are displayed. The Alert message is then “showTime”
 * seconds visible.
 *
 */
static void DoAlert(int alertId, char* s1, char* s2, char* s3, char* 
s4)
{
 AlertDitlPtr  theAlertDitlPtr;
 AlertDitlHdl  theAlertDitlHdl;
 DialogRecord  dlogRecord;
 DialogPtrtheDlogPtr;
 Rect   theBounds;
 int    theItem;
 int    textHeight;
 int    nChars;
 FontInfo theFont;
 
 if ((alertId < 0) && (showTime <= 0))
 {
 return;
 }
 
 theAlertDitlHdl = (AlertDitlHdl)NewHandle(sizeof(AlertDitl));
 if (theAlertDitlHdl != NIL)
 {
 HLock(theAlertDitlHdl);
 theAlertDitlPtr = * theAlertDitlHdl;
 
 nChars = (int)((unsigned char)*s1) +
 (int)((unsigned char)*s2) +
 (int)((unsigned char)*s3) +
 (int)((unsigned char)*s4);
 
 GetFontInfo(&theFont);
 textHeight = ((nChars * theFont.widMax) / LineLength + 1) *
 (theFont.ascent + theFont.descent + theFont.leading);
 if ((textHeight < IconSize) && (alertId >= 0))
 {
 textHeight = IconSize;
 }
 
 theAlertDitlPtr->nItems = (alertId >= 0) ? 3 : 0;
 
 theAlertDitlPtr->textHandle = ((void*) 0L);
 theAlertDitlPtr->textRect.top = AMargin - 3;
 theAlertDitlPtr->textRect.left = BMargin - 3;
 if (alertId >= 0)
 {
 theAlertDitlPtr->textRect.left += IconSize + BMargin;
 }
 theAlertDitlPtr->textRect.bottom =
 theAlertDitlPtr->textRect.top + textHeight;
 theAlertDitlPtr->textRect.right =
 theAlertDitlPtr->textRect.left + LineLength;
 theAlertDitlPtr->text = statText + itemDisable;
 theAlertDitlPtr->textSize = 8;
 theAlertDitlPtr->textString[0] = ‘^’;
 theAlertDitlPtr->textString[1] = ‘0’;
 theAlertDitlPtr->textString[2] = ‘^’;
 theAlertDitlPtr->textString[3] = ‘1’;
 theAlertDitlPtr->textString[4] = ‘^’;
 theAlertDitlPtr->textString[5] = ‘2’;
 theAlertDitlPtr->textString[6] = ‘^’;
 theAlertDitlPtr->textString[7] = ‘3’;
 
 if (alertId >= 0)
 {
 theAlertDitlPtr->buttonHandle = ((void*) 0L);
 theAlertDitlPtr->buttonRect.top =
 theAlertDitlPtr->textRect.bottom + AMargin;
 theAlertDitlPtr->buttonRect.right =
 theAlertDitlPtr->textRect.right;
 theAlertDitlPtr->buttonRect.bottom =
 theAlertDitlPtr->buttonRect.top + ButtonHeight;
 theAlertDitlPtr->buttonRect.left =
 theAlertDitlPtr->buttonRect.right - ButtonLength;
 theAlertDitlPtr->button = ctrlItem + btnCtrl;
 theAlertDitlPtr->buttonSize = 2;
 theAlertDitlPtr->buttonString[0] = ‘O’;
 theAlertDitlPtr->buttonString[1] = ‘K’;
 
 theAlertDitlPtr->iconHandle = ((void*) 0L);
 theAlertDitlPtr->iconRect.top = theAlertDitlPtr->textRect.top;
 theAlertDitlPtr->iconRect.left = BMargin - 3;
 theAlertDitlPtr->iconRect.bottom =
 theAlertDitlPtr->iconRect.top + IconSize;
 theAlertDitlPtr->iconRect.right =
 theAlertDitlPtr->iconRect.left + IconSize;
 theAlertDitlPtr->icon = iconItem + itemDisable;
 theAlertDitlPtr->iconSize = 2;
 theAlertDitlPtr->iconId = alertId;
 
 theAlertDitlPtr->outlineHandle = (Handle)&OutlineProc;
 theAlertDitlPtr->outlineRect.top = theAlertDitlPtr->buttonRect.top;
 theAlertDitlPtr->outlineRect.left = theAlertDitlPtr->buttonRect.left;
 theAlertDitlPtr->outlineRect.bottom =
 theAlertDitlPtr->buttonRect.bottom;
 theAlertDitlPtr->outlineRect.right = theAlertDitlPtr->buttonRect.right;
 theAlertDitlPtr->outline = userItem + itemDisable;
 theAlertDitlPtr->outlineSize = 0;
 }
 
 theBounds.top = DlogTop;
 theBounds.left = DlogLeft;
 theBounds.bottom = DlogTop + AMargin - 3;
 theBounds.bottom += (alertId >= 0) ?
 theAlertDitlPtr->buttonRect.bottom :
 theAlertDitlPtr->textRect.bottom;
 theBounds.right = DlogLeft + theAlertDitlPtr->textRect.right + AMargin 
- 3;
 
 HUnlock(theAlertDitlHdl);
 
 ParamText(s1, s2, s3, s4);
 theDlogPtr = NewDialog(&dlogRecord, &theBounds, “\p”, True, dBoxProc,
 InFrontOfAll, False, 0L, theAlertDitlHdl);
 if (alertId >= 0)
 {
 ModalDialog(NIL, &theItem);
 }
 else
 {
 DrawDialog(theDlogPtr);
 sleep(showTime);
 }
 CloseDialog(theDlogPtr);
 DisposHandle(theAlertDitlHdl);
 }
};
#endif MAC_APPL

/*
 *
 * FindSocketStruct - finds a data structure for a particular socket 
in a linked list
 *
 */
static SockElmntPtrFindSocketStruct(int sock)
{
 register SockElmntPtr  theSockPtr;

 for (theSockPtr = theHeadPtr; theSockPtr != NIL;
   theSockPtr = (SockElmntPtr)theSockPtr->next)
 {
 if (theSockPtr->number == sock)
 {
 errno_MacSocket = noErr;
 return (theSockPtr);
 }
 }
 errno_MacSocket = nonSocket;
 return (NIL);
}

/*
 *
 * OpenTCPDriver - loads and opens UDP-TCP/IP driver (“.IPP”)
 *
 */
static  int OpenTCPDriver()
{
 ParamBlockRec thePB;
 
 thePB.ioParam.ioCompletion = NIL;
 thePB.ioParam.ioNamePtr = (StringPtr)TCPDriverName;
 thePB.ioParam.ioPermssn = fsCurPerm;
 PBOpen(&thePB, Asynchronous);
 PollTCPDriver((TCPiopb *)&thePB);
 if (errno_MacSocket == noErr)
 {
 TCPDriverNotOpened = False;
 ioRefNumTCP = thePB.ioParam.ioRefNum;
 return(1);
 }
 else
 {
 errno_MacSocket = noTCPDriver;
 return(0);
 }
}

#ifdef MAC_APPL
/*
 *
 * OutlineProc - Outlines an item in a dialogbox
 *
 */
static pascal void OutlineProc(WindowPtr thePtr, int theItem)
{
 int    theItemType;
 GrafPtrcurrentPort;
 Handle theItemHdl;
 Rect theBox;

 GetDItem (thePtr, theItem, &theItemType, &theItemHdl, &theBox);
 GetPort(&currentPort);
 SetPort(thePtr);
 PenSize(3, 3);
 InsetRect(&theBox, -4, -4);
 FrameRoundRect (&theBox, 16, 16);
 PenNormal();
 SetPort(currentPort);
};
#endif  MAC_APPL

/*
 *
 * PollTCPDriver - polls the UDP-TCP/IP driver until an action is completed
 *
 */
static  voidPollTCPDriver(TCPiopb *theTCPPtr)
{
 while((errno_MacSocket = theTCPPtr->ioResult) > 0)
 {
 SystemTask();
 }
}

/*
 *
 * RemoveSocketStruct - removes a data structure for a particular socket 
from a
 * linked list
 *
 */
static intRemoveSocketStruct(int sock)
{
 register SockElmntPtr  theSockPtr, thePrevOne = NIL;

 for (theSockPtr = theHeadPtr; theSockPtr != NIL;
   thePrevOne = theSockPtr, theSockPtr = (SockElmntPtr)theSockPtr->next)
 {
 if (theSockPtr->number == sock)
 {
 if (thePrevOne == NIL)
 {
 theHeadPtr = theSockPtr->next;
 }
 else
 {
 thePrevOne->next = theSockPtr->next;
 }
 free(theSockPtr);
 errno_MacSocket = noErr;
 return (1);
 }
 }
 errno_MacSocket = nonSocket;
 return(0);
}

/*
 *
 * SockNotify - prints notification messages for the UDP-TCP/IP driver
 *
 */
static pascal void SockNotify(StreamPtr tcpStream, unsigned short eventCode,
  Ptr userDataPtr, unsigned short terminReason, struct ICMPReport *icmpMsg)
{
 char theErrorMsg[128];
 char *errStrPtr1 = “\0”, *errStrPtr2 = “\0”;
#ifdef  MAC_APPL
 char errNoStr[32];
#endif  MAC_APPL
 
 strcpy(theErrorMsg, “MacSocket: “);
 switch (eventCode)
 {
 case TCPClosing:
 errStrPtr1 = “all data has been received and delivered”;
 break;
 case TCPULPTimeout:
 errStrPtr1 = “time out”;
 break;
 case TCPTerminate:
 errStrPtr1 = “connection terminated, “;
 switch(terminReason)
 {
 case TCPRemoteAbort:
 errStrPtr2 = “connection reset by peer”;
 break;
 case TCPNetworkFailure:
 errStrPtr2 = “network failure”;
 break;
 case TCPSecPrecMismatch:
 errStrPtr2 = “invallid security option or precedence level”;
 break;
 case TCPULPTimeoutTerminate:
 errStrPtr2 = “ULP time out”;
 break;
 case TCPULPAbort:
 errStrPtr2 = “connection aborted”;
 break;
 case TCPULPClose:
 errStrPtr2 = “connection closed gracefully”;
 break;
 case TCPServiceError:
 errStrPtr2 = “unexpected connection initiation segment read”;
 break;
 default:
 errStrPtr2 = “unknown reason”;
 break;
 }
 break;
 case TCPDataArrival:
 errStrPtr1 = “data arrived, no receive outstanding”;
 break;
 case TCPUrgent:
 errStrPtr1 = “urgent data arrived”;
 break;
 case TCPICMPReceived:
 errStrPtr1 = “Internet Control Message arrived”;
 /* still to be printed */
 break;
 default:
 errStrPtr1 = “unknown eventcode”;
 break;
 }
 strcat(theErrorMsg, errStrPtr1);
 strcat(theErrorMsg, errStrPtr2);
#ifndef MAC_APPL
 fprintf(stderr, “%s (%d).\n”, theErrorMsg, eventCode);
#else MAC_APPL
 NumToString(eventCode, errNoStr);
 DoAlert(-1, CtoPstr(theErrorMsg), “\p(“, errNoStr, “\p)”);
#endif  MAC_APPL
};

/**
 **
 ** Global functions
 **
 **/

/**
 **
 ** Functions that substitute relevant UNIX-system calls on the Mac
 **
 **/

/*
 *
 * close_MacSocket - delete a (socket) descriptor if present, else do 
close(int s)
 *
 */
int close_MacSocket(int s)
{
 TCPiopb*theTCPPtr;
 SockElmntPtr  theSockPtr, thePrevPtr = NIL;

 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 return(close(s));
 }
 
 theTCPPtr = &(theSockPtr->thePB);
 theTCPPtr->csCode = TCPClose;
 theTCPPtr->csParam.close.ulpTimeoutValue = CloseTimeout;
 theTCPPtr->csParam.close.ulpTimeoutAction = Abort;
 theTCPPtr->csParam.close.validityFlags = (byte)(timeoutValue | timeoutAction);
 theTCPPtr->csParam.close.userDataPtr = (Ptr)&theUserData;
 PBControl((ParmBlkPtr)theTCPPtr, Asynchronous);
 PollTCPDriver(theTCPPtr);
 theSockPtr->number = -1;
 if (errno_MacSocket == noErr)
 {
 return(0);
 }
 else
 {
 return (-1);
 }
};

/*
 *
 * exit_MacSocket - substitute for exit(int status)
 *
 */
void exit_MacSocket(int status)
{
 ParamBlockRec thePB;

 while (theHeadPtr != NIL)
 {
 shutdown(theHeadPtr->number, 2);
 }
 
 if (!TCPDriverNotOpened)
 {
 thePB.ioParam.ioCompletion = NIL;
 thePB.ioParam.ioRefNum = ioRefNumTCP;
 PBClose(&thePB, Asynchronous);
 /*
 PollTCPDriver(&thePB);
 */
 }
 exit(status);
}

/*
 *
 * perror_MacSocket - substitute for void perror(char *s)
 *
 */
void perror_MacSocket(char *s)
{
 char theErrorMsg[128];
#ifdef  MAC_APPL
 char errNoStr[32];
#endif  MAC_APPL
 
 strcpy(theErrorMsg, s);
 strcat(theErrorMsg, “: “);
 strcat(theErrorMsg, strerror_MacSocket(errno_MacSocket));
#ifndef MAC_APPL
 fprintf(stderr, “%s (%d).\n”, theErrorMsg, errno_MacSocket);
#else MAC_APPL
 NumToString(errno_MacSocket, errNoStr);
 DoAlert(stopIcon, CtoPstr(theErrorMsg), “\p (“, errNoStr, “\p).”);
#endif  MAC_APPL
}

/*
 *
 * strerror_MacSocket - substitute for strerror(int errnum)
 *
 */
char* strerror_MacSocket(int errnum)
{
 char *errStrPtr;
 
 switch (errnum)
 {
 case noTCPDriver:
 errStrPtr = “UDP-TCP/IP driver (\”.IPP\”) not available”;
 break;
 case invalidArgument:
 errStrPtr = “invalid address argument”;
 break;
 case nonSOCK_STREAM:
 errStrPtr = “socket type not supported”;
 break;
 case nonSocket:
 errStrPtr = “invalid socket descriptor”;
 break;
 case nonAF_INET:
 errStrPtr = “domain not supported”;
 break;
 case noBufSpace:
 errStrPtr = “no memory for buffers available”;
 break;
 case ipBadLapErr:
 errStrPtr = “bad network configuration”;
 break;
 case ipBadCnfgErr:
 errStrPtr = “bad IP configuration error”;
 break;
 case ipNoCnfgErr:
 errStrPtr = “missing IP or LAP configuration error”;
 break;
 case ipLoadErr:
 errStrPtr = “error in MacTCP load”;
 break;
 case ipBadAddr:
 errStrPtr = “error in getting address”;
 break;
 case streamAlreadyOpen:
 errStrPtr = “an open stream is already using this receive buffer area”;
 break;
 case invalidLength:
 errStrPtr = “the buffer is too small or too large”;
 break;
 case invalidBufPtr:
 errStrPtr = “illegal buffer pointer”;
 break;
 case insufficientResources:
 errStrPtr = “there are already 64 TCP streams open”;
 break;
 case invalidStreamPtr:
 errStrPtr = “the specified TCP stream is not open”;
 break;
 case connectionExists:
 errStrPtr = “this TCP stream has an open connection”;
 break;
 case duplicateSocket:
 errStrPtr = “a connection already exists on this link”;
 break;
 case commandTimeout:
 errStrPtr =
 “no connection attempt was received in the specified time-out period”;
 break;
 case openFailed:
 errStrPtr = “the connection came halfway up and then failed”;
 break;
 case connectionDoesntExist:
 errStrPtr = “there is no open connection on this stream”;
 break;
 case connectionClosing:
 errStrPtr = “a TCP close command was already issued”;
 break;
 case connectionTerminated:
 errStrPtr = “the connection went down”;
 break;
 case invalidRDS:
 errStrPtr = “trying to release wrong buffer”;
 break;
 default:
 errStrPtr = strerror(errnum);;
 break;
 }
 strcpy(macSocketErrorMssg, errStrPtr);
 return(macSocketErrorMssg);
}

/**
 **
 ** MacSocket calls
 **
 **/

/*
 *
 * connect - initiate a connection on a socket
 *
 */
int connect(int s, struct sockaddr_in *name, int namelen)
{
 TCPiopb*theTCPPtr;
 SockElmntPtr  theSockPtr;
 
 if (namelen != sizeof(struct sockaddr_in))
 {
 errno_MacSocket = invalidArgument;
 return (-1);
 }

 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 return (-1);
 }
 
 theTCPPtr = &(theSockPtr->thePB);
 theTCPPtr->csCode = TCPActiveOpen;
 theTCPPtr->csParam.open.ulpTimeoutValue = ConnectTimeout;
 theTCPPtr->csParam.open.ulpTimeoutAction = Abort;
 theTCPPtr->csParam.open.validityFlags =
 (byte)(timeoutValue | timeoutAction | typeOfService | precedence);
 memcpy((void *)&theTCPPtr->csParam.open.remoteHost, (void *)&name->sin_addr,
 sizeof(name->sin_addr));
 theTCPPtr->csParam.open.remotePort = name->sin_port;
 theTCPPtr->csParam.open.localPort = 0;
 theTCPPtr->csParam.open.tosFlags = (byte)(reliability | lowDelay);
 theTCPPtr->csParam.open.precedence = 0;
 theTCPPtr->csParam.open.dontFrag = False;
 theTCPPtr->csParam.open.timeToLive = (byte)60;
 theTCPPtr->csParam.open.security = False;
 theTCPPtr->csParam.open.optionCnt = (byte)0;
 theTCPPtr->csParam.open.userDataPtr = (Ptr)&theUserData;
 PBControl((ParmBlkPtr)theTCPPtr, Asynchronous);
 PollTCPDriver(theTCPPtr);
 if (errno_MacSocket == noErr)
 {
 return (0);
 }
 else
 {
 return (-1);
 }
};

/*
 *
 * recv - receive a message from a socket
 *
 */
int recv(int s, char *msg, int len, int flags)
{
 TCPiopb*theTCPPtr;
 SockElmntPtr  theSockPtr;
 
 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 return (-1);
 }
 
 theTCPPtr = &(theSockPtr->thePB);
 theTCPPtr->csCode = TCPRcv;
 theTCPPtr->csParam.receive.commandTimeoutValue = RecvTimeout;
 theTCPPtr->csParam.receive.rcvBuff = msg;
 theTCPPtr->csParam.receive.rcvBuffLen = len;
 theTCPPtr->csParam.receive.userDataPtr = (Ptr)&theUserData;
 PBControl((ParmBlkPtr)theTCPPtr, Asynchronous);
 PollTCPDriver(theTCPPtr);
 if (errno_MacSocket == noErr)
 {
 return (theTCPPtr->csParam.receive.rcvBuffLen);
 }
 else
 {
 return (-1);
 }
};

/*
 *
 * recvfrom - receive a message from a socket
 *
 */
int recvfrom(int s, char *msg, int len, int flags, struct sockaddr_in 
*from, int *fromlen)
{
 SockElmntPtr  theSockPtr;
 
 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 errno_MacSocket = invalidStreamPtr;
 return (-1);
 }
 
 if (from != NULL)
 {
 *fromlen = sizeof(from);
 if (!theSockPtr->state & Connected)
 {
 if (!connect(s, from, *fromlen))
 {
 return(-1);
 }
 }
 }
 return(recv(s, msg, len, flags));
};

/*
 *
 * recvmsg - receive a message from a socket
 *
 */
int recvmsg(int s, struct msghdr *msg, int flags)
{
 SockElmntPtr  theSockPtr;
 
 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 errno_MacSocket = invalidStreamPtr;
 return (-1);
 }
 
 if (msg->msg_name != NULL)
 {
 if (!theSockPtr->state & Connected)
 {
 if (!connect(s, (struct sockaddr_in *)msg->msg_name, msg->msg_namelen))
 {
 return(-1);
 }
 }
 }
 return(recv(s, (char *)msg->msg_iov, msg->msg_iovlen, flags));
};

/*
 *
 * send - send a message from a socket
 *
 */
int send(int s, char *msg, int len, int flags)
{
 TCPiopb*theTCPPtr;
 SockElmntPtr  theSockPtr;

 struct theWDS
 {
 short  length;
 Ptr  theDataPtr;
 short  end;
 } theWDS;
 

 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 return (-1);
 }
 theTCPPtr = &(theSockPtr->thePB);
 theTCPPtr->csCode = TCPSend;
 theTCPPtr->csParam.send.ulpTimeoutValue = SendTimeout;
 theTCPPtr->csParam.send.ulpTimeoutAction = True;
 theTCPPtr->csParam.send.validityFlags = (byte)(timeoutValue | timeoutAction);
 theTCPPtr->csParam.send.pushFlag = True; /* May be false ?? */
 theTCPPtr->csParam.send.urgentFlag = False;
 theWDS.length = len;
 theWDS.theDataPtr = msg;
 theWDS.end = 0;
 theTCPPtr->csParam.send.wdsPtr = (Ptr)&theWDS;
 theTCPPtr->csParam.send.userDataPtr = (Ptr)&theUserData;
 PBControl((ParmBlkPtr)theTCPPtr, Asynchronous);
 PollTCPDriver(theTCPPtr);
 if (errno_MacSocket == noErr)
 {
 return(len);
 }
 else
 {
 return (-1);
 }
};

/*
 *
 * sendto - send a message to a socket
 *
 */
int sendto(int s, char *msg, int len, int flags, struct sockaddr_in *to, 
int *tolen)
{
 SockElmntPtr  theSockPtr;
 
 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 errno_MacSocket = invalidStreamPtr;
 return (-1);
 }
 
 if (to != NULL)
 {
 *tolen = sizeof(struct sockaddr_in);
 if (!theSockPtr->state & Connected)
 {
 if (!connect(s, to, *tolen))
 {
 return(-1);
 }
 }
 }
 return(send(s, msg, len, flags));
};

/*
 * sendmsg - send a message to a socket
 */
int sendmsg(int s, struct msghdr *msg, int flags)
{
 SockElmntPtr  theSockPtr;
 
 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 errno_MacSocket = invalidStreamPtr;
 return (-1);
 }
 
 if (msg->msg_name != NULL)
 {
 if (!theSockPtr->state & Connected)
 {
 if (!connect(s, (struct sockaddr_in *)msg->msg_name, msg->msg_namelen))
 {
 return(-1);
 }
 }
 }
 return(send(s, (char *)msg->msg_iov, msg->msg_iovlen, flags));
};

#ifdef  MAC_APPL
/*
 *
 * SetDialogShowTime - sets the time that an MacTCP/IP info DialogBox 
is vissible.
 * when sec <= 0, no message will be displayed.
 *
 */
void SetDialogShowTime(int sec)
{
 showTime = sec;
}
#endif  MAC_APPL

/*
 *
 * shutdown - shut down part of a full-duplex connection
 *
 */
int shutdown(int s, int how)
{
 TCPiopb*theTCPPtr;
 SockElmntPtr  theSockPtr;

 switch (how)
 {
 case 1: /* further sends disalowed */
 return (close_MacSocket(s));
 break;
 case 2: /* further sends and receives disalowed */
 if ((theSockPtr = FindSocketStruct(s)) == NIL)
 {
 return(-1);
 }
 theTCPPtr = &(theSockPtr->thePB);
 theTCPPtr->csCode = TCPRelease;
 PBControl((ParmBlkPtr)theTCPPtr, Asynchronous);
 PollTCPDriver(theTCPPtr);
 return (RemoveSocketStruct(s));
 break;
 case 0: /* further receives disalowed */
 default:
 errno_MacSocket = invalidArgument;
 return(-1);
 break;
 }
};

/*
 * socket - create an endpoint for communication
 */
intsocket(int domain, int type, int protocol)
{
 TCPiopb*theTCPPtr;
 SockElmntPtr  theSockPtr;
 
 if (domain != AF_INET)
 {
 errno_MacSocket = nonAF_INET;
 return (-1);
 }
 if (protocol != 0)
 {
 errno_MacSocket = invalidArgument;
 return (-1);
 }
 if (type != SOCK_STREAM)
 {
 errno_MacSocket = nonSOCK_STREAM;
 return (-1);
 }
 if ((theSockPtr = (SockElmntPtr)CreateSocketStruct()) == NIL)
 {
 errno_MacSocket = noBufSpace;
 return (-1);
 }

 if (TCPDriverNotOpened)
 {
 if (!OpenTCPDriver())
 {
 return(-1);;
 }
 }
 theTCPPtr = &(theSockPtr->thePB);
 theTCPPtr->ioCompletion = NIL;
 theTCPPtr->ioRefNum = ioRefNumTCP;
 theTCPPtr->csCode = TCPCreate;
 theTCPPtr->csParam.create.rcvBuff = theSockPtr->sockBuf;
 theTCPPtr->csParam.create.rcvBuffLen = SockBufSize;
 theTCPPtr->csParam.create.notifyProc = SockNotify;
 theTCPPtr->csParam.create.userDataPtr = (Ptr)&theUserData;
 PBControl((ParmBlkPtr)theTCPPtr, Asynchronous);
 PollTCPDriver(theTCPPtr);
 if (errno_MacSocket == noErr)
 {
 return (theSockPtr->number);
 }
 else
 {
 RemoveSocketStruct(theSockPtr->number);
 return (-1);
 };
}
 
AAPL
$99.76
Apple Inc.
+2.09
MSFT
$44.08
Microsoft Corpora
+0.45
GOOG
$520.84
Google Inc.
+9.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Apple iOS 8.1 - The latest version of Ap...
The latest version of iOS can be downloaded through iTunes. Apple iOS 8 comes with big updates to apps you use every day, like Messages and Photos. A whole new way to share content with your family.... Read more
TechTool Pro 7.0.5 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PDFKey Pro 4.0.2 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Yasu 2.9.1 - System maintenance app; per...
Yasu was originally created with System Administrators who service large groups of workstations in mind, Yasu (Yet Another System Utility) was made to do a specific group of maintenance tasks... Read more
Hazel 3.3 - Create rules for organizing...
Hazel is your personal housekeeper, organizing and cleaning folders based on rules you define. Hazel can also manage your trash and uninstall your applications. Organize your files using a... Read more
Autopano Giga 3.7 - Stitch multiple imag...
Autopano Giga allows you to stitch 2, 20, or 2,000 images. Version 3.0 integrates impressive new features that will definitely make you adopt Autopano Pro or Autopano Giga: Choose between 9... Read more
MenuMeters 1.8 - CPU, memory, disk, and...
MenuMeters is a set of CPU, memory, disk, and network monitoring tools for Mac OS X. Although there are numerous other programs which do the same thing, none had quite the feature set I was looking... Read more
Coda 2.5 - One-window Web development su...
Coda is a powerful Web editor that puts everything in one place. An editor. Terminal. CSS. Files. With Coda 2, we went beyond expectations. With loads of new, much-requested features, a few... Read more
Arq 4.6.1 - Online backup to Google Driv...
Arq is super-easy online backup for the Mac. Back up to your own Google Drive storage (15GB free storage), your own Amazon Glacier ($.01/GB per month storage) or S3, or any SFTP server. Arq backs up... Read more
Airfoil 4.8.10 - Send audio from any app...
Airfoil allows you to send any audio to AirPort Express units, Apple TVs, and even other Macs and PCs, all in sync! It's your audio - everywhere. With Airfoil you can take audio from any... Read more

Latest Forum Discussions

See All

This Week at 148Apps: October 13-17, 201...
Expert App Reviewers   So little time and so very many apps. What’s a poor iPhone/iPad lover to do? Fortunately, 148Apps is here to give you the rundown on the latest and greatest releases. And we even have a tremendous back catalog of reviews; just... | Read more »
Angry Birds Transformers Review
Angry Birds Transformers Review By Jennifer Allen on October 20th, 2014 Our Rating: :: TRANSFORMED BIRDSUniversal App - Designed for iPhone and iPad Transformed in a way you wouldn’t expect, Angry Birds Transformers is a quite... | Read more »
GAMEVIL Announces the Upcoming Launch of...
GAMEVIL Announces the Upcoming Launch of Mark of the Dragon Posted by Jessica Fisher on October 20th, 2014 [ permalink ] Mark of the Dragon, by GAMEVIL, put | Read more »
Interview With the Angry Birds Transform...
Angry Birds Transformers recently transformed and rolled out worldwide. This run-and-gun title is a hit with young Transformers fans, but the ample references to classic Transformers fandom has also earned it a place in the hearts of long-time... | Read more »
Find Free Food on Campus with Ypay
Find Free Food on Campus with Ypay Posted by Jessica Fisher on October 20th, 2014 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
Strung Along Review
Strung Along Review By Jordan Minor on October 20th, 2014 Our Rating: :: GOT NO STRINGSUniversal App - Designed for iPhone and iPad A cool gimmick and a great art style keep Strung Along from completely falling apart.   | Read more »
P2P file transferring app Send Anywhere...
File sharing services like Dropbox have security issues. Email attachments can be problematic when it comes to sharing large files. USB dongles don’t fit into your phone. Send Anywhere, a peer-to-peer file transferring application, solves all of... | Read more »
Zero Age Review
Zero Age Review By Jordan Minor on October 20th, 2014 Our Rating: :: MORE THAN ZEROiPad Only App - Designed for the iPad With its mind-bending puzzles and spellbinding visuals, Zero Age has it all.   | Read more »
Hay Ewe Review
Hay Ewe Review By Campbell Bird on October 20th, 2014 Our Rating: :: SAVE YOUR SHEEPLEUniversal App - Designed for iPhone and iPad Pave the way for your flock in this line drawing puzzle game from the creators of Worms.   | Read more »
My Very Hungry Caterpillar (Education)
My Very Hungry Caterpillar 1.0.0 Device: iOS Universal Category: Education Price: $3.99, Version: 1.0.0 (iTunes) Description: Care for your very own Very Hungry Caterpillar! My Very Hungry Caterpillar will captivate you as he crawls... | Read more »

Price Scanner via MacPrices.net

2013 15-inch 2.0GHz Retina MacBook Pro availa...
B&H Photo has leftover previous-generation 15″ 2.0GHz Retina MacBook Pros now available for $1599 including free shipping plus NY sales tax only. Their price is $400 off original MSRP. B&H... Read more
Updated iPad Prices
We’ve updated our iPad Air Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers, including the new iPad Air 2 and the... Read more
Apple Pay Available to Millions of Visa Cardh...
Visa Inc. brings secure, convenient payments to iPad Air 2 and iPad mini 3as well as iPhone 6 and 6 Plus. Starting October 20th, eligible Visa cardholders in the U.S. will be able to use Apple Pay,... Read more
Textkraft Pocket – the missing TextEdit for i...
infovole GmbH has announced the release and immediate availability of Textkraft Pocket 1.0, a professional text editor and note taking app for Apple’s iPhone. In March 2014 rumors were all about... Read more
C Spire to offer iPad Air 2 and iPad mini 3,...
C Spire on Friday announced that it will offer iPad Air 2 and iPad mini 3, both with Wi-Fi + Cellular, on its 4G+ LTE network in the coming weeks. C Spire will offer the new iPads with a range of... Read more
Belkin Announces Full Line of Keyboards and C...
Belkin International has unveiled a new lineup of keyboard cases and accessories for Apple’s newest iPads, featuring three QODE keyboards and a collection of thin, lightweight folios for both the... Read more
Verizon offers new iPad Air 2 preorders for $...
Verizon Wireless is accepting preorders for the new iPad Air 2, cellular models, for $100 off MSRP with a 2-year service agreement: - 16GB iPad Air 2 WiFi + Cellular: $529.99 - 64GB iPad Air 2 WiFi... Read more
Price drops on refurbished Mac minis, now ava...
The Apple Store has dropped prices on Apple Certified Refurbished previous-generation Mac minis, with models now available starting at $419. Apple’s one-year warranty is included with each mini, and... Read more
Apple refurbished 2014 MacBook Airs available...
The Apple Store has Apple Certified Refurbished 2014 MacBook Airs available for up to $180 off the cost of new models. An Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
Refurbished 2013 MacBook Pros available for u...
The Apple Store has Apple Certified Refurbished 13″ and 15″ MacBook Pros available starting at $929. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz MacBook Pros (4GB RAM/... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** At the Apple Store, you connect business professionals and entrepreneurs with the tools they need in order to put Apple solutions to work in their Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** The Apple Store is a retail environment like no other - uniquely focused on delivering amazing customer experiences. As an Expert, you introduce people Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** As businesses discover the power of Apple computers and mobile devices, it's your job - as a Solutions Engineer - to show them how to introduce these Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.