home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Archived
/
MP3
/
Riscster
/
riscsrc
/
c
/
proto
< prev
Wrap
Text File
|
2000-05-26
|
20KB
|
871 lines
/*
_ __
____(_)__ _______ / /____ ____
/ __/ (_-</ __(_-</ __/ -_) __/
/_/ /_/___/\__/___/\__/\__/_/
Napster client for RISC OS
Copyright (C) 2000 Robert Dimond
Portions are based on gnap by Ryan Dahl.
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; either version 2 of the License, or
(at your option) any later version.
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
Bransley Cottage, Cleobury Mortimer, Kidderminster, WORCS. DY14 0BZ
England. robdimond@cwcom.net
*/
#include "runimage.h"
socket_s server;
socket_s listen;
char buffer[0xffff];
extern char email[];
extern char username[];
extern char password[];
extern int connection;
extern int new_user;
extern connect_level connected;
extern search_result * search_resblock;
extern int search_currentres;
extern int listening_port;
extern transfer downloads[];
extern incoming incon[];
char ip_bestserver[34];
char debugmsg[200];
int on=1;
message_status mess_stat=get_head;
int mess_recvd=0, mess_len=0, mess_command=0;
char mess_header[4];
int napster_connect(void)
{
int b;
socket_sockaddr serveraddress;
connected=notc;
if(error(xsocket_creat(socket_AF_INET,
socket_SOCK_STREAM,
socket_IPPROTO_IP, &server))) return(-1);
if(error(xsocket_ioctl(server, socket_FIONBIO, (byte *) &on)))
{
xsocket_close(server);
return(-2);
}
/* connect socket to remote server */
serveraddress.sockaddr_in.af=socket_AF_INET;
serveraddress.sockaddr_in.port=portconv(HOSTPORT);
serveraddress.sockaddr_in.addr=ipconv(HOSTIP);
for(b=0; b<8; b++) serveraddress.sockaddr_in.data[b]=0;
connectedchange(tc_redir);
motd_addline("Connecting to redirect server...");
strcpy(ip_bestserver, "");
if(nerror(xsocket_connect(server, &serveraddress, sizeof(serveraddress))))
{
napster_close();
return(-3);
}
return(0);
}
int nerror(os_error * err)
{
int e;
e=err->errnum;
if ((e==socket_EAGAIN)||(e==socket_EWOULDBLOCK)||
(e==socket_EINPROGRESS)) return (0);
else return(error(err));
}
void napster_handle_bestserver()
{
char c;
int cc=0, pos, b;
int newip, newport;
socket_sockaddr serveraddress;
if (nerror(xsocket_recv(server, (byte *) &c, 1, 0, &cc))) return;
pos=strlen(ip_bestserver);
if (cc)
{
ip_bestserver[pos]=c;
ip_bestserver[pos+1]='\0';
}
if (strlen(ip_bestserver)>=20)
{
error(xsocket_close(server));
sprintf(debugmsg, "Redirecting to: %s", ip_bestserver);
napster_get_best_host(&newip, &newport, ip_bestserver);
if(error(xsocket_creat(socket_AF_INET,
socket_SOCK_STREAM,
socket_IPPROTO_IP, &server)))
{
napster_close();
return;
}
serveraddress.sockaddr_in.af=socket_AF_INET;
serveraddress.sockaddr_in.port=newport;
serveraddress.sockaddr_in.addr=newip;
for(b=0; b<8; b++) serveraddress.sockaddr_in.data[b]=0;
error(xsocket_ioctl(server, socket_FIONBIO, (byte *) &on));
if(nerror(xsocket_connect(server, &serveraddress, sizeof(serveraddress))))
{
napster_close();
return;
}
connectedchange(tc_server);
motd_addline(debugmsg);
}
}
void napster_close()
{
if (connected!=notc) error(xsocket_close(server));
connectedchange(notc);
}
int napster_mo_userlogin(char * username, char * password, int port, int connection, int new_user)
{
char connect_string[200]="";
if (!new_user)
{
sprintf(connect_string,"%s %s %i \"%s\" %i",username,password,port,VERSION_STRING,connection);
napster_send(connect_string, 2, strlen(connect_string));
}
else
{
sprintf(connect_string,"%s %s %i \"%s\" %i %s",username,password,port,VERSION_STRING,connection, email);
napster_send(connect_string, 6, strlen(connect_string));
}
return(0);
}
int napster_mo_newuser(char * username)
{
napster_send(username, 7, strlen(username));
return(0);
}
int napster_mo_dlrequest(search_result * toget)
{
char get_string[300];
sprintf(get_string, "%s \"%s\"", toget->user, toget->filename);
napster_send(get_string, 203, strlen(get_string));
return(0);
}
void napster_get_best_host(int * ipo, int * porto, char * string)
{
char * ip, * port, * c;
ip=string;
port=strchr(string, ':');
port[0]='\0';
port+=sizeof(char);
c=strchr(port, '\0');
c[0]='\0';
*porto=portconv(atoi(port));
*ipo=ipconv(ip);
}
int portconv(int port)
{
char *b, *c;
b=(char *)&port;
c=b+1;
return(*c|(*b<<8));
}
int ipconv(char * ipin)
{
char c[]=".";
char ip[]="000.000.000.000";
char * t;
int out=0, n=0;
strcpy(ip, ipin);
t=strtok(ip, c);
while ((t!=NULL)&&(n<4))
{
out+=atoi(t)<<(n*8);
t=strtok(NULL, c);
n++;
}
/*os_writec('\4');
printf("%s %d\n", ip, out);*/
return(out);
}
/*int main(void)
{
napster_connect();
napster_mo_userlogin("ribby", "jelly", 6699, 3, 0);
while(napster_poll()==0);
}*/
/*int napster_poll(void)
{
int cc, length, type;
if(error(xsocket_recv(server, (byte *) buffer, 4, 0, &cc))) return(-1);
if (cc==4)
{
length=buffer[0]|(buffer[1]<<8);
type=buffer[2]|(buffer[3]<<8);
printf("%d %d\n", length, type);
if(error(xsocket_recv(server, (byte *) buffer, length, 0, &cc))) return(-1);
buffer[cc]='\0';
printf("%s\n", buffer);
switch(type)
{
case 0:
napster_mess_error(buffer); break;
case 1: break;
}
return(0);
}
}*/
int napster_poll(void)
{
int i;
socket_s newsocket;
socket_timeval timeout;
long readfd=0, writefd=0;
int nfound=0;
readfd=readfd|(long)1<<(int)listen;
switch(connected)
{
case notc:
break;
case tc_redir:
writefd=writefd|(long)1<<(int)server;
break;
case get_redir:
readfd=readfd|(long)1<<(int)server;
break;
case tc_server:
writefd=writefd|(long)1<<(int)server;
break;
default:
if (connected>=try_login)
{
readfd=readfd|(long)1<<(int)server;
for(i=0; i<C_DOWNLOADS; i++)
{
if(downloads[i].active==tc) writefd=writefd|(long)1<<(int)downloads[i].socket;
if(downloads[i].active>=get_one)
readfd=readfd|(long)1<<(int)downloads[i].socket;
}
}
}
for(i=0; i<C_INCOMING; i++)
{
if(incon[i].active) readfd=readfd|(long)1<<(int)incon[i].socket;
}
timeout.sec=0; timeout.usec=0;
error(xsocket_select(32, (socket_fdset *) &readfd,
(socket_fdset *) &writefd,
NULL, &timeout, &nfound));
if(readfd&((long)1<<(int)listen))
{
if(!nerror(xsocket_accept(listen, NULL, NULL, &newsocket)))
napster_incoming(newsocket);
}
switch(connected)
{
case notc:
break;
case tc_redir:
if(writefd&((long)1<<(int)server)) connectedchange(get_redir);
break;
case get_redir:
if(readfd&((long)1<<(int)server)) napster_handle_bestserver();
break;
case tc_server:
if(writefd&((long)1<<(int)server))
{
motd_addline("Connected, trying to log in...");
if(!new_user)
napster_mo_userlogin(username, password, listening_port, connection, 0);
else napster_mo_newuser(username);
connectedchange(try_login);
}
break;
default:
if(connected>=try_login)
{
if(readfd&((long)1<<(int)server))
{
napster_handle_input();
}
for(i=0; i<C_DOWNLOADS; i++)
{
if((downloads[i].active==tc)&&(writefd&((long)1<<(int)downloads[i].socket)))
napster_handle_nfconnected(i);
if((downloads[i].active>=get_one)&&(readfd&((long)1<<(int)downloads[i].socket)))
{
switch(downloads[i].active)
{
case get_one:
napster_handle_one(i);
break;
case get_header:
napster_handle_header(i);
break;
case download:
napster_handle_download(i);
break;
}
}
}
}
break;
}
for(i=0; i<C_INCOMING; i++)
{
if((incon[i].active)&&(readfd&((long)1<<(int)incon[i].socket)))
{
napster_handle_inconheader(i);
}
}
return(0);
}
void napster_incoming(socket_s newsocket)
{
int cc=0;
int in_slot=0;
while((in_slot<=C_INCOMING)&&(incon[in_slot].active!=0))
{
in_slot++;
}
if(incon[in_slot].active!=0)
{
xsocket_close(newsocket);
return;
}
if (nerror(xsocket_send(newsocket, (byte *) "1", 1, 0, &cc)))
{
ui_messalert("ERRCOMC");
xsocket_close(newsocket);
return;
}
incon[in_slot].socket=newsocket;
incon[in_slot].active=1;
incon[in_slot].hpos=0;
incon[in_slot].header[0]='\0';
incon[in_slot].command=0;
}
void napster_handle_inconheader(int ino)
{
char c;
int cc=0, i;
if (nerror(xsocket_recv(incon[ino].socket, (byte *) &c, 1, 0, &cc)))
{
ui_messalert("ERRCOMC");
incon[ino].active=0;
xsocket_close(incon[ino].socket);
return;
}
incon[ino].header[incon[ino].hpos]=c;
incon[ino].hpos++;
incon[ino].header[incon[ino].hpos]='\0';
if(incon[ino].active==1)
{
if(!strcmp(incon[ino].header, "SEND"))
{
incon[ino].command=1;
incon[ino].hpos=0;
incon[ino].active=2;
return;
}
}
if(incon[ino].active==2)
{
if (c=='\"')
{
incon[ino].active=3;
return;
}
}
if(incon[ino].active==3)
{
if (c==' ')
{
for(i=0; i<C_DOWNLOADS; i++)
{
if((downloads[i].active==window)&&
(strstr(incon[ino].header, downloads[i].filename)))
{
cc=0;
if(nerror(xsocket_send(incon[ino].socket, (byte *) "0", 1, 0, &cc)))
{
incon[ino].active=0;
xsocket_close(incon[ino].socket);
ui_messalert("ERRCOMC");
return;
}
if(cc)
{
incon[ino].active=0;
downloads[i].socket=incon[ino].socket;
downloads[i].active=get_header;
downloads[i].headcount=0;
}
}
}
}
}
}
void napster_handle_header(int tno)
{
int cc;
char c;
if(nerror(xsocket_recv(downloads[tno].socket, (byte *) &c, 1,
socket_MSG_PEEK, &cc)))
{
ui_messalert("ERRCOMC");
napster_download_end(tno);
}
if (!isdigit((int) c))
{
downloads[tno].header[downloads[tno].headcount]='\0';
sprintf(debugmsg, "Got size header: %s bytes", downloads[tno].header);
motd_addline(debugmsg);
napster_send((char *) "", 218, 0);
downloads[tno].totalsize=atoi((downloads[tno].header));
downloads[tno].active=download;
}
else
{
if(nerror(xsocket_recv(downloads[tno].socket, (byte *) &c, 1, 0, &cc)))
{
ui_messalert("ERRCOMC");
napster_download_end(tno);
}
downloads[tno].header[downloads[tno].headcount]=c;
downloads[tno].headcount++;
}
}
void napster_handle_download(int tno)
{
char buffer[2048];
int amount_recv, i;
for (i=0; i<2048; i++) buffer[i]=0;
/*amount_recv = recv(t_current.socket,buffer,2048,0);*/
nerror(xsocket_recv(downloads[tno].socket, (byte *)buffer,
2048, 0, &amount_recv));
fwrite(buffer, sizeof(char), amount_recv, downloads[tno].filehandle);
downloads[tno].size += amount_recv;
if (downloads[tno].size>=downloads[tno].totalsize) napster_download_end(tno);
}
void napster_download_end(int tno)
{
if (downloads[tno].active==download)
{
napster_send((char *) "", 219, 0);
}
if (downloads[tno].active>=tc)
{
error(xsocket_close(downloads[tno].socket));
if (fclose(downloads[tno].filehandle)==EOF)
{
ui_messalert("ERRCSC");
}
}
get_closewin(tno);
downloads[tno].active=freesl;
}
void napster_send(char * data, int type, int length)
{
char msb, lsb;
char head[4];
char motd[255];
int cc;
msb=(length>>8);
lsb=length-(msb<<8);
head[0]=lsb; head[1]=msb;
msb=(type>>8);
lsb=type-(msb<<8);
head[2]=lsb; head[3]=msb;
if((nerror(xsocket_send(server, (byte *)head, 4, 0, &cc)))
||(nerror(xsocket_send(server, (byte *)data, length, 0, &cc))))
{
ui_messalert("ERRCOMS");
napster_close();
return;
}
sprintf(motd, "> Type:%d Len:%d %s", type, length, data);
motd_addline(motd);
}
void napster_mess_loginerror(char * message)
{
/*printf("Error from server: %s\n", message);*/
ui_alert(message);
napster_close();
}
void napster_mess_error(char * message)
{
ui_alert(message);
search_ungrey();
}
void napster_mess_loginack(char * email)
{
/*printf("Logged in, email is %s\n", email);*/
ui_messalert("SMLOGIN");
/* napster_init_server();*/
connectedchange(loggedin);
}
void napster_mess_regsuccess(void)
{
/*printf("New user registration success\n");*/
ui_messalert("SMREGS");
napster_mo_userlogin(username, password, 6699, connection, 1);
}
void napster_mess_alreadyreg(void)
{
/*printf("Nickname is already in use by another user\n");*/
ui_messalert("SMNICK");
napster_close();
}
void napster_mess_invalidreg(void)
{
/*printf("Nickname is invalid\n");*/
ui_messalert("SMINV");
napster_close();
}
void napster_mess_searchresponse(char * line)
{
search_result * result, * i;
char *filename,user[40],id[100];
int number,size,bitrate,frequency,speed;
unsigned int ip;
filename = line;
filename ++;
line = (char*)strchr(filename,'\"');
if(!line) {
/* printf("strange filename error\n");*/
os_writec('\4');
printf("%s\n", line);
ui_messalert("ERRSFILE");
return;
}
line[0] = '\0';
line ++;
result = malloc(sizeof(search_result));
if (result==NULL) return;
sscanf(line," %s %u %d %d %d %s %u %d",id,&size,&bitrate,&frequency,&number,user,&ip,&speed);
strcpy(result->filename, filename);
strcpy(result->id, id);
result->number = number;
result->ip = ip;
strcpy(result->user, user);
result->size = size;
result->bitrate = bitrate;
result->frequency = frequency;
result->speed = speed;
result->next = NULL;
if (speed<0) return;
search_update(result);
}
void napster_mess_searchend()
{
search_ungrey();
search_finish();
}
void napster_mess_dlack(char * buffer)
{
/*char motdt[100];*/
char getstring[300];
char fn[300], fnt[255];
char *filename,*rest,user[40],id[40];
int port,speed;
unsigned int ip;
int tno=-1, i;
int b, used=0;
char dot[]=".";
socket_sockaddr otheruser;
filename = strchr(buffer,'\"');
filename[0] = '\0';
filename ++;
rest = strchr(filename,'\"');
rest[0] = '\0';
rest++;
sscanf(buffer,"%s %u %d ",user,&ip,&port);
sscanf(rest," %s %d",id,&speed);
sprintf(debugmsg, "Connect to port %d", port);
motd_addline(debugmsg);
if(error(xos_read_var_val("Riscster$MusicDir", fn, 300, 0, os_VARTYPE_STRING,
&used, NULL, NULL)))
{
ui_messalert("ERRMPNS");
return;
}
fn[used]='\0';
for (i=0; i<C_DOWNLOADS; i++)
{
if (downloads[i].active==window)
{
if (strcmp(downloads[i].filename, filename)==0) tno=i;
}
}
if (tno==-1)
{
return;
}
strcpy(fnt, filename);
strcat(fn, dot);
strcat(fn, napster_sanefile(fnt));
downloads[tno].filehandle=fopen(fn, "wb");
if (downloads[tno].filehandle==NULL)
{
ui_messalert("ERRSCRAP");
return;
}
error(xosfile_set_type(fn, 0x1ad));
/*downloads[tno].totalsize=(search_resblock+search_currentres)->size;*/
if (port==0)
{
sprintf(getstring, "%s \"%s\" 0", downloads[tno].user, filename);
napster_send(getstring, 500, strlen(getstring));
return;
}
if(error(xsocket_creat(socket_AF_INET, socket_SOCK_STREAM, socket_IPPROTO_IP,
&downloads[tno].socket)))
{
return;
}
error(xsocket_ioctl(downloads[tno].socket, socket_FIONBIO, (byte *) &on));
otheruser.sockaddr_in.af=socket_AF_INET;
otheruser.sockaddr_in.port=portconv(port);
otheruser.sockaddr_in.addr=ip;
for(b=0; b<8; b++) otheruser.sockaddr_in.data[b]=0;
if(nerror(xsocket_connect(downloads[tno].socket, &otheruser, sizeof(otheruser))))
{
ui_messalert("ERRCNCN");
xsocket_close(downloads[tno].socket);
return;
}
downloads[tno].active=tc;
downloads[tno].headcount=0;
}
void napster_handle_nfconnected(int tno)
{
char getstring[300];
int cc=0;
nerror(xsocket_send(downloads[tno].socket, (byte *) "GET", 3, 0, &cc));
sprintf(getstring, "%s \"%s\" 0", username, downloads[tno].filename);
cc=0;
nerror(xsocket_send(downloads[tno].socket,
(byte *) getstring, strlen(getstring), 0, &cc));
downloads[tno].active=get_one;
}
void napster_handle_one(int tno)
{
int cc=0;
char mustbeone;
nerror(xsocket_recv(downloads[tno].socket, (byte *) &mustbeone, 1, 0, &cc));
if (mustbeone!='1')
{
ui_messalert("ERRIHE");
napster_download_end(tno);
}
downloads[tno].active=get_header;
}
char * napster_sanefile(char * file)
{
char * nfile;
nfile=strrchr(file, (int) '\\');
if (nfile!=NULL) file=nfile+1;
nfile=file;
while (*nfile!='\0')
{
if (*nfile=='.') *nfile='/';
if (*nfile==' ') *nfile='_';
nfile++;
}
return(file);
}
void napster_mess_motd(char * buffer)
{
/*os_writec('\4');
printf("%s\n", buffer);*/
motd_addline(buffer);
}
void napster_handle_input(void)
{
char buffer2[0xffff];
switch(mess_stat)
{
case get_head:
{
int cc=0, i=0;
/*FILE * messydebug;*/
if(nerror(xsocket_recv(server, (byte *) &mess_header[mess_recvd],
1, 0, &cc)))
{
ui_messalert("ERRCOMS");
napster_close();
return;
}
mess_recvd+=cc;
if(mess_recvd==4)
{
mess_len=mess_header[0]|(mess_header[1]<<8);
mess_command=mess_header[2]|(mess_header[3]<<8);
for(i=0; i<sizeof(buffer); i++) buffer[i]='\0';
if (mess_len>0) mess_stat=get_data;
else napster_handle_message(mess_command, buffer);
mess_recvd=0;
/*messydebug=fopen("RAM::RamDisc0.$.messdebug", "a");
fprintf(messydebug, "Length: %d Type: %d\n", mess_len, mess_command);
fclose(messydebug);*/
}
}
break;
case get_data:
{
int cc=0, i=0;
/*FILE * messydebug;
messydebug=fopen("RAM::RamDisc0.$.messdebug", "a");
fprintf(messydebug, "Got Already: %d\n", mess_recvd);
fclose(messydebug);*/
for (i=0; i<sizeof(buffer2); i++) buffer2[i]='\0';
if(nerror(xsocket_recv(server, (byte *) buffer2,
(mess_len-mess_recvd), 0, &cc)))
{
ui_messalert("ERRCOMS");
napster_close();
}
/*messydebug=fopen("RAM::RamDisc0.$.messdebug", "a");
fprintf(messydebug, "Just Got: %d\n", cc);
fclose(messydebug);*/
memcpy(buffer+mess_recvd, buffer2, cc);
mess_recvd+=cc;
if(mess_recvd==mess_len)
{
napster_handle_message(mess_command, buffer);
mess_stat=get_head;
mess_len=0;
mess_command=0;
mess_recvd=0;
}
}
break;
}
}
void napster_handle_message(int mc, char * buffer)
{
switch(mc)
{
case 0:
napster_mess_loginerror(buffer); break;
case 3:
napster_mess_loginack(buffer); break;
case 8:
napster_mess_regsuccess(); break;
case 9:
napster_mess_alreadyreg(); break;
case 10:
napster_mess_invalidreg(); break;
case 201:
napster_mess_searchresponse(buffer); break;
case 202:
napster_mess_searchend(); break;
case 204:
napster_mess_dlack(buffer); break;
case 404:
napster_mess_error(buffer); break;
case 621:
napster_mess_motd(buffer); break;
}
}
int napster_init_server()
{
socket_sockaddr localport;
int b;
int tryport=6698;
if(error(xsocket_creat(socket_AF_INET,
socket_SOCK_STREAM,
socket_IPPROTO_IP, &listen))) return(-1);
error(xsocket_ioctl(listen, socket_FIONBIO, (byte *) &on));
do
{
tryport++;
localport.sockaddr_in.af=socket_AF_INET;
localport.sockaddr_in.port=portconv(tryport);
localport.sockaddr_in.addr=0;
for(b=0; b<8; b++) localport.sockaddr_in.data[b]=0;
}while(xsocket_bind(listen, &localport, sizeof(localport))&&
(tryport<6800));
listening_port=tryport;
if(error(xsocket_listen(listen, 5))) return(-2);
return(0);
}
int napster_end_server()
{
return(error(xsocket_close(listen)));
}