diff --git a/Wawi Source/ClientConnection.cpp b/Wawi Source/ClientConnection.cpp new file mode 100644 index 0000000..29c04f8 --- /dev/null +++ b/Wawi Source/ClientConnection.cpp @@ -0,0 +1,541 @@ +/* --- CLIENTCONNECTION.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include +#include "types.h" +#include "wamessage.h" +#include "main.h" +#include "op_winamp.h" +#include "html.h" +#include "plugin.h" +#include "resource.h" + + +extern char mp3root[MAX_PATH], logfiledir[MAX_PATH]; +extern int dl_wa_files, dl_other_files, frames, title_refresh; +extern char szAppVer[]; +extern char pagetitle[255]; + +extern winampGeneralPurposePlugin plugin; + +bool loglocked = false; + +char realm_server[] = "Wawi Server Control"; +char realm_control[] = "Wawi Playback Control"; +char realm_clear[] = "Wawi Playlist Clear Control"; +char realm_playlist[] = "Wawi Playlist Control"; +char realm_download[] = "Wawi Downloads"; +char realm_browse[] = "Wawi Music Collection"; + +CControl Control; + +// -------------------------------------------------------------------------------- +// Thread called for each connection +DWORD WINAPI ClientConnection(LPVOID socket_param) // new thread for a new client. +{ + + + bool matched = false; + connection conn; // structure to hold request details + ZeroMemory(&conn,sizeof(conn)); + conn.http.auth = AUTH_ANON; + wsprintf(conn.http.user,"anon"); + conn.log = true; + conn.state = ST_NONE; + conn.http.responsecode = 200; + + conn.socket = (SOCKET)socket_param; // convert param into socket + + + int rhost_len = sizeof(conn.remote_host); + getpeername(conn.socket,(sockaddr*)&conn.remote_host,&rhost_len); + + if (!GetRequest(&conn)) + { + //MessageBox(NULL,conn.http.file,"400",MB_TOPMOST | MB_OK); + conn.http.responsecode = 400; + Send400(&conn); + shutdown(conn.socket,0); + closesocket(conn.socket); + MakeLogEntry(&conn); + return true; + } + + + +// ------------- Images ------------------ + // Of the form /img?image=n where 'n' is the id of the image, eg. IDR_DIRECTORY. + if (StrComp(conn.http.page,"/img")) + { + //MessageBox(NULL,conn.http.file,"File",MB_OK | MB_TOPMOST); + //MessageBox(NULL,conn.http.page,"Page",MB_OK | MB_TOPMOST); + conn.log = false; + conn.state = Control.Image(&conn,IMG_GIF); + } + +// ------------- Favicon.ico!!!----------- + // Sent the same as a img resource but with a different header + if (StrComp(conn.http.page,"/favicon.ico")) + { + //conn.log = false; + wsprintf(conn.http.file,"/img?%d",IDR_ICO_WINAMP); + conn.state = Control.Image(&conn,IMG_ICO); + } + + +// ------------ Top ----------------- + if (StrComp(conn.http.page,"/top")) + { + conn.log = false; + conn.state = Control.TopFrame(&conn); + } + + +// ------------- Small Title ------------ +// No page formatting at all; just the song info. + + if (StrComp(conn.http.page,"/smalltitle")) + conn.state = Control.SmallTitle(&conn); + + +// -------------- Title ---------------- + if (StrComp(conn.http.page,"/title")) + { + conn.log = false; + conn.state = Control.Title(&conn); + } + + +// ---------- Shutdown Computer ------------- + if (StrComp(conn.http.page,"/shutdown")) + { + if (!(conn.http.auth & AUTH_SERVER)) + conn.state = SendBasic401(&conn,realm_server); + else + conn.state = Control.Shutdown(&conn); + + } + + + +// ---------- Clear Playlist ----- + if (StrComp(conn.http.page,"/clear")) + { + if (!(conn.http.auth & AUTH_CLEAR)) + conn.state = SendBasic401(&conn,realm_playlist); + else + conn.state = Control.Clear(&conn); + } + + +// ---------- Sort playlist ---------- + if (StrComp(conn.http.page,"/sort")) + { + if (!(conn.http.auth & AUTH_PLAYLIST)) + conn.state = SendBasic401(&conn,realm_playlist); + else + conn.state = Control.Sort(&conn); + } + + + + +// ------------ Browse ----------- + if (StrComp(conn.http.page,"/browse")) + { + if (!(conn.http.auth & AUTH_BROWSE)) + conn.state = SendBasic401(&conn,realm_browse); + else + { + char mp3path[MAX_PATH]; + if (GetArgValue(&conn,"path",(char*)&mp3path,MAX_PATH) == false) + wsprintf(mp3path,"%%5c"); + ReplaceSlashes(mp3path); + conn.state = Browse(&conn, mp3path); + if (frames == 1) + LinkBar(&conn); + } + } + +// ------------ Download --------- + if (StrComp(conn.http.page,"/dl")) + if (!(conn.http.auth & AUTH_DOWNLOAD)) + conn.state = SendBasic401(&conn,realm_download); + else + conn.state = Control.Download(&conn); + + + +// ------------ Load ------------- + if (StrComp(conn.http.page,"/ld")) // ld = load + { + if (!(conn.http.auth & AUTH_PLAYLIST)) + conn.state = SendBasic401(&conn,realm_playlist); + else + conn.state = Control.Load(&conn); + } + +// ------------ List ------------- + if (StrComp(conn.http.page,"/list")) + conn.state = Control.List(&conn); + + +// ------------ Next ------------- + if (StrComp(conn.http.page,"/next")) // Next track + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Next(&conn); + } + + +// ------------ Prev ------------- + if (StrComp(conn.http.page,"/prev")) // Previous track + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Prev(&conn); + } + + +// ------------ Play ------------- + if (StrComp(conn.http.page,"/play")) + // Play (or play?xxxx) + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Play(&conn); + } + +// ------------ Stop ------------- + if (StrComp(conn.http.page,"/stop")) + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Stop(&conn); + } + +// ----------- Stop slowly ----------- + + if (StrComp(conn.http.page,"/stopslow")) + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.StopSlow(&conn); + } + + +// ------------ Pause ------------ + if (StrComp(conn.http.page,"/pause")) + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Pause(&conn); + } + +// ------------ Volume ----------- + if (StrComp(conn.http.page,"/vol")) + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Volume(&conn); + } + +// ----------- Random / Repeat -------------- + if (StrComp(conn.http.page,"/playmode")) + { + if (!(conn.http.auth & AUTH_CONTROL)) + conn.state = SendBasic401(&conn,realm_control); + else + conn.state = Control.Playmode(&conn); + } + +// ------------- Login/out--------------- + if (StrComp(conn.http.page,"/login")) + conn.state = SendBasic401(&conn,"Winamp Web Interface"); + +// ------------ About ---------------- + + if (StrComp(conn.http.page,"/about")) + { + conn.state = Control.About(&conn); + } + + +// ---------- Delete playlist entry ---- + if (StrComp(conn.http.page,"/delete")) + { + if (!(conn.http.auth & AUTH_CLEAR)) + conn.state = SendBasic401(&conn,realm_clear); + else + conn.state = Control.Delete(&conn); + } + + +// ---------- Stylesheet ------------- + if (StrComp(conn.http.page,"/wawi.css")) + { + conn.log = false; + conn.state = Control.UserStyle(&conn); + } + +// ------------ Main page ---------------- + if (StrComp(conn.http.page,"/main")) + { + conn.state = Control.Main(&conn); + } + + +// ------------ PDA Page ---------------- + if (StrComp(conn.http.page,"/pda")) + { + conn.state = Control.pda(&conn); + } + +// ------------ Admin ------------------ + if (StrComp(conn.http.page,"/admin")) + { + if (!(conn.http.auth & AUTH_SERVER)) + conn.state = SendBasic401(&conn,realm_server); + else + conn.state = Control.WebAdmin(&conn); + } + + if (StrComp(conn.http.page,"/apply")) + { + if (!(conn.http.auth & AUTH_SERVER)) + conn.state = SendBasic401(&conn,realm_server); + else + conn.state = Control.ApplyAdmin(&conn); + } + + +// -------------- Users ----------------- + if (StrComp(conn.http.page,"/user")) + { + if (!(conn.http.auth & AUTH_SERVER)) + conn.state = SendBasic401(&conn,realm_server); + else + conn.state = Control.User(&conn); + } + +// ------ Set user permissions ------------ + if (StrComp(conn.http.page,"/setuser")) + { + if (!(conn.http.auth & AUTH_SERVER)) + conn.state = SendBasic401(&conn,realm_server); + else + conn.state = Control.SetUser(&conn); + } + +// ------ Save playlist ------------ + if (StrComp(conn.http.page,"/save")) + { + if (!(conn.http.auth & AUTH_PLAYLIST)) + conn.state = SendBasic401(&conn,realm_playlist); + else + conn.state = Control.SavePlaylist(&conn); + } + + +// ------ Page redirect - page?page=(main|list|browse) + if (StrComp(conn.http.page,"/page")) + { + char page[10]; + GetArgValue(&conn,"page",page,10); + + if (!(StrComp(page,"main") || StrComp(page,"list") || StrComp(page,"browse"))) + wsprintf(page,"main"); + + prints(&conn,"HTTP/1.0 302 Temporarily Moved\nLocation: /"); + prints(&conn,page); + prints(&conn,"\nConnection: close\nContent-type: text/html\n\n"); + prints(&conn,"\n\nWinamp Web Interface\n\n"); + prints(&conn,"\n

Winamp Web Interface

\n\n\n\n"); + + conn.state = ST_CLOSE; + } + + + + + + if (StrComp(conn.http.page,"/winamp")) + { + OpenHTTPHeader(&conn,"text/html",0,NULL); + if (conn.http.reqID == RID_HEAD) + conn.state = ST_CLOSE; + else + { + char reqpage[10]; + GetArgValue(&conn,"page",reqpage,10); + + if (!(StrComp(reqpage,"main") || StrComp(reqpage,"list") || StrComp(reqpage,"browse"))) + wsprintf(reqpage,"main"); + + OpenHtmlHeader(&conn); + Style(&conn); + CloseHeader(&conn); + if (frames == 3) + { + prints(&conn,"\n\n\n\n"); + prints(&conn,"<p><b>Frames are required for this site!<b></p><p>If no-frames operation is required, check the <b>No Frames Mode</b> box in the Options screen.</p>\n"); + prints(&conn,"</frameset>\n"); + } + else + { + prints(&conn,"<frameset border=\"0\" frameborder=\"0\" rows=\"35,1*\">\n<frame name=\"top\" src=\"/top\" noresize marginheight=\"0\" marginwidth=\"0\">\n<frame name=\"main\" src=\"/page?page="); + prints(&conn,reqpage); + prints(&conn,"\" noresize>\n"); + prints(&conn,"<noframes><p><b>Frames are required for this site!<b></p><p>If no-frames operation is required, check the <b>No Frames Mode</b> box in the Options screen.</p>\n"); + prints(&conn,"</frameset>\n"); + } + + conn.state = ST_CLOSEBODY; + } + } + + if (conn.state == ST_NONE) // something else, including '/' + { // 302 to /winamp?page=frames + if (frames == 1) + { + prints(&conn,"HTTP/1.0 302 Temporarily Moved\nLocation: /page?page=main\nConnection: close\nContent-type: text/html\n\n"); + prints(&conn,"<html>\n<head>\n<title>Winamp Web Interface</title>\n</head>\n"); + prints(&conn,"<body>\n<p><a href=\"/page?page=main\">Winamp Web Interface</a></p>\n</body>\n</html>\n\n"); + } + else + { + prints(&conn,"HTTP/1.0 302 Temporarily Moved\nLocation: /winamp?page=main\nConnection: close\nContent-type: text/html\n\n"); + prints(&conn,"<html>\n<head>\n<title>Winamp Web Interface</title>\n</head>\n"); + prints(&conn,"<body>\n<p><a href=\"/winamp?page=main\">Winamp Web Interface</a></p>\n</body>\n</html>\n\n"); + } + //conn.log = false; + conn.state = ST_CLOSE; + } + + if (conn.state == ST_CLOSEBODY) + CloseBody(&conn); // end html + + + flush(&conn); + closesocket(conn.socket); // close connection + + if (conn.log) + MakeLogEntry(&conn); + + + return true; +}; + +/* +struct HOSTENT FAR * gethostbyaddr ( + const char FAR * addr, + int len, + int type +); +*/ + +// -------------------------------------------------------------------------------- +// Adds entry in log +void MakeLogEntry(connection * conn) +{ + int logbuffer_len; + + SYSTEMTIME time; + GetSystemTime(&time); + char timestr[100]; // "[DD/MM/YYYY HH:MM:SS]" + wsprintf(timestr,"[%02d.%02d.%04d %02d:%02d:%02d]",time.wDay, time.wMonth, time.wYear, time.wHour, time.wMinute, time.wSecond); + + char logbuffer[2048]; + ZeroMemory(&logbuffer,sizeof(logbuffer)); + + logbuffer_len = wsprintf(logbuffer,"%s %s %s %d %s %s\r\n",timestr, (char*)inet_ntoa(conn->remote_host.sin_addr), conn->http.user, conn->http.responsecode, conn->http.request, conn->http.file); + + // Find log file, in winamp plugin directory (same dir as gen_httpsrv.dll) + char logfilepath[MAX_PATH], *p; + char logfile[MAX_PATH]; + + if (lstrlen(logfiledir) == 0) + { + GetModuleFileName(plugin.hDllInstance,logfilepath,sizeof(logfilepath)); + p=logfilepath+lstrlen(logfilepath); + while (p >= logfilepath && *p != '\\') p--; + if (++p >= logfilepath) *p = 0; + wsprintf(logfile,"%shttpsrv.log",logfilepath); + } + else + { + lstrcpy(logfilepath,logfiledir); + wsprintf(logfile,"%s\\httpsrv.log",logfilepath); + } + + //lstrcat(logfile,"gen_httpsrv_log.log); + + //MessageBox(NULL,logfile,"Logfile",MB_OK| MB_TOPMOST); + + while(loglocked == true) // wait for log file to be free + Sleep(50); + + loglocked = true; // lock it + + HANDLE hLog = CreateFile( logfile, + GENERIC_WRITE, + 0, + 0, + OPEN_ALWAYS, + 0, + 0); + + if (hLog == NULL) + { + //MessageBox(NULL,"Couldn't open log file","gen_httpSrv debug", MB_OK); + return; + } + + DWORD dwSize = GetFileSize(hLog, NULL); + + //MessageBox(NULL,logfilename,"logfile size",MB_OK); + SetFilePointer(hLog,(LONG)dwSize,NULL,FILE_BEGIN); + + unsigned long written; + WriteFile(hLog,&logbuffer,logbuffer_len,&written,NULL); + + CloseHandle(hLog); + + if (dwSize >= 50000) // rename log file to something else to start a new one + { + char logfilename[MAX_PATH]; + bool name_used = true; + int letter = 1; + while(name_used) + { // loop through acceptable names, find first unused one of form httpsrv_dd-dd-yyyy_n.log + wsprintf(logfilename,"%shttpsrv_%d-%d-%d_%d.log",logfilepath,time.wDay,time.wMonth,time.wYear,letter); + //MessageBox(NULL,logfilename,"Logfilename",MB_OK | MB_TOPMOST); + if (GetFileAttributes(logfilename) == 0xFFFFFFFF) + { + name_used = false; + MoveFile(logfile,logfilename); + } + else + { + letter++; + } + } + } + + loglocked = false; // release log file +} \ No newline at end of file diff --git a/Wawi Source/Config.cpp b/Wawi Source/Config.cpp new file mode 100644 index 0000000..f10382c --- /dev/null +++ b/Wawi Source/Config.cpp @@ -0,0 +1,535 @@ +/* --- CONFIG.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + + +#include <windows.h> +#include <prsht.h> + +#include "types.h" +#include "main.h" +#include "resource.h" +#include "plugin.h" + +extern int con_port, hide_error, frames, securepassword, pass_debug; +extern int show_other_files, dl_wa_files, dl_other_files, title_refresh; + +extern char mp3root[MAX_PATH], playlistdir[MAX_PATH], filetypes[255], pagetitle[255], logfiledir[MAX_PATH]; + + +extern char szAppVer[], szAppName[]; +extern winampGeneralPurposePlugin plugin; + +HWND ConfigWnd = NULL; // To ensure only one config window appears at once +HWND UsersWnd = NULL; + +// -------------------------------------------------------------------------------- +// Server options window proc +BOOL CALLBACK ConfigServerWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + char TempString[10]; + int port_temp; + switch(uMsg) + { + case WM_INITDIALOG: + wsprintf(TempString,"%d",con_port); + SetDlgItemText(hwndDlg,IDC_PORT_EDIT,TempString); + CheckDlgButton(hwndDlg,IDC_SECUREPASSWORD,securepassword); + CheckDlgButton(hwndDlg,IDC_PASS_DEBUG,pass_debug); + CheckDlgButton(hwndDlg,IDC_HIDE_ERROR,hide_error); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_SECUREPASSWORDHELP: + MessageBox(hwndDlg,"Secure Passwords...\n\nWawi is able to encrypt passwords in the config file using the MD5 algorithm, or they can just be stored as jumbled but potentially retrievable strings using the Base64 algorithm.\n\nLeave this checked unless you have problems. Note that changing between secure and insecure passwords will require entering all passwords in again.\n\nThe \"debug\" option is in case of further trouble. This will make message boxes pop up telling you what it is doing when saving a password; if it doesn't work let me know what these say and I'll see what I can do. Ta...","Winamp Web Interface Help",MB_OK); + break; + } + break; + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: port_temp = GetDlgItemInt(hwndDlg,IDC_PORT_EDIT,NULL,false); + if (port_temp > 0 && port_temp < 65536) + { + con_port = port_temp; + hide_error = IsDlgButtonChecked(hwndDlg,IDC_HIDE_ERROR); + securepassword = IsDlgButtonChecked(hwndDlg,IDC_SECUREPASSWORD); + pass_debug = IsDlgButtonChecked(hwndDlg,IDC_PASS_DEBUG); + } + else + { + MessageBox(hwndDlg,"Port must be from 1 to 65535!","Winamp Web Interface",MB_OK); + SetDlgItemInt(hwndDlg,IDC_PORT_EDIT,con_port,false); + SetWindowLong(hwndDlg,DWL_MSGRESULT,true); + return true; + } + break; + } + break; + } + return false; +} + + +// -------------------------------------------------------------------------------- +// Web page options window proc +BOOL CALLBACK ConfigWebPageWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + char TempString[10]; + HANDLE img; + switch(uMsg) + { + case WM_INITDIALOG: + + wsprintf(TempString,"%d",title_refresh); + SetDlgItemText(hwndDlg,IDC_REFRESH,TempString); + SetDlgItemText(hwndDlg,IDC_PAGETITLE,pagetitle); + + /* + LONG SendDlgItemMessage( + HWND hDlg, // handle of dialog box + int nIDDlgItem, // identifier of control + UINT Msg, // message to send + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ); + */ + + + switch(frames) + { + case 1: CheckDlgButton(hwndDlg,IDC_NOFRAMES,1); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_FRAMES_ONE),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_FRAMEIMG,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + break; + case 3: CheckDlgButton(hwndDlg,IDC_THREEFRAMES,1); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_FRAMES_THREE),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_FRAMEIMG,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + break; + default: CheckDlgButton(hwndDlg,IDC_TWOFRAMES,1); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_FRAMES_TWO),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_FRAMEIMG,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + break; + } + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_PAGETITLEHELP: + MessageBox(hwndDlg,"Page Title...\n\nThis text is what appears as the title on the main page on a user's browser. It can be up to 255 characters long, but should be made to fit into the width of a page in the browser.\n\nHTML tags can be included.","Winamp Web Interface Help",MB_OK); + break; + case IDC_NOFRAMES: + if (HIWORD(wParam) == BN_CLICKED) + { + //MessageBox(hwndDlg,"No frames","wawi",MB_OK| MB_TOPMOST); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_FRAMES_ONE),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_FRAMEIMG,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + } + break; + case IDC_TWOFRAMES: + if (HIWORD(wParam) == BN_CLICKED) + { + //MessageBox(hwndDlg,"Two frames","wawi",MB_OK| MB_TOPMOST); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_FRAMES_TWO),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_FRAMEIMG,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + } + break; + case IDC_THREEFRAMES: + if (HIWORD(wParam) == BN_CLICKED) + { + //MessageBox(hwndDlg,"Three frames","wawi",MB_OK| MB_TOPMOST); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_FRAMES_THREE),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_FRAMEIMG,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + } + break; + + } + break; + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: GetDlgItemText(hwndDlg,IDC_PAGETITLE,(char*)pagetitle,255); + title_refresh = GetDlgItemInt(hwndDlg,IDC_REFRESH,NULL,false); + + if (IsDlgButtonChecked(hwndDlg,IDC_NOFRAMES)) + frames = 1; + else + if (IsDlgButtonChecked(hwndDlg,IDC_THREEFRAMES)) + frames = 3; + else + frames = 2; + + break; + } + break; + } + return false; +} + +// -------------------------------------------------------------------------------- +// Browse options window proc +BOOL CALLBACK ConfigBrowseWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int length; + switch(uMsg) + { + case WM_INITDIALOG: + CheckDlgButton(hwndDlg,IDC_WA_FILES_SHOW,1); + CheckDlgButton(hwndDlg,IDC_OTHER_FILES_SHOW,show_other_files); + CheckDlgButton(hwndDlg,IDC_WA_FILES_DL,dl_wa_files); + CheckDlgButton(hwndDlg,IDC_OTHER_FILES_DL,dl_other_files); + + SetDlgItemText(hwndDlg,IDC_MP3_ROOT,mp3root); + SetDlgItemText(hwndDlg,IDC_FILETYPES,filetypes); + SetDlgItemText(hwndDlg,IDC_PLAYLISTDIR,playlistdir); + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_ROOTDIRHELP: + MessageBox(hwndDlg,"Root Music Directory...\n\nEnter the path of the directory you want users to be able to browse. Any files and folders within this folder will appear in the Music Collection. Files and folders outside this folder will not be accessible.","Winamp Web Interface Help",MB_OK); + break; + case IDC_FILETYPEHELP: + MessageBox(hwndDlg,"Loadable Filetypes...\n\nEnter file extensions of files that winamp can play, separated by spaces. For example, entering \"mp3 wav mid\" will enable files with those extensions to be clicked on and played from the browser.\n\nIncluding 'url' will enable Wawi to follow internet shortcuts to load songs or streams rather than just treat them as non-winamp files.","Winamp Web Interface Help",MB_OK); + break; + case IDC_PLAYLISTDIRHELP: + MessageBox(hwndDlg,"Playlist Directory...\n\nWhen a playlist is saved from the web interface it is saved in this directory. The name given here is relative to the Root Music Directory; for example if the root directory is \"c:\\mp3\" and the playlist directory is \"playlists\", saved playlists will be stored in \"c:\\mp3\\playlists\\\".\n\nEnsure the directory exists before saving playlists into it!", "Winamp Web Interface Help", MB_OK); + break; + + } + break; + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: show_other_files = IsDlgButtonChecked(hwndDlg,IDC_OTHER_FILES_SHOW); + dl_other_files = IsDlgButtonChecked(hwndDlg,IDC_OTHER_FILES_DL); + dl_wa_files = IsDlgButtonChecked(hwndDlg,IDC_WA_FILES_DL); + + GetDlgItemText(hwndDlg,IDC_FILETYPES,(char*)filetypes,255); + + length = GetDlgItemText(hwndDlg,IDC_MP3_ROOT,(char*)mp3root,MAX_PATH); + if (mp3root[length-1] == '\\') + mp3root[length-1] = 0; // chop off trailing '\' + else + mp3root[length] = 0; // make null terminated + + length = GetDlgItemText(hwndDlg,IDC_PLAYLISTDIR,(char*)playlistdir,MAX_PATH); + if (playlistdir[length-1] == '\\') + playlistdir[length-1] = 0; // chop off trailing '\' + else + playlistdir[length] = 0; // make null terminated + + + break; + } + break; + } + return false; +} + + +// -------------------------------------------------------------------------------- +// Log options window proc +BOOL CALLBACK ConfigLogWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int length; + switch(uMsg) + { + case WM_INITDIALOG: + SetDlgItemText(hwndDlg,IDC_LOGFILEPATH,logfiledir); + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_VIEWLOG: ViewLog(); + break; + } + break; + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: length = GetDlgItemText(hwndDlg,IDC_LOGFILEPATH,(char*)logfiledir,MAX_PATH); + if (logfiledir[length-1] == '\\') + logfiledir[length-1] = 0; // chop off trailing '\' + else + logfiledir[length] = 0; // make null terminated + + + break; + } + break; + } + return false; +} + +// -------------------------------------------------------------------------------- +// About options window proc +BOOL CALLBACK ConfigAboutWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HANDLE img; + char title[100]; + switch(uMsg) + { + case WM_INITDIALOG: + ConfigWnd = (HWND) (((NMHDR FAR *) lParam)->hwndFrom); + img = LoadImage(plugin.hDllInstance,MAKEINTRESOURCE(IDB_TITLE),IMAGE_BITMAP,0,0,0); + SendDlgItemMessage(hwndDlg,IDC_MAINIMAGE,STM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)img); + CloseHandle(img); + wsprintf(title,"Winamp Web Interface %s",szAppVer); + SetDlgItemText(hwndDlg,IDC_ABOUT_TITLE,title); + + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: break; + default: break; + } + break; + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: + break; + } + break; + } + return false; +} + + +// -------------------------------------------------------------------------------- +// Loading / Saving of config +void config_read() +{ + char ini_file[MAX_PATH], *p; + GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"gen_httpsrv.ini"); + + con_port = GetPrivateProfileInt(szAppName,"Port",80,ini_file); + hide_error = GetPrivateProfileInt(szAppName,"HideErrors",0,ini_file); + frames = GetPrivateProfileInt(szAppName,"Frames",2,ini_file); + securepassword = GetPrivateProfileInt(szAppName,"SecurePassword",1,ini_file); + pass_debug = GetPrivateProfileInt(szAppName,"PassDebug",0,ini_file); + + show_other_files = GetPrivateProfileInt(szAppName,"ShowOtherFiles",0,ini_file); + dl_wa_files = GetPrivateProfileInt(szAppName,"DLWaFiles",0,ini_file); + dl_other_files = GetPrivateProfileInt(szAppName,"DLOtherFiles",0,ini_file); + + title_refresh = GetPrivateProfileInt(szAppName,"TitleRefresh",60,ini_file); + + GetPrivateProfileString(szAppName,"filetypes","mp3 wav m3u url",(char*)&filetypes,255,ini_file); + GetPrivateProfileString(szAppName,"pagetitle","... Winamp Web Interface ...",(char*)&pagetitle,255,ini_file); + GetPrivateProfileString(szAppName,"logfiledir","",(char*)&logfiledir,MAX_PATH,ini_file); + GetPrivateProfileString(szAppName,"playlistdir","",(char*)&playlistdir,MAX_PATH,ini_file); + + int length = GetPrivateProfileString(szAppName,"mp3root","c:\\",(char*)&mp3root,MAX_PATH,ini_file); + + if (mp3root[length-1] == '\\') + mp3root[length-1] = 0; // chop off trailing '\' + else + mp3root[length] = 0; // make null terminated + +} + +void config_write() +{ + char ini_file[MAX_PATH], *p; + char string[32]; + GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"gen_httpsrv.ini"); + + wsprintf(string,"%d",con_port); + WritePrivateProfileString(szAppName,"Port",string,ini_file); + wsprintf(string,"%d",hide_error); + WritePrivateProfileString(szAppName,"HideErrors",string,ini_file); + wsprintf(string,"%d",frames); + WritePrivateProfileString(szAppName,"Frames",string,ini_file); + wsprintf(string,"%d",securepassword); + WritePrivateProfileString(szAppName,"Securepassword",string,ini_file); + wsprintf(string,"%d",pass_debug); + WritePrivateProfileString(szAppName,"PassDebug",string,ini_file); + + wsprintf(string,"%d",title_refresh); + WritePrivateProfileString(szAppName,"TitleRefresh",string,ini_file); + + wsprintf(string,"%d",show_other_files); + WritePrivateProfileString(szAppName,"ShowOtherFiles",string,ini_file); + wsprintf(string,"%d",dl_other_files); + WritePrivateProfileString(szAppName,"DLOtherFiles",string,ini_file); + wsprintf(string,"%d",dl_wa_files); + WritePrivateProfileString(szAppName,"DLWaFiles",string,ini_file); + + WritePrivateProfileString(szAppName,"mp3root",mp3root,ini_file); + WritePrivateProfileString(szAppName,"pagetitle",pagetitle,ini_file); + WritePrivateProfileString(szAppName,"filetypes",filetypes,ini_file); + WritePrivateProfileString(szAppName,"logfiledir",logfiledir,ini_file); + WritePrivateProfileString(szAppName,"playlistdir",playlistdir,ini_file); + +} + + + + +// -------------------------------------------------------------------------------- +// Open log in user's favourite text editor - Registry! Aaargh! +void ViewLog() +{ + /* + + 'log' files might not have an association, so open it with whatever + program opens text files. + + - enumerate keys until '.log' is found + - if it's not, look for '.txt' + - find filetype (eg. txtfile) + - enumerate keys until 'filetype' is found + - read filetype\open\command + - if that goes arse over tit, just run 'notepad.exe <logfile>', but that's cheating. + + */ + + // Ah, sod it, let's just run notepad! + + + // Find log file, in winamp plugin directory (same dir as gen_httpsrv.dll) + char logfilepath[MAX_PATH], *p; + + if (lstrlen(logfiledir) == 0) + { + GetModuleFileName(plugin.hDllInstance,logfilepath,sizeof(logfilepath)); + p=logfilepath+lstrlen(logfilepath); + while (p >= logfilepath && *p != '\\') p--; + if (++p >= logfilepath) *p = 0; + } + else + { + lstrcpy(logfilepath,logfiledir); + lstrcat(logfilepath,"\\"); + } + + char logfilecmd[MAX_PATH]; + //lstrcat(logfile,"gen_httpsrv_log.log); + wsprintf(logfilecmd,"notepad.exe %shttpsrv.log",logfilepath); + + WinExec(logfilecmd,SW_SHOWDEFAULT); + +} + + +BOOL CALLBACK NewConfigWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + return false; +} + +// -------------------------------------------------------------------------------- +// Entry point for new Config window, using Property Sheets instead of a single dialog. +void NewConfig() +{ + PROPSHEETPAGE psp[6]; + PROPSHEETHEADER psh; + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[0].hInstance = plugin.hDllInstance; + psp[0].pszTemplate = MAKEINTRESOURCE(IDD_ABOUT); + psp[0].pszIcon = MAKEINTRESOURCE(IDI_WINAMP); + psp[0].pfnDlgProc = ConfigAboutWndProc; + psp[0].pszTitle = "About WAWI"; + psp[0].lParam = 0; + psp[0].pfnCallback = NULL; + + psp[1].dwSize = sizeof(PROPSHEETPAGE); + psp[1].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[1].hInstance = plugin.hDllInstance; + psp[1].pszTemplate = MAKEINTRESOURCE(IDD_SERVER); + psp[1].pszIcon = MAKEINTRESOURCE(IDI_SERVER); + psp[1].pfnDlgProc = ConfigServerWndProc; + psp[1].pszTitle = "Server"; + psp[1].lParam = 0; + psp[1].pfnCallback = NULL; + + psp[2].dwSize = sizeof(PROPSHEETPAGE); + psp[2].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[2].hInstance = plugin.hDllInstance; + psp[2].pszTemplate = MAKEINTRESOURCE(IDD_USERS); + psp[2].pszIcon = MAKEINTRESOURCE(IDI_USERS); + psp[2].pfnDlgProc = ConfigUsersWndProc; + psp[2].pszTitle = "Users"; + psp[2].lParam = 0; + psp[2].pfnCallback = NULL; + + psp[3].dwSize = sizeof(PROPSHEETPAGE); + psp[3].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[3].hInstance = plugin.hDllInstance; + psp[3].pszTemplate = MAKEINTRESOURCE(IDD_WEBPAGE); + psp[3].pszIcon = MAKEINTRESOURCE(IDI_WEBPAGE); + psp[3].pfnDlgProc = ConfigWebPageWndProc; + psp[3].pszTitle = "Web Page"; + psp[3].lParam = 0; + psp[3].pfnCallback = NULL; + + psp[4].dwSize = sizeof(PROPSHEETPAGE); + psp[4].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[4].hInstance = plugin.hDllInstance; + psp[4].pszTemplate = MAKEINTRESOURCE(IDD_BROWSE); + psp[4].pszIcon = MAKEINTRESOURCE(IDI_BROWSE); + psp[4].pfnDlgProc = ConfigBrowseWndProc; + psp[4].pszTitle = "Music Collection"; + psp[4].lParam = 0; + psp[4].pfnCallback = NULL; + + psp[5].dwSize = sizeof(PROPSHEETPAGE); + psp[5].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[5].hInstance = plugin.hDllInstance; + psp[5].pszTemplate = MAKEINTRESOURCE(IDD_LOG); + psp[5].pszIcon = MAKEINTRESOURCE(IDI_LOG); + psp[5].pfnDlgProc = ConfigLogWndProc; + psp[5].pszTitle = "Log"; + psp[5].lParam = 0; + psp[5].pfnCallback = NULL; + + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE; + psh.hwndParent = plugin.hwndParent; + psh.hInstance = plugin.hDllInstance; + psh.pszIcon = NULL; + psh.pszCaption = "Winamp Web Interface Config"; + psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); + psh.nStartPage = 0; + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + psh.pfnCallback = NULL; + + PropertySheet(&psh); + config_write(); + ConfigWnd = NULL; + return; +} \ No newline at end of file diff --git a/Wawi Source/Config_users.cpp b/Wawi Source/Config_users.cpp new file mode 100644 index 0000000..6af3c70 --- /dev/null +++ b/Wawi Source/Config_users.cpp @@ -0,0 +1,345 @@ +/* --- CONFIG_USERS.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include "types.h" +#include "main.h" +#include "resource.h" +#include "plugin.h" + +extern winampGeneralPurposePlugin plugin; + +int securepassword; +int pass_debug; + +extern HWND UsersWnd; + +// -------------------------------------------------------------------------------- +// WindowProc for Config dialog +BOOL CALLBACK ConfigUsersWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + int nItem; + HWND hwndList; + + UsersWnd = hwndDlg; + + + char ini_file[MAX_PATH], *p; + hwndList = GetDlgItem(hwndDlg, IDC_USERS); + GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"gen_httpsrv.ini"); + + switch (uMsg) + { + case WM_INITDIALOG: + + UpdateUserList((char*)&ini_file, hwndList); + + PostMessage(hwndList,LB_SETCURSEL,0,0); + UpdateUserInfoBoxes(hwndDlg,hwndList,ini_file,0); + + break; + + + + + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_USERS: + switch (HIWORD(wParam)) + { + case LBN_SELCHANGE: + hwndList = GetDlgItem(hwndDlg, IDC_USERS); + nItem = SendMessage(hwndList, LB_GETCURSEL, 0, 0); + UpdateUserInfoBoxes(hwndDlg,hwndList,ini_file,nItem); + + break; + } + + break; + case IDC_UPDATE: + UpdateDlgUser((char*)&ini_file, hwndDlg, hwndList); + UpdateUserList((char*)&ini_file, hwndList); + break; + + case IDC_DELETE: + DeleteDlgUser((char*)&ini_file, hwndDlg, hwndList); + UpdateUserList((char*)&ini_file, hwndList); + UpdateUserInfoBoxes(hwndDlg,hwndList,(char*)&ini_file,0); + break; + + } + break; + + } + return false; +} + +// -------------------------------------------------------------------------------- +// Enters use details into relevant boxes +void UpdateUserInfoBoxes(HWND hwndDlg, HWND hwndList, char * ini_file, int item) +{ + char userkey[30]; + char username[20]; + char password[40]; + int access; + + SendMessage(hwndList,LB_GETTEXT, item, (LPARAM)&username); + + SetDlgItemText(hwndDlg,IDC_USERNAME,username); + GetPrivateProfileString("Users",username,"password",(char*)&password,40,ini_file); + if (StrComp(username,"anon")) + SetDlgItemText(hwndDlg,IDC_PASSWORD,""); + else + SetDlgItemText(hwndDlg,IDC_PASSWORD,password); + + wsprintf(userkey, "#%s_access", username); + access = GetPrivateProfileInt("Users",userkey,AUTH_ANON,ini_file); + + DisplayDlgAccess(hwndDlg,access); + +} + +// -------------------------------------------------------------------------------- +// Marks check boxes according to user access levels +void DisplayDlgAccess(HWND hwndDlg, int access) +{ + if (access & AUTH_SERVER) + CheckDlgButton(hwndDlg,IDC_AUTH_SHUTDOWN,BST_CHECKED); + else + CheckDlgButton(hwndDlg,IDC_AUTH_SHUTDOWN,BST_UNCHECKED); + + if (access & AUTH_CONTROL) + CheckDlgButton(hwndDlg,IDC_AUTH_CONTROL,BST_CHECKED); + else + CheckDlgButton(hwndDlg,IDC_AUTH_CONTROL,BST_UNCHECKED); + + if (access & AUTH_CLEAR) + CheckDlgButton(hwndDlg,IDC_AUTH_CLEAR,BST_CHECKED); + else + CheckDlgButton(hwndDlg,IDC_AUTH_CLEAR,BST_UNCHECKED); + + if (access & AUTH_PLAYLIST) + CheckDlgButton(hwndDlg,IDC_AUTH_PLAYLIST,BST_CHECKED); + else + CheckDlgButton(hwndDlg,IDC_AUTH_PLAYLIST,BST_UNCHECKED); + + if (access & AUTH_DOWNLOAD) + CheckDlgButton(hwndDlg,IDC_AUTH_DOWNLOAD,BST_CHECKED); + else + CheckDlgButton(hwndDlg,IDC_AUTH_DOWNLOAD,BST_UNCHECKED); + + if (access & AUTH_BROWSE) + CheckDlgButton(hwndDlg,IDC_AUTH_BROWSE,BST_CHECKED); + else + CheckDlgButton(hwndDlg,IDC_AUTH_BROWSE,BST_UNCHECKED); +} + +// -------------------------------------------------------------------------------- +// Retrieves user access from check boxes +int GetDlgAccess(HWND hwndDlg) +{ + int access = 0; + if (IsDlgButtonChecked(hwndDlg,IDC_AUTH_BROWSE) == BST_CHECKED) + access += 1; + if (IsDlgButtonChecked(hwndDlg,IDC_AUTH_DOWNLOAD) == BST_CHECKED) + access += 2; + if (IsDlgButtonChecked(hwndDlg,IDC_AUTH_PLAYLIST) == BST_CHECKED) + access += 4; + if (IsDlgButtonChecked(hwndDlg,IDC_AUTH_CLEAR) == BST_CHECKED) + access += 8; + if (IsDlgButtonChecked(hwndDlg,IDC_AUTH_CONTROL) == BST_CHECKED) + access += 16; + if (IsDlgButtonChecked(hwndDlg,IDC_AUTH_SERVER) == BST_CHECKED) + access += 32; + + return access; +} + +// -------------------------------------------------------------------------------- +// Builds a list of usernames from the ini file +user * RetrieveUsers(user * users, char * ini_file) +{ + bool anon = false; + int userslen, uptr, tptr; + char t_users[10000]; + + userslen = GetPrivateProfileSection("Users",(char*)t_users,10000,ini_file); + uptr = 0; + tptr = 0; + + while(uptr < userslen) // until we're done + { + // weedle through to the end, replacing the equals sign as we go. + tptr = uptr; + //MessageBox(NULL,users+uptr,"start of section",MB_OK | MB_TOPMOST); + while(t_users[tptr] != 0) + { + if (t_users[tptr] == '=') // equals - make it a null + t_users[tptr] = 0; + tptr++; + } + if (StrComp("anon",t_users+uptr)) + anon = true; + user * newuser = new user; + lstrcpy(newuser->name,t_users+uptr); + newuser->next = users; + users = newuser; + + tptr++; // move to char after null + //if (users[tptr] == 0) // if it's null too, that's the lot; end + // break; + if (t_users[tptr] == '#') // if it's a hash, it's the access level - skip it + { + while(t_users[tptr] != 0) + tptr++; + tptr++; + // if (users[tptr] == 0) // if that's null it's the end + // break; + } + + + uptr = tptr; // move on to next + } + + if (!anon) // anonymous user has not been added; add it + { + user * anonuser = new user; + lstrcpy(anonuser->name,"anon"); + anonuser->next = users; + users = anonuser; + } + + return users; +} + + +// -------------------------------------------------------------------------------- +// Enters usernames into the dialog box list +void UpdateUserList(char * ini_file, HWND hwndList) +{ + + SendMessage(hwndList, LB_RESETCONTENT, 0, 0); + + user * users = NULL; + users = RetrieveUsers(users, ini_file); // fill list 'users' with usernames + user * current = users; // pointer to start of list + + while(current != NULL) + { + SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM) (current->name)); // add it + current = current->next; + delete users; + users = current; + } +} + + + +// -------------------------------------------------------------------------------- +// Updates user information in the ini file +void UpdateDlgUser(char * ini_file, HWND hwndDlg, HWND hwndList) +{ + + char username[20]; + char password[40]; + + int access = GetDlgAccess(hwndDlg); + + GetDlgItemText(hwndDlg,IDC_USERNAME,(char*)&username,20); + GetDlgItemText(hwndDlg,IDC_PASSWORD,(char*)&password,40); + + if (StrComp(password,"password")) + { + MessageBox(hwndDlg,"Choosing a slightly better password than 'password' provides better security.","WAWI User Config",MB_OK | MB_ICONINFORMATION); + return; + } + + UpdateUser(ini_file,username,password,access); +} + +// -------------------------------------------------------------------------------- +// Adds/updates user with passed-in information +void UpdateUser(char * ini_file,char * username, char * password, int access) +{ + + char debugtemp[100]; + char oldmd5password[40]; + char md5password[40]; + char userkey[30]; + char str_access[5]; + + wsprintf(str_access,"%d",access); + + if (pass_debug == 1) + { + wsprintf(debugtemp,"User: %s\nPassword: %s\nAccess: %d",username,password,access); + MessageBox(NULL,debugtemp,"WAWI Password Debug",MB_OK | MB_TOPMOST); + } + + wsprintf(userkey,"#%s_access",username); + if (securepassword == 1) + { + MD5(password,(char*)&md5password,40); + if (pass_debug == 1) + { + wsprintf(debugtemp,"MD5 encoded: %s",md5password); + MessageBox(NULL,debugtemp,"WAWI Password Debug",MB_OK | MB_TOPMOST); + } + } + else + { + ToBase64(password,(char*)&md5password); + if (pass_debug == 1) + { + wsprintf(debugtemp,"Base64 encoded: %s",md5password); + MessageBox(NULL,debugtemp,"WAWI Password Debug",MB_OK | MB_TOPMOST); + } + } + + GetPrivateProfileString("Users",username,"password",(char*)&oldmd5password,40,ini_file); + if (pass_debug == 1) + { + wsprintf(debugtemp,"Previous password (or 'password' if none):\n%s",oldmd5password); + MessageBox(NULL,debugtemp,"WAWI Password Debug",MB_OK | MB_TOPMOST); + } + + if (!StrComp(password,oldmd5password)) + { + WritePrivateProfileString("Users",username,md5password,ini_file); + if (pass_debug == 1) + { + wsprintf(debugtemp,"Written to gen_httpsrv.ini - \nUser: %s\nPassword: %s",username,md5password); + MessageBox(NULL,debugtemp,"WAWI Password Debug",MB_OK | MB_TOPMOST); + } + } + WritePrivateProfileString("Users",userkey,str_access,ini_file); +} + +// -------------------------------------------------------------------------------- +// Deletes a user from the user dialog +void DeleteDlgUser(char * ini_file, HWND hwndDlg, HWND hwndList) +{ + char username[20]; + + GetDlgItemText(hwndDlg,IDC_USERNAME,(char*)&username,20); + DeleteUser(ini_file,username); +} + +// -------------------------------------------------------------------------------- +// Deletes a user +void DeleteUser(char * ini_file, char * username) +{ + char userkey[30]; + wsprintf(userkey,"#%s_access",username); + WritePrivateProfileString("Users",username,NULL,ini_file); + WritePrivateProfileString("Users",userkey,NULL,ini_file); +} diff --git a/Wawi Source/DeletePlaylistEntry.cpp b/Wawi Source/DeletePlaylistEntry.cpp new file mode 100644 index 0000000..1e9d13c --- /dev/null +++ b/Wawi Source/DeletePlaylistEntry.cpp @@ -0,0 +1,231 @@ +/* --- DELETEPLAYLISTENTRY.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> + +#include "types.h" +#include "main.h" +#include "html.h" +#include "plugin.h" +#include "wamessage.h" + +// -------------------------------------------------------------------------------- +// Delete a playlist entry by manipulating the playlist file. +// No longer used; replaced by DeletePlaylistEntry2 (below) which is much shorter and easier! +int DeletePlaylistEntry(int track) +{ + // Get current position and save playlist to winamp.m3u + int plcount = SendMessage(WAwnd(),WM_USER,0,WAU_PLCOUNT); + int plpos = SendMessage(WAwnd(),WM_USER,0,WAU_PLSAVE); + + + // Find winamp.m3u; it's in the same dir as exe of current process. + DWORD wapid = GetWindowThreadProcessId(WAwnd(),NULL); + HMODULE hMod = (HMODULE)OpenProcess(PROCESS_ALL_ACCESS,false,wapid); + + char playlistfile[MAX_PATH], *p; + GetModuleFileName(hMod,playlistfile,sizeof(playlistfile)); + CloseHandle(hMod); + + // Make \path\winamp.exe into \path\winamp.m3u + p=playlistfile+lstrlen(playlistfile); + while (p >= playlistfile && *p != '\\') p--; + if (++p >= playlistfile) *p = 0; + lstrcat(playlistfile,"winamp.m3u"); + + + /* Right then, that's the playlist file extracted and found. + - read playlist into memory - linked list + - scan through list writing back to playlist file + - don't write back track to delete + - reload playlist. As easy as that... + */ + + + HANDLE hFile = CreateFile( playlistfile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + return DPE_NOREAD; + + // Put entire file into a char array + DWORD dwSize = GetFileSize(hFile, NULL); + char * cplaylist = new char[dwSize]; + DWORD read; + ReadFile(hFile,cplaylist,dwSize,&read,NULL); + CloseHandle(hFile); + + // playlist file is now in cplaylist; scan through and put in a 'playlist' structure + + + char * chptr = cplaylist; + char temp[MAX_PATH]; + + playlistitem * startitem = NULL; + playlistitem * currentitem = startitem; + + for (int i=1;i<=plcount;i++) + { + + playlistitem * newitem = new playlistitem; + newitem->next = NULL; + newitem->number = i; + + // skip '#EXTINF:' + chptr = GetDelimitedString(chptr,':',temp,MAX_PATH); + chptr++; + + // get time + chptr = GetDelimitedString(chptr,',',newitem->time,10); + chptr++; + // get title + chptr = GetDelimitedString(chptr,'\r',newitem->name,MAX_PATH); + chptr++; + chptr++; + + // get path + chptr = GetDelimitedString(chptr,'\r',newitem->path,MAX_PATH); + + if (startitem == NULL) + { + startitem = newitem; + currentitem = newitem; + } + else + { + currentitem->next = newitem; + currentitem = newitem; + } + } + + // hopefully the list is complete here. + + // Open winamp.m3u for writing + hFile = CreateFile( playlistfile, + GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + FreePlaylist(startitem); + return DPE_NOWRITE; + } + + // Write it back into cplaylist. It'll be shorter, obviously, so it'll fit + wsprintf(cplaylist,"#EXTM3U\r\n"); + currentitem = startitem; + while(currentitem != NULL) + { + if (currentitem->number != track) + { + wsprintf(temp,"#EXTINF:%s,%s\r\n%s\r\n",currentitem->time,currentitem->name,currentitem->path); + lstrcat(cplaylist,temp); + } + currentitem = currentitem->next; + } + + // Write playlist to file + DWORD written; + WriteFile(hFile,cplaylist,lstrlen(cplaylist),&written,NULL); + CloseHandle(hFile); + delete cplaylist; + + // free memory of linked list + FreePlaylist(startitem); + + // clear current playlist and reload it + SendMessage(WAwnd(),WM_USER,0,WAU_CLEARPLIST); + + int pathlen = lstrlen(playlistfile); + COPYDATASTRUCT cds; + cds.dwData = IPC_PLAYFILE; + cds.lpData = (void *)&playlistfile; + cds.cbData = pathlen+1; + SendMessage(WAwnd(),WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds); + + + // return to old position in list + if (plpos >= track) + plpos--; + SendMessage(WAwnd(),WM_USER,plpos,WAU_SETPLPOS); + + return DPE_OK; + +} + +// -------------------------------------------------------------------------------- +// Delete linked list after it's done with +void FreePlaylist(playlistitem * startitem) +{ + playlistitem * current = startitem; + + while(current != NULL) + { + startitem = current->next; + delete current; + current = startitem; + } +} + +// -------------------------------------------------------------------------------- +// Delete using Playlist window messages +int DeletePlaylistEntry2(connection * conn, int track) +{ + HWND PLwnd = FindWindow("Winamp PE",NULL); + if (!PLwnd) + { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + // Process any inserts in lpMsgBuf. + // ... + // Display the string. + MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); + // Free the buffer. + LocalFree( lpMsgBuf ); + } + + + SendMessage(PLwnd,WM_USER,104,track); + + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + wsprintf(refreshto,"/list"); + + RefreshHeader(conn,refreshto); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Track"); + printsi(conn,track); + prints(conn," deleted</p>"); + + return ST_CLOSEBODY; + +} \ No newline at end of file diff --git a/Wawi Source/HTTPServer.exe b/Wawi Source/HTTPServer.exe new file mode 100644 index 0000000..2973c57 Binary files /dev/null and b/Wawi Source/HTTPServer.exe differ diff --git a/Wawi Source/Images/OK.gif b/Wawi Source/Images/OK.gif new file mode 100644 index 0000000..43a7b51 Binary files /dev/null and b/Wawi Source/Images/OK.gif differ diff --git a/Wawi Source/Images/Title Graphic/Wawi.jpg b/Wawi Source/Images/Title Graphic/Wawi.jpg new file mode 100644 index 0000000..39dc453 Binary files /dev/null and b/Wawi Source/Images/Title Graphic/Wawi.jpg differ diff --git a/Wawi Source/Images/about.gif b/Wawi Source/Images/about.gif new file mode 100644 index 0000000..17a54d0 Binary files /dev/null and b/Wawi Source/Images/about.gif differ diff --git a/Wawi Source/Images/admin.gif b/Wawi Source/Images/admin.gif new file mode 100644 index 0000000..2d2436a Binary files /dev/null and b/Wawi Source/Images/admin.gif differ diff --git a/Wawi Source/Images/black.gif b/Wawi Source/Images/black.gif new file mode 100644 index 0000000..185d95b Binary files /dev/null and b/Wawi Source/Images/black.gif differ diff --git a/Wawi Source/Images/browse.gif b/Wawi Source/Images/browse.gif new file mode 100644 index 0000000..6e327dd Binary files /dev/null and b/Wawi Source/Images/browse.gif differ diff --git a/Wawi Source/Images/frames_one.bmp b/Wawi Source/Images/frames_one.bmp new file mode 100644 index 0000000..a300200 Binary files /dev/null and b/Wawi Source/Images/frames_one.bmp differ diff --git a/Wawi Source/Images/frames_one_lg.bmp b/Wawi Source/Images/frames_one_lg.bmp new file mode 100644 index 0000000..2ab4591 Binary files /dev/null and b/Wawi Source/Images/frames_one_lg.bmp differ diff --git a/Wawi Source/Images/frames_three.bmp b/Wawi Source/Images/frames_three.bmp new file mode 100644 index 0000000..0807cb3 Binary files /dev/null and b/Wawi Source/Images/frames_three.bmp differ diff --git a/Wawi Source/Images/frames_three_lg.bmp b/Wawi Source/Images/frames_three_lg.bmp new file mode 100644 index 0000000..d4f3604 Binary files /dev/null and b/Wawi Source/Images/frames_three_lg.bmp differ diff --git a/Wawi Source/Images/frames_two.bmp b/Wawi Source/Images/frames_two.bmp new file mode 100644 index 0000000..97c2b5a Binary files /dev/null and b/Wawi Source/Images/frames_two.bmp differ diff --git a/Wawi Source/Images/frames_two_lg.bmp b/Wawi Source/Images/frames_two_lg.bmp new file mode 100644 index 0000000..d2f859d Binary files /dev/null and b/Wawi Source/Images/frames_two_lg.bmp differ diff --git a/Wawi Source/Images/list_delete.gif b/Wawi Source/Images/list_delete.gif new file mode 100644 index 0000000..51ade2d Binary files /dev/null and b/Wawi Source/Images/list_delete.gif differ diff --git a/Wawi Source/Images/list_play.gif b/Wawi Source/Images/list_play.gif new file mode 100644 index 0000000..e32a6bb Binary files /dev/null and b/Wawi Source/Images/list_play.gif differ diff --git a/Wawi Source/Images/main.gif b/Wawi Source/Images/main.gif new file mode 100644 index 0000000..5884aaa Binary files /dev/null and b/Wawi Source/Images/main.gif differ diff --git a/Wawi Source/Images/next.gif b/Wawi Source/Images/next.gif new file mode 100644 index 0000000..123c411 Binary files /dev/null and b/Wawi Source/Images/next.gif differ diff --git a/Wawi Source/Images/pause.gif b/Wawi Source/Images/pause.gif new file mode 100644 index 0000000..92e69d2 Binary files /dev/null and b/Wawi Source/Images/pause.gif differ diff --git a/Wawi Source/Images/play.gif b/Wawi Source/Images/play.gif new file mode 100644 index 0000000..8305f45 Binary files /dev/null and b/Wawi Source/Images/play.gif differ diff --git a/Wawi Source/Images/playlist.gif b/Wawi Source/Images/playlist.gif new file mode 100644 index 0000000..a81b5d7 Binary files /dev/null and b/Wawi Source/Images/playlist.gif differ diff --git a/Wawi Source/Images/popup.gif b/Wawi Source/Images/popup.gif new file mode 100644 index 0000000..9204373 Binary files /dev/null and b/Wawi Source/Images/popup.gif differ diff --git a/Wawi Source/Images/prev.gif b/Wawi Source/Images/prev.gif new file mode 100644 index 0000000..175d003 Binary files /dev/null and b/Wawi Source/Images/prev.gif differ diff --git a/Wawi Source/Images/randomoff.gif b/Wawi Source/Images/randomoff.gif new file mode 100644 index 0000000..e761402 Binary files /dev/null and b/Wawi Source/Images/randomoff.gif differ diff --git a/Wawi Source/Images/randomon.gif b/Wawi Source/Images/randomon.gif new file mode 100644 index 0000000..858b4e6 Binary files /dev/null and b/Wawi Source/Images/randomon.gif differ diff --git a/Wawi Source/Images/repeatoff.gif b/Wawi Source/Images/repeatoff.gif new file mode 100644 index 0000000..e158d64 Binary files /dev/null and b/Wawi Source/Images/repeatoff.gif differ diff --git a/Wawi Source/Images/repeaton.gif b/Wawi Source/Images/repeaton.gif new file mode 100644 index 0000000..012821a Binary files /dev/null and b/Wawi Source/Images/repeaton.gif differ diff --git a/Wawi Source/Images/stop.gif b/Wawi Source/Images/stop.gif new file mode 100644 index 0000000..dddb484 Binary files /dev/null and b/Wawi Source/Images/stop.gif differ diff --git a/Wawi Source/Images/stopslow.gif b/Wawi Source/Images/stopslow.gif new file mode 100644 index 0000000..76a636c Binary files /dev/null and b/Wawi Source/Images/stopslow.gif differ diff --git a/Wawi Source/Images/vol0.gif b/Wawi Source/Images/vol0.gif new file mode 100644 index 0000000..032f2ea Binary files /dev/null and b/Wawi Source/Images/vol0.gif differ diff --git a/Wawi Source/Images/vol1.gif b/Wawi Source/Images/vol1.gif new file mode 100644 index 0000000..2dd49e4 Binary files /dev/null and b/Wawi Source/Images/vol1.gif differ diff --git a/Wawi Source/Images/vol10.gif b/Wawi Source/Images/vol10.gif new file mode 100644 index 0000000..fd18b15 Binary files /dev/null and b/Wawi Source/Images/vol10.gif differ diff --git a/Wawi Source/Images/vol2.gif b/Wawi Source/Images/vol2.gif new file mode 100644 index 0000000..90b0589 Binary files /dev/null and b/Wawi Source/Images/vol2.gif differ diff --git a/Wawi Source/Images/vol3.gif b/Wawi Source/Images/vol3.gif new file mode 100644 index 0000000..43cb09c Binary files /dev/null and b/Wawi Source/Images/vol3.gif differ diff --git a/Wawi Source/Images/vol4.gif b/Wawi Source/Images/vol4.gif new file mode 100644 index 0000000..9581c54 Binary files /dev/null and b/Wawi Source/Images/vol4.gif differ diff --git a/Wawi Source/Images/vol5.gif b/Wawi Source/Images/vol5.gif new file mode 100644 index 0000000..a2cda11 Binary files /dev/null and b/Wawi Source/Images/vol5.gif differ diff --git a/Wawi Source/Images/vol6.gif b/Wawi Source/Images/vol6.gif new file mode 100644 index 0000000..f4c4275 Binary files /dev/null and b/Wawi Source/Images/vol6.gif differ diff --git a/Wawi Source/Images/vol7.gif b/Wawi Source/Images/vol7.gif new file mode 100644 index 0000000..99dea72 Binary files /dev/null and b/Wawi Source/Images/vol7.gif differ diff --git a/Wawi Source/Images/vol8.gif b/Wawi Source/Images/vol8.gif new file mode 100644 index 0000000..de0e0ee Binary files /dev/null and b/Wawi Source/Images/vol8.gif differ diff --git a/Wawi Source/Images/vol9.gif b/Wawi Source/Images/vol9.gif new file mode 100644 index 0000000..ffd9b01 Binary files /dev/null and b/Wawi Source/Images/vol9.gif differ diff --git a/Wawi Source/Images/volume-all.bmp b/Wawi Source/Images/volume-all.bmp new file mode 100644 index 0000000..923da17 Binary files /dev/null and b/Wawi Source/Images/volume-all.bmp differ diff --git a/Wawi Source/Images/wa.ico b/Wawi Source/Images/wa.ico new file mode 100644 index 0000000..f11456c Binary files /dev/null and b/Wawi Source/Images/wa.ico differ diff --git a/Wawi Source/Images/winamp.ico b/Wawi Source/Images/winamp.ico new file mode 100644 index 0000000..3f19ac6 Binary files /dev/null and b/Wawi Source/Images/winamp.ico differ diff --git a/Wawi Source/Images/world.gif b/Wawi Source/Images/world.gif new file mode 100644 index 0000000..19a73b0 Binary files /dev/null and b/Wawi Source/Images/world.gif differ diff --git a/Wawi Source/Log.ico b/Wawi Source/Log.ico new file mode 100644 index 0000000..f6cab08 Binary files /dev/null and b/Wawi Source/Log.ico differ diff --git a/Wawi Source/Operations.txt b/Wawi Source/Operations.txt new file mode 100644 index 0000000..922dd0c --- /dev/null +++ b/Wawi Source/Operations.txt @@ -0,0 +1,51 @@ +Winamp Control + +/play[?nnn] Plays current track if no argument is given, or plays + the track at playlist position nnn. Also resumes playback + if Winamp is paused. +/prev Previous Track +/next Next Track +/pause Pause / Resume +/stop Stop +/stopslow Stops with fadeout +/vol?nn Sets the volume. <nn> is a number between 0 and 10 where + 0 is mute and 10 is full volume. + +Playlist control + +/clear Clears playlist +/url?l&<url> Loads a HTTP location at <url> into the playlist +/url?p&<url> Loads a HTTP location at <url> into the playlist and plays it. +/sct?xxxxxxxxx.url Loads a URL shortcut file + + +Other pages + +/list Returns current playlist +/img?nnn Image number nnn +/top Graphic link bar +/browse?\path\ Browse music collection at "%mp3_root_dir%\path\" +/about Returns a little 'about' page +/main Main page, with title and current track information + + +Unlinked + +/smalltitle Returns the artist and title of the playing track. No HTML + formatting; just the HTTP header and a line of text. +/title Returns a HTML page of the track information - artist, title, + state of playback (playing, paused, stopped), track time. + Automatically refreshes. +/login Brings up a username & password box every time; can be used + to log out. + + +Still in development - they might work, they might not... + +/shutdown Turns off the computer +/dl?\path\file Download a file at "%mp3_root_dir%\path\file" + + +Anything else returns the frameset to load the top link bar and the main page. + + diff --git a/Wawi Source/Resource.rc b/Wawi Source/Resource.rc new file mode 100644 index 0000000..aca4ff0 --- /dev/null +++ b/Wawi Source/Resource.rc @@ -0,0 +1,411 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// IMAGE +// + +IDR_DIRECTORY IMAGE DISCARDABLE "dir.gif" +IDR_WAFILE IMAGE DISCARDABLE "wafile.gif" +IDR_PLAYLIST IMAGE DISCARDABLE "playlist.gif" +IDR_FILE IMAGE DISCARDABLE "file.gif" +IDR_IMG_ABOUT IMAGE DISCARDABLE "Images\\about.gif" +IDR_IMG_STOP IMAGE DISCARDABLE "Images\\stop.gif" +IDR_IMG_MAIN IMAGE DISCARDABLE "Images\\main.gif" +IDR_IMG_NEXT IMAGE DISCARDABLE "Images\\next.gif" +IDR_IMG_PAUSE IMAGE DISCARDABLE "Images\\pause.gif" +IDR_IMG_PLAY IMAGE DISCARDABLE "Images\\play.gif" +IDR_IMG_PLAYLIST IMAGE DISCARDABLE "Images\\playlist.gif" +IDR_IMG_PREV IMAGE DISCARDABLE "Images\\prev.gif" +IDR_IMG_BROWSE IMAGE DISCARDABLE "Images\\browse.gif" +IDR_IMG_BLACK IMAGE DISCARDABLE "Images\\black.gif" +IDR_VOL_09 IMAGE DISCARDABLE "Images\\vol9.gif" +IDR_VOL_10 IMAGE DISCARDABLE "Images\\vol10.gif" +IDR_VOL_02 IMAGE DISCARDABLE "Images\\vol2.gif" +IDR_VOL_03 IMAGE DISCARDABLE "Images\\vol3.gif" +IDR_VOL_04 IMAGE DISCARDABLE "Images\\vol4.gif" +IDR_VOL_05 IMAGE DISCARDABLE "Images\\vol5.gif" +IDR_VOL_06 IMAGE DISCARDABLE "Images\\vol6.gif" +IDR_VOL_07 IMAGE DISCARDABLE "Images\\vol7.gif" +IDR_VOL_08 IMAGE DISCARDABLE "Images\\vol8.gif" +IDR_VOL_01 IMAGE DISCARDABLE "Images\\vol1.gif" +IDR_VOL_00 IMAGE DISCARDABLE "Images\\vol0.gif" +IDR_IMG_STOPSLOW IMAGE DISCARDABLE "Images\\stopslow.gif" +IDR_ICO_WINAMP IMAGE DISCARDABLE "Images\\wa.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_USERS DIALOGEX 0, 0, 220, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Manage Users" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LISTBOX IDC_USERS,23,39,173,54,LBS_SORT | LBS_NOINTEGRALHEIGHT | + NOT WS_BORDER | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE + EDITTEXT IDC_USERNAME,66,100,130,12,ES_AUTOHSCROLL | NOT + WS_BORDER,WS_EX_STATICEDGE + EDITTEXT IDC_PASSWORD,66,119,130,12,ES_PASSWORD | ES_AUTOHSCROLL | + NOT WS_BORDER,WS_EX_STATICEDGE + RTEXT "User",IDC_STATIC,27,102,31,10 + RTEXT "Password",IDC_STATIC,26,121,32,10 + PUSHBUTTON "Add/Update",IDC_UPDATE,150,146,46,15 + CONTROL "Server",IDC_AUTH_SERVER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,23,147,47,10 + CONTROL "Play",IDC_AUTH_CONTROL,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,23,158,48,10 + CONTROL "Add files",IDC_AUTH_PLAYLIST,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,88,147,50,10 + CONTROL "Download",IDC_AUTH_DOWNLOAD,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,88,158,48,10 + CONTROL "Browse",IDC_AUTH_BROWSE,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,88,169,50,10 + PUSHBUTTON "Delete",IDC_DELETE,150,162,46,15 + LTEXT "Select a user and update their permissions using the boxes below.", + IDC_STATIC,15,19,187,18 + CONTROL "Remove Files",IDC_AUTH_CLEAR,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,23,169,59,10 + GROUPBOX "User Management",IDC_STATIC,7,7,206,187 +END + +IDD_SERVER DIALOGEX 0, 0, 220, 201 +STYLE WS_CHILD | WS_CAPTION | WS_SYSMENU +CAPTION "WAWI Config : Server Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Network Settings",IDC_STATIC,7,7,206,92 + RTEXT "Port:",IDC_STATIC,61,66,16,8 + EDITTEXT IDC_PORT_EDIT,83,65,30,12,ES_AUTOHSCROLL | ES_NUMBER | + NOT WS_BORDER,WS_EX_STATICEDGE + CONTROL "Hide error message if an error occurs",IDC_HIDE_ERROR, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,81,140,10 + LTEXT "Change the port the server runs on. The default is 80; however if you run another web server you probably want to change it.", + IDC_STATIC,13,19,184,26 + LTEXT "Winamp must be restarted before a change will take effect.", + IDC_STATIC,13,49,193,12 + GROUPBOX "Password Storage",IDC_STATIC,7,105,206,75 + CONTROL "Secure Passwords",IDC_SECUREPASSWORD,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,26,148,75,11 + PUSHBUTTON "Err... what?",IDC_SECUREPASSWORDHELP,153,118,51,17 + CONTROL "Debug Mode",IDC_PASS_DEBUG,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,141,148,58,11 + LTEXT "Warning! Changing between Secure and Insecure passwords will require entering all passwords again.", + IDC_STATIC,13,118,131,26 + LTEXT "Click 'Ok' before editing users if you change these.", + IDC_STATIC,13,164,194,10 +END + +IDD_WEBPAGE DIALOGEX 0, 0, 220, 201 +STYLE WS_CHILD | WS_CAPTION | WS_SYSMENU +CAPTION "WAWI Config : Web Page Settings" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Frames",IDC_STATIC,7,7,206,75 + LTEXT "Change how many frames Wawi uses depending on your browser.", + IDC_STATIC,13,19,184,18 + EDITTEXT IDC_PAGETITLE,20,112,150,12,ES_AUTOHSCROLL | NOT + WS_BORDER,WS_EX_STATICEDGE + PUSHBUTTON "?",IDC_PAGETITLEHELP,174,113,12,12 + LTEXT "Web Page Title",IDC_STATIC,20,101,139,8 + CONTROL "No Frames",IDC_NOFRAMES,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,23,42,60,10 + CONTROL "Two Frames",IDC_TWOFRAMES,"Button",BS_AUTORADIOBUTTON, + 23,52,60,10 + CONTROL "Three Frames",IDC_THREEFRAMES,"Button", + BS_AUTORADIOBUTTON,23,62,60,10 + GROUPBOX "Page Details",IDC_STATIC,7,87,206,65 + CONTROL "",IDC_FRAMEIMG,"Static",SS_BITMAP | SS_REALSIZEIMAGE, + 128,40,16,14 + EDITTEXT IDC_REFRESH,96,131,30,12,ES_AUTOHSCROLL | ES_NUMBER | + NOT WS_BORDER,WS_EX_STATICEDGE + LTEXT "Title Page Refresh (s)",IDC_STATIC,20,133,69,8 +END + +IDD_BROWSE DIALOGEX 0, 0, 220, 201 +STYLE DS_MODALFRAME | WS_CHILD | WS_CAPTION | WS_SYSMENU +CAPTION "Browse Options" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT IDC_MP3_ROOT,23,35,150,12,ES_AUTOHSCROLL | NOT WS_BORDER, + WS_EX_STATICEDGE + GROUPBOX "Browsing Options",IDC_STATIC,7,7,206,187 + LTEXT "Root Directory",IDC_STATIC,23,24,114,8 + EDITTEXT IDC_FILETYPES,23,98,150,12,ES_AUTOHSCROLL | NOT + WS_BORDER,WS_EX_STATICEDGE + LTEXT "Loadable Filetypes",IDC_STATIC,23,87,153,8 + PUSHBUTTON "?",IDC_FILETYPEHELP,177,98,12,12 + PUSHBUTTON "?",IDC_ROOTDIRHELP,177,35,12,12 + CONTROL "Show",IDC_OTHER_FILES_SHOW,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,79,129,38,9 + CONTROL "Download",IDC_OTHER_FILES_DL,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,126,129,48,9 + CONTROL "Download",IDC_WA_FILES_DL,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,126,116,51,10 + LTEXT "Other files:",IDC_STATIC,23,129,40,9 + LTEXT "Winamp Files:",IDC_STATIC,23,116,55,10 + CONTROL "Show",IDC_WA_FILES_SHOW,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,79,116,38,10 + EDITTEXT IDC_PLAYLISTDIR,23,67,150,12,ES_AUTOHSCROLL | NOT + WS_BORDER,WS_EX_STATICEDGE + LTEXT "Playlist Directory (Leave empty for Root Dir)", + IDC_STATIC,23,56,147,8 + PUSHBUTTON "?",IDC_PLAYLISTDIRHELP,177,67,12,12 +END + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 220, 201 +STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "",IDC_MAINIMAGE,"Static",SS_BITMAP,6,13,206,68 + CTEXT "Title goes here",IDC_ABOUT_TITLE,5,88,207,14 + CTEXT "© Phil Himsworth 2002\r\n\r\ncontact@flippet.net - http://www.flippet.org", + IDC_STATIC,9,160,201,28 + CTEXT "Remote control winamp from your web browser. First released waaaay back in August 2001; now much improved and shinier than ever!\r\n\r\nIf you see anything broken, or have an idea, get in touch and I'll have a look...", + IDC_STATIC,9,101,202,48 +END + +IDD_LOG DIALOGEX 0, 0, 220, 201 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Log File" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Server Access Log",IDC_STATIC,7,7,206,108 + LTEXT "WAWI keeps a log of who has accessed the server for diagnostic or statistical purposes.", + IDC_STATIC,18,26,125,25 + EDITTEXT IDC_LOGFILEPATH,17,84,179,12,ES_AUTOHSCROLL | NOT + WS_BORDER,WS_EX_STATICEDGE + LTEXT "Logfile Directory (leave empty for Plugins Dir)", + IDC_STATIC,17,71,146,8 + PUSHBUTTON "View Log...",IDC_VIEWLOG,149,26,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_USERS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + END + + IDD_SERVER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + END + + IDD_WEBPAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + END + + IDD_BROWSE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + END + + IDD_LOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 194 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_USERS ICON DISCARDABLE "users.ico" +IDI_SERVER ICON DISCARDABLE "server.ico" +IDI_WEBPAGE ICON DISCARDABLE "webpage.ico" +IDI_BROWSE ICON DISCARDABLE "browse.ico" +IDI_LOG ICON DISCARDABLE "Log.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_FRAMES_TWO BITMAP DISCARDABLE "Images\\frames_two_lg.bmp" +IDB_FRAMES_THREE BITMAP DISCARDABLE "Images\\frames_three_lg.bmp" +IDB_FRAMES_ONE BITMAP DISCARDABLE "Images\\frames_one_lg.bmp" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// IMAGE +// + +IDR_DOWNLOAD IMAGE DISCARDABLE "download.gif" +IDR_IMG_POPUP IMAGE DISCARDABLE "Images\\popup.gif" +IDR_PLAYDIR IMAGE DISCARDABLE "playdir.gif" +IDR_URLSCT IMAGE DISCARDABLE "Images\\world.gif" +IDR_IMG_ADMIN IMAGE DISCARDABLE "Images\\admin.gif" +IDR_IMG_OK IMAGE DISCARDABLE "Images\\OK.gif" +IDR_IMG_RPT_ON IMAGE DISCARDABLE "Images\\repeaton.gif" +IDR_IMG_RND_ON IMAGE DISCARDABLE "Images\\randomon.gif" +IDR_IMG_RPT_OFF IMAGE DISCARDABLE "Images\\repeatoff.gif" +IDR_IMG_RND_OFF IMAGE DISCARDABLE "Images\\randomoff.gif" +IDR_IMG_LIST_DEL IMAGE DISCARDABLE "Images\\list_delete.gif" +IDR_IMG_LIST_PLAY IMAGE DISCARDABLE "Images\\list_play.gif" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_WINAMP ICON DISCARDABLE "images\\winamp.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_TITLE BITMAP DISCARDABLE "Images\\Title Graphic\\No Background.bmp" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 7,5,10,0 + PRODUCTVERSION 7,5,10,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "Winamp Web Interface Plugin\0" + VALUE "CompanyName", " \0" + VALUE "FileDescription", "Winamp Web Interface Plugin\0" + VALUE "FileVersion", "7, 5, 10, 0\0" + VALUE "InternalName", "gen_httpSrv\0" + VALUE "LegalCopyright", "Copyright © 2002 Phil Himsworth\0" + VALUE "LegalTrademarks", "It's mine, dammit, MINE!\0" + VALUE "OriginalFilename", "gen_httpSrv.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", " gen_httpSrv\0" + VALUE "ProductVersion", "7, 5, 10, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Wawi Source/Wawi_Readme.txt b/Wawi Source/Wawi_Readme.txt new file mode 100644 index 0000000..e62b2a9 --- /dev/null +++ b/Wawi Source/Wawi_Readme.txt @@ -0,0 +1,231 @@ +---------------------- +Winamp Web Interface +---------------------- + +WAWI is a plugin which gives you remote control of Winamp from any computer which can access it over a network with any common-or-garden web browser. It lets you have full control over immediate playback, lets you edit the playlist and add songs +from your music collection, all without touching the computer actually running winamp or installing anything on the client computer. + + +Using It +-------- + +Install the plugin and point your browser at your computer. By default it runs on the normal web server port 80, but that can be changed in the Options->Server window. For example, at your own computer http://localhost/ should bring it up. If you change the port you can use http://localhost:xxxx instead, where xxxx is the port number. The main screen should appear; from there everything is linked so you can control winamp, access the playlist etc. + +To start with you can't actually do much; you need to set up some permissions first. Do this in the Options -> Users window. + + +Adding Users +------------ + +Initially there is just one user listed, 'anon'... this is anyone who hasn't logged in using a different name. It does not have a password, and to start with has no permissions; change permissions by clicking on the boxes for what you want anyone to be able to do, and click 'Add/Update'. + +To add a new user, maybe to let you control winamp but only let others look but not touch, type in a username in the 'user' box and a password in the 'password' box, check the desired access permissions, and click 'Add/Update'. Bingo, a new user. + +Delete a user by clicking on the name in the list or typing the name straight into the 'user' box and click 'Delete'. Gone... + + +Different Modes for Different Browsers +-------------------------------------- + +The default mode is using two frames, one for the black bar along the top with the blue buttons and the main frame which displays the pages. + +If you're using a no-frames browser select 'One Frame' in the Options->Web Page window. This will disable the top frame, and instead have a set of text links on each page to navigate around pages. + +If you are using the interface from a PDA or something with a similarly small screen, there is a special small page with the basic controls on it, which lets you change the state of Random and Repeat and control playback. Point your browser at '/pda' to access this page. + +The three frames mode is currently experimental but I think it works properly. This is similar to the two frame mode but with another frame at the bottom which updates with the song title and allows the main page to stay where it is when loading files or playing songs in the playlist. + + +Keeping track of what goes on +----------------------------- + +The plugin keeps a log of who's been accessing the interface. By default this is kept in a file in the winamp 'plugins' directory called 'httpsrv.log'. Once this log file reaches 50KB it is renamed to 'httpsrv_<date>_<number>.log', for example the second full log file generated on the 12th of April 2002 will be named 'httpsrv_12-4-2002_2.log'. + +The log file stores the time of the connection, the IP address and username of the client, the page they requested and the HTTP return code, for example '200' is a successful operation and '401' is when access is not allowed to a page or function. + + +Your Music Collection +--------------------- + +The web interface can load files into winamp from a directory specified as your music collection. Enter the path of your music collection into the box in the options screen, make sure you have the right access permission, and go load songs. + +The contents of each directory are listed in a fairly self explanatory manner. Clicking on the name of a file or the icon next to it will load a file into winamp. Clicking on the name of a directory or the icon of a folder will browse that directory. Clicking on the icon of a folder with a red plus sign will add the entire contents of the folder to the playlist. + +If downloading files is enabled, clicking on the icon of a disk will download a file onto the user's computer. Change this setting from the Options window. + +Files that the interface should be able to load can be specified in the Options->Music Collection window; enter the extension of a file into the 'Filetypes' box to enable loading it from the interface. For example the default is 'wav mp3 m3u url', which allows MP3 files, Wave files, Winamp playlists and Internet Shortcuts to be loaded. + +Internet Shortcut files appear with an icon of a world; loading these will load the target of the shortcut into the winamp playlist. This is useful if you make a shortcut to an internet radio station, for example. + + +Tinkering with how it looks +--------------------------- + +To alter the look of the page you can define your own Stylesheet to be sent along with the pages, if for example you are integrating it into another website or simply want to change how it looks. If there is a stylesheet in the winamp plugins directory called 'wawi.css' it will be used. If there isn't one there the default built-in stylesheet will be used instead. + + +Errors +------ + +If you've not told it to keep quiet it will pop up a message if it can't open the specified port. This is usually because there's another program using it - check you haven't got another web server running, as the default port for the plugin is the standard web port. If this is the case change it in the Config window for the plugin. If you tell it to not bother you if an error occurs it will sit quietly doing nothing. + + +Bugs +---- + +Hopefully the problem with MD5 passwords should be fixed now, after I finally got my hands on a computer that it wouldn't work on. However just in case it crops up again... sometimes it will not let you log in if passwords are being stored securely. If this seems to be the case tick the "debug" box and see what it says when adding a user or changing a password; if it says something like "encoded password" and a short string of gibberish (rather than a long string of alphanumerical gibberish) then please let me know about it! In the meantime, untick the secure mode; this should work. The difference is how the password is stored on your computer, not how it is sent over the network. + +It was designed mainly using IE6 as a client... while Netscape and Lynx like it, Opera 6 seems to have a few problems; the currently playing track is not highlighted in the playlist; the main page doesn't update properly when selecting a track from the playlist to play. I shall look into it. + +The 'download' function didn't work for me on Windows 9x; it has been fiddled with extensively but given that I now run Windows 2000 I have no way of testing it any more. It works on 2000. The interface uses the same method to send a StyleSheet for the web pages; while downloading files is not essential this probably is; let me know if it goes wrong and I'll try to fix it. + +There're bound to be more... let me know if you find any. + + + +Possibly More Recent Versions +----------------------------- + +At the moment (April 2002) I am working on this regularly, so a new version is uploaded to the WAWI web site frequently. Check there for recent versions including bug fixes and new features. Wander over to www.flippet.net... + + + +Test Platforms so far +--------------------- + +Development started on a Windows Me system, but now is done entirely on Windows 2000. Platforms I know it has been used on are now too numerous to name individually, but range from various versions of windows to PDAs. I feel quite boring using it from my laptop... + + + +Change Log +---------- + +7.5.10 + +* Fixed the silly thing with the "browse" pages if you didn't give it a path to start with - it would show the root directory but none of the links would work. + +7.5.9 + +* Secure passwords should now work ALL the time!!! Woohoo!!! (Hopefully...) + +7.5.8 + +* Fixed the Base64 password system AGAIN, hopefully for the last time! + +7.5.7 + +* Fixed which frame the new Delete went to (now stays in one frame; bit daft deleting something but not updating the playlist... +* Added a line in the HTTP header of HTML pages to stop the page being cached (hopefully) +* Made the 'random' and 'repeat' stay on the main page (again, a bit daft turning random off if the main page says it's still on and the like) + +7.5.6 + +* Fixed the Base64 encoding/decoding, which hopefully should solve some password problems. +* Changed how delete playlist entry works - should be faster now, hopefully. + +7.5.5 + +* Added a Save Playlist option +* Fixed a little bug if you tried to use a password of 'password' (muppet... ;¬P ) + +7.5 + +* Shiny new Options window; pretty pictures and pages, rather than having all options crammed onto one page + +7.1 + +* First half-decent three frames mode! +* Ability to sort the playlist by title from the playlist page + +7.0.1 + +* Fixed bug where there were no users in the list when first installing it +* Cleaned up the delete playlist entries function a bit + +7.0 + +* Define your own stylesheet... if there's a file called 'wawi.css' in the plugins directory it will be used as a stylesheet. +* Ability to remove tracks from the playlist +* First introduction of web-based user management page, accessible from the 'admin' page. I think it looks funny on Opera though... I'll fix it shortly... +* Fixed bug where it would not save changes from the web admin page +* Slight under-the-hood change of page refreshing on adding files from the Browse pages +* Addded a 'PDA' mode for simple controls on small browsers - just point at '/pda' +* Added a password debug mode; if you have problems let me know what it says. +* Made it work again on w9x (sorry...) +* Certain options can be changed from the web interface with a new Admin page. +* When loading a file from the Browse page it will now return to the page where you clicked, instead of having to navigate back to it again. +* Option of using secure or non-secure passwords if you encounter problems. + +6.0 + +* Added a 'restrict search' option; narrow your search of the playlist. I find it very handy. +* It now uses escape characters properly, so it should work on more browsers (the file browsing didn't work on Lynx before). +* 'View Log' button works wherever the log file directory is set to +* Massive, but under the hood, changes; any variables passed to the server are in the proper 'name=value' format, so they can be used from forms. +* Icons in the Browse section don't have silly backgrounds. At last! + +5 + +* Added a completely new authentication system. You can set up users with different permissions - browse files, download files, add files to the playlist, clear the playlist and actually control playback. +* Added a favicon.ico so if you make it a Favourite you'll get a nice pwetty picture. Wow... + +4 + +* Added a 'play URL immediately' option. Load a normal URL using /url?l&http://whatever, and play one immediately by /url?p&http://whatever. +* Requesting '/title' from the server returns a very simple page with just the currently playing song title, and which refreshes every minute. +* Requesting 'smalltitle' returns something similar, but it's just dead simple plain text version of the song info, so it can be included in another page or something along those lines. +* Directories have a 'play' button so you can load songs a directory at a time rather than a file at a time (which took ages!) +* Made links work properly in browsers that didn't convert spaces to %20s (eg. Lynx). There are probably other characters in names that don't work... if you find any, let me know. +* Added an (unlinked) url? command, which can play any filepath, UNC path, HTTP file, you name it. Just type it in... "/url?http://computer/path/to/song.mp3" and (hopefully) it'll work. +* Improved log handling - logs are rotated if they get big +* The popup window link works properly now and can be added to your Favourites or Bookmarks or whatever. +* Added an option to turn off the password protection if it annoys you and you've no need for it. +* Added a 'Stop with fadeout' button to the graphic link bar. It's not on the text link bar, but you can still use it if you must by typing in "/stopslow" in the Address bar of your browser. +* Passwords! Stop peeps messing... properly. +* A button to load the interface in a smaller popup window without the normal browser baggage like buttons and stuff. Still experimental, but it's there. +* The bar at the top is now a seperate frame to avoid having it reload the images every time. +* It also has a text only (well, mostly) mode if you don't like the top links at all; this makes it look like it did before version 3.0. + +3 +* A nice shiny bar at the top instead of the old text links bar. Popup about window; customisable title; and slightly better html. +* Under-the-hood changes; includes better http parsing, and should be faster too. Doesn't crash my network card any more! Also includes a small 'about' window from the browser, and lets you put your own title in for the main page. +* Wooo, shiny... now includes graphics in the Music Collection pages. Playlists (.m3u files) are handled better too. +* First submitted to winamp.com! +* The file types that can be loaded into winamp from the Browse section can now be chosen in the Options window. By default .wav and .mp3 files are loadable. Other filetypes can be displayed or hidden as desired. The access log file can also be viewed from within Winamp by clicking the View Log button in the options window. +* Now creates a log file with every connection, showing time, client and requested URL. Stored in a file in the plugins directory; I know several plugins where the log file ends up all over the place... +* Mainly under-the-hood changes; should be safer with multiple connections. More obvious directories in Browse pages. Got rid of server bluescreening problem! +* Added 'Read Only' option to stop people fiddling if you don't want them to. + +2 +* Added file browsing and adding. +* Added html stylesheets, proper html and random things to make it look nice + +1 +* Initial release + + + +Me +-- + +Phil Himsworth, UK + +web: http://www.flippet.org +email: contact@flippet.net + +September, 2002 + + + + +The Dull(er?) Bits +------------------ + +Disclaimer +---------- + +While I've gone to every effort to make sure this doesn't cause harmful effects - I don't want to fry my own computer! - I cannot say for sure that it will not fry yours. I will not be responsible for any damage or loss of anything even slightly relating to this program. You use it ENTIRELY AT YOUR OWN RISK. Don't run to me if things break. I'll fix bits of the program if you spot bugs if I want to, but I'm under no obligation to do so at all. And don't you forget it. + +Besides that, I hope it's useful. Have fun! + + diff --git a/Wawi Source/WebAdmin.cpp b/Wawi Source/WebAdmin.cpp new file mode 100644 index 0000000..452601e --- /dev/null +++ b/Wawi Source/WebAdmin.cpp @@ -0,0 +1,530 @@ +/* --- WEBADMIN.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include "types.h" +#include "main.h" +#include "html.h" +#include "plugin.h" +#include "resource.h" + +#include "op_winamp.h" + +extern char mp3root[MAX_PATH], playlistdir[MAX_PATH], logfiledir[MAX_PATH], filetypes[255]; +extern int browse_enable, dl_wa_files, dl_other_files, show_other_files, frames, title_refresh, securepassword; + +extern char szAppVer[]; +extern char pagetitle[255]; + +extern winampGeneralPurposePlugin plugin; + +// -------------------------------------------------------------------------------- +// Returns Web Admin page +int CControl::WebAdmin(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<h3>\n<i>\n... Wawi Remote Admin ...\n</i></h3>\n"); + + prints(conn,"<h4>"); + Link(conn,"/user","<font color=red>[</font>User Management<font color=red>]</font>",T_MAIN); + prints(conn,"</h4>\n"); + + prints(conn,"<form action=\"/apply\" method=\"get\">\n"); + + prints(conn,"<table width=\"100%\" cellspacing=\"5\" cellpadding=\"0\" border=\"0\">\n<tr>\n"); + prints(conn,"<td align=\"right\">Main Page Title</td>\n<td><input type=\"text\" name=\"title\" size=\"30\" value=\""); + prints(conn,pagetitle); + prints(conn,"\"></td>\n</tr>\n<tr>\n"); + prints(conn,"<td align=\"right\">Loadable Filetypes</td>\n<td><input type=\"text\" name=\"filetypes\" size=\"30\" value=\""); + prints(conn,filetypes); + prints(conn,"\"></td>\n</tr>\n<tr>\n"); + prints(conn,"<td align=\"right\">Music Root Directory</td>\n<td><input type=\"text\" name=\"root\" size=\"30\" value=\""); + prints(conn,mp3root); + prints(conn,"\"></td>\n</tr>\n<tr>\n"); + prints(conn,"<td align=\"right\">Playlists Directory</td>\n<td><input type=\"text\" name=\"playlists\" size=\"30\" value=\""); + prints(conn,playlistdir); + prints(conn,"\"></td>\n</tr>\n<tr>\n<td>&nbsp;</td>\n</tr>\n<tr>\n"); + + + // Frames mode radio buttons + prints(conn,"<td align=\"right\">Frames:</td>\n<td><input type=\"radio\" name=\"frames\" value=\"1\""); + if (frames == 1) + prints(conn," checked=\"on\""); + prints(conn,">No Frames</td>\n</tr>\n<tr>\n<td align=\"right\">&nbsp;</td>\n<td><input type=\"radio\" name=\"frames\" value=\"2\""); + if (frames == 2) + prints(conn," checked=\"on\""); + prints(conn,">2</td>\n</tr>\n<tr>\n<td align=\"right\">&nbsp;</td>\n<td><input type=\"radio\" name=\"frames\" value=\"3\""); + if (frames == 3) + prints(conn," checked=\"on\""); + + prints(conn,">3</td>\n</tr>\n<tr>\n"); + prints(conn,"<td align=\"right\">Secure Passwords</td>\n<td><input type=\"checkbox\" name=\"securepassword\""); + if (securepassword == 1) + prints(conn," checked=\"on\""); + prints(conn,"><b>Warning!</b> Changing this will invalidate all user passwords.</td>\n</tr>\n<tr>"); + prints(conn,"<td>&nbsp;</td>\n</tr>\n<tr>\n"); + prints(conn,"<td align=\"right\">Winamp Files</td>\n<td><input type=\"checkbox\" name=\"dl_wa_files\""); + if (dl_wa_files == 1) + prints(conn," checked=\"on\""); + prints(conn,">Download</td>\n</tr>\n<tr>\n"); + prints(conn,"<td align=\"right\">Other Files</td>\n<td><input type=\"checkbox\" name=\"dl_other_files\""); + if (dl_other_files == 1) + prints(conn," checked=\"on\""); + prints(conn,">Download <input type=\"checkbox\" name=\"show_other_files\""); + if (show_other_files == 1) + prints(conn," checked=\"on\""); + prints(conn,">Show</td>\n</tr>\n"); + prints(conn,"<td colspan=\"2\" align=\"center\"><input type=\"image\" alt=\"Apply Changes\" src=\"img?image="); + printsi(conn,IDR_IMG_OK); + prints(conn,"\"></td>\n</tr>\n</table>"); + prints(conn,"</form>\n"); + + + + if (frames == 1) + LinkBar(conn); + prints(conn,"<p>&nbsp;</p>"); + + return ST_CLOSEBODY; +} + +// Returns admin apply page and actually does the stuff +int CControl::ApplyAdmin(connection * conn) +{ + bool changed = false; + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<h3>\n<i>\n... Wawi Remote Admin ...\n</i></h3>\n"); + + char instring[255]; // used for everything + + if (GetArgValue(conn,"title",instring,255)) + { + Unescape_url(instring); + if (!StrComp(pagetitle,instring)) + { + lstrcpy(pagetitle,instring); + prints(conn,"<p>Page title changed to <b>"); + prints(conn,pagetitle); + prints(conn,"</b></p>\n"); + changed = true; + } + } + + if (GetArgValue(conn,"filetypes",instring,255)) + { + Unescape_url(instring); + if (!StrComp(filetypes,instring)) + { + lstrcpy(filetypes,instring); + prints(conn,"<p>Filetypes changed to <b>"); + prints(conn,filetypes); + prints(conn,"</b></p>\n"); + changed = true; + } + } + + if (GetArgValue(conn,"root",instring,255)) + { + Unescape_url(instring); + if (!StrComp(mp3root,instring)) + { + lstrcpy(mp3root,instring); + prints(conn,"<p>Root music directory changed to <b>"); + prints(conn,mp3root); + prints(conn,"</b></p>\n"); + changed = true; + } + } + + if (GetArgValue(conn,"playlists",instring,255)) + { + Unescape_url(instring); + if (!StrComp(playlistdir,instring)) + { + lstrcpy(playlistdir,instring); + prints(conn,"<p>Playlist directory changed to <b>"); + prints(conn,playlistdir); + prints(conn,"</b></p>\n"); + changed = true; + } + } + + wsprintf(instring,"2"); + GetArgValue(conn,"frames",instring,255); + if (StrComp(instring,"1")) + { + if (frames != 1) + { + frames = 1; + prints(conn,"<p>No Frames mode turned <b>On</b></p>"); + changed = true; + } + } + else + { + if (StrComp(instring,"3")) + { + if (frames != 3) + { + frames = 3; + prints(conn,"<p>Three Frames mode turned <b>On</b></p>"); + changed = true; + } + } + else + { + if (frames != 2) + { + frames = 2; + prints(conn,"<p>Two Frames mode turned <b>On</b></p>"); + changed = true; + } + } + } + + wsprintf(instring,"off"); + GetArgValue(conn,"securepassword",instring,255); + if (StrComp(instring,"on")) + { + if (securepassword == 0) + { + securepassword = 1; + prints(conn,"<p>Secure passwords turned <b>On</b></p>"); + changed = true; + } + } + else + { + if (securepassword == 1) + { + securepassword = 0; + prints(conn,"<p>Secure passwords turned <b>Off</b></p>"); + changed = true; + } + } + + wsprintf(instring,"off"); + GetArgValue(conn,"dl_wa_files",instring,255); + if (StrComp(instring,"on")) + { + if (dl_wa_files == 0) + { + dl_wa_files = 1; + prints(conn,"<p>Downloading of Winamp files is <b>Enabled</b></p>"); + changed = true; + } + } + else + { + if (dl_wa_files == 1) + { + dl_wa_files = 0; + prints(conn,"<p>Downloading of Winamp files is <b>Disabled</b></p>"); + changed = true; + } + } + + wsprintf(instring,"off"); + GetArgValue(conn,"dl_other_files",instring,255); + if (StrComp(instring,"on")) + { + if (dl_other_files == 0) + { + dl_other_files = 1; + prints(conn,"<p>Downloading other files is <b>Enabled</b></p>"); + changed = true; + } + } + else + { + if (dl_other_files == 1) + { + dl_other_files = 0; + prints(conn,"<p>Downloading other files is <b>Disabled</b></p>"); + changed = true; + } + } + + wsprintf(instring,"off"); + GetArgValue(conn,"show_other_files",instring,255); + if (StrComp(instring,"on")) + { + if (show_other_files == 0) + { + show_other_files = 1; + prints(conn,"<p>Listing other files is <b>Enabled</b></p>"); + changed = true; + } + } + else + { + if (show_other_files == 1) + { + show_other_files = 0; + prints(conn,"<p>Listing other files is <b>Disabled</b></p>"); + changed = true; + } + } + + if (changed == false) + prints(conn,"<p>No changes made.</p>\n"); + + config_write(); + + prints(conn,"<p>"); + ImgLink(conn,"/",IDR_IMG_OK,"Return to Main Page",0,0,T_TOP); + prints(conn,"</p>\n"); + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// User admin page +int CControl::User(connection * conn) +{ + + char username[20]; + char password[40]; + int access; + + if (!GetArgValue(conn,"user",username,20)) + wsprintf(username,"anon"); + + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<h3>\n<i>\n... Wawi User Admin ...\n</i></h3>\n"); + + prints(conn,"<form action=\"/user\" method=\"get\">\n<p>\n"); + prints(conn,"<table border=\"0\" cellpadding=\"0\" cellspacing=\"5\">\n<tr>\n<td align=\"right\">"); + prints(conn,"Show User:</td>\n<td colspan=\"2\"><select onchange=\"form.submit()\" size=\"1\" name=\"user\">\n"); + + user * users = NULL; + + char ini_file[MAX_PATH], *p; + GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"gen_httpsrv.ini"); + + users = RetrieveUsers(users, ini_file); // fill list 'users' with usernames + user * current = users; // pointer to start of list + + bool goodname = false; + + while(current != NULL) + { + prints(conn,"<option value=\""); + prints(conn,current->name); + if (StrComp(current->name,username)) + { + prints(conn,"\" selected>"); + goodname = true; + } + else + prints(conn,"\">"); + prints(conn,current->name); + prints(conn,"</option>\n"); + current = current->next; + delete users; + users = current; + } + + prints(conn,"</select>\n"); + + prints(conn,"<input type=\"image\" alt=\"Show information\" src=\"img?image="); + printsi(conn,IDR_IMG_OK); + prints(conn,"\"></td>\n</tr>\n</table>\n</p>\n</form>\n"); + + if (!goodname) + { + prints(conn,"<p>User <b>"); + prints(conn,username); + prints(conn,"</b> is not a user of this server.</p>"); + return ST_CLOSEBODY; + } + else + { + char userkey[30]; + wsprintf(userkey,"#%s_access",username); + access = GetPrivateProfileInt("Users",userkey,AUTH_ANON,ini_file); + GetPrivateProfileString("Users",username,"password",password,40,ini_file); + + prints(conn,"<form action=\"/setuser\" method=\"get\">\n<p>\n"); + prints(conn,"<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"5\">\n"); + prints(conn,"<tr>\n<td align=\"right\">User</td>\n"); + prints(conn,"<td colspan=\"2\"><input type=\"text\" name=\"user\" size=\"40\" value=\""); + prints(conn,username); + prints(conn,"\"></td>\n</tr>\n"); + prints(conn,"<tr>\n<td align=\"right\">Password</td>\n"); + prints(conn,"<td colspan=\"2\"><input type=\"password\" name=\"p\" size=\"40\" value=\""); + if (!StrComp(username,"anon")) + prints(conn,password); + prints(conn,"\"></td>\n</tr>\n"); + + prints(conn,"<tr>\n<td colspan=\"2\">&nbsp;</td>\n</tr>\n"); + prints(conn,"<tr>\n<td align=\"right\">Server<input type=\"checkbox\" name=\"a_server\" "); + if (access & AUTH_SERVER) + prints(conn,"checked=\"on\""); + prints(conn,"></td>\n"); + + prints(conn,"<td align=\"left\"><input type=\"checkbox\" name=\"a_playlist\" "); + if (access & AUTH_PLAYLIST) + prints(conn,"checked=\"on\""); + prints(conn,">Add files</td>\n</tr>\n"); + + prints(conn,"<tr>\n<td align=\"right\">Play<input type=\"checkbox\" name=\"a_control\" "); + if (access & AUTH_CONTROL) + prints(conn,"checked=\"on\""); + prints(conn,"></td>\n"); + + prints(conn,"<td align=\"left\"><input type=\"checkbox\" name=\"a_download\" "); + if (access & AUTH_DOWNLOAD) + prints(conn,"checked=\"on\""); + prints(conn,">Download</td>\n</tr>\n"); + + prints(conn,"<tr>\n<td align=\"right\">Remove files<input type=\"checkbox\" name=\"a_clear\" "); + if (access & AUTH_CLEAR) + prints(conn,"checked=\"on\""); + prints(conn,"></td>\n"); + + prints(conn,"<td align=\"left\"><input type=\"checkbox\" name=\"a_browse\" "); + if (access & AUTH_BROWSE) + prints(conn,"checked=\"on\""); + prints(conn,">Browse</td>\n</tr>\n<tr>\n<td colspan=\"2\" align=\"center\">"); + + prints(conn,"<input type=\"submit\" name=\"addupd\" value=\"Add/Update\">"); + prints(conn,"<input type=\"submit\" name=\"delete\" value=\"Delete\">\n</td>\n</tr>\n</table>\n</p>\n</form>\n"); + + } + + if (frames == 1) + LinkBar(conn); + + prints(conn,"<p>&nbsp;</p>\n"); + + + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Sets stuff from the user admin page +int CControl::SetUser(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + + prints(conn,"<h3>\n<i>\n... Wawi User Admin ...\n</i></h3>\n"); + char username[20]; + char password[40]; + if (!GetArgValue(conn,"user",username,20) || StrComp(username,"")) + { + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>No user selected.</p>\n"); + ImgLink(conn,"/main",IDR_IMG_OK,"Return to main page",0,0,T_MAIN); + return ST_CLOSEBODY; + } + + char ini_file[MAX_PATH], *p; + GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"gen_httpsrv.ini"); + + + char whichbutton[20]; + if (GetArgValue(conn,"delete",whichbutton,20)) + { + DeleteUser(ini_file,username); + RefreshHeader(conn,"/user"); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Deleting user <b>"); + prints(conn,username); + prints(conn,"</b></p>\n"); + + return ST_CLOSEBODY; + } + + + + char refreshto[40]; + wsprintf(refreshto,"/user?user=%s",username); + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<p>Updating user information for <b>"); + prints(conn,username); + prints(conn,"</b></p>\n"); + + GetArgValue(conn,"p",password,40); + //MessageBox(NULL,password,"password",MB_OK | MB_TOPMOST); + + int access = 0; + char authstring[10]; + + if (GetArgValue(conn,"a_server",authstring,10)) + if (StrComp(authstring,"on")) + access += AUTH_SERVER; + + if (GetArgValue(conn,"a_control",authstring,10)) + if (StrComp(authstring,"on")) + access += AUTH_CONTROL; + + if (GetArgValue(conn,"a_clear",authstring,10)) + if (StrComp(authstring,"on")) + access += AUTH_CLEAR; + + if (GetArgValue(conn,"a_playlist",authstring,10)) + if (StrComp(authstring,"on")) + access += AUTH_PLAYLIST; + + if (GetArgValue(conn,"a_download",authstring,10)) + if (StrComp(authstring,"on")) + access += AUTH_DOWNLOAD; + + if (GetArgValue(conn,"a_browse",authstring,10)) + if (StrComp(authstring,"on")) + access += AUTH_BROWSE; + + + + UpdateUser(ini_file,username,password,access); + + return ST_CLOSEBODY; +} diff --git a/Wawi Source/browse.cpp b/Wawi Source/browse.cpp new file mode 100644 index 0000000..eabe0f9 --- /dev/null +++ b/Wawi Source/browse.cpp @@ -0,0 +1,460 @@ +/* --- BROWSE.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/ Contains everything for the "Browse Music Collection" pages. + +/*/ + +#include <windows.h> +#include "types.h" +#include "main.h" +#include "resource.h" + + +#include "html.h" + + +/* All this lot made obsolete by using all local vars instead - + Should make it more thread-safe, anyway (even if it seems to + work anyway...) + +int dnodes=0; +int fnodes=0; + +char tempstring[200]; + + +fileinfo * firstfile; +fileinfo * firstdir; + +*/ + +extern int show_other_files, dl_other_files, dl_wa_files, frames; + +extern char filetypes[255]; +extern char mp3root[MAX_PATH]; + +// -------------------------------------------------------------------------------- +// Removes the topmost directory to go to parent directory +void UpDirectory(char * mp3path, char * mp3pathout) +{ + + int c=0; + while(mp3path[c] != 0) // increment c until it is at end of mp3path + c++; + + c-=2; // c is now character before last slash + + while(mp3path[c] != '\\') // decrement c to find second to last slash + c--; + + c++; + mp3pathout[c] = 0; + c--; // c now points at last required character + + while(c>=0) + { + mp3pathout[c] = mp3path[c]; // copy rest of string across + c--; + } +} + +// -------------------------------------------------------------------------------- +// Tests whether the current name is a Winamp-readable file or not (by file extension) +bool IsWinampFile(fileinfo * file) +{ + file->playlist = false; // clear playlist flag - it's random otherwise + file->urlsct = false; + + char * xtn; // eXTensioN + int c=0; + + while(file->name[c] != 0) // increment c until it is at end of mp3path + c++; + + while(file->name[c] != '.') // decrement c to find last period + c--; + + xtn = &file->name[c+1]; // extension should now be 'mp3', 'wav' etc. + + if (StrComp("m3u",xtn)) // one-off check to see if the file is a playlist + file->playlist=true; // mark as a playlist. + + if (StrComp("url",xtn)) // check if the file is a URL shortcut + file->urlsct = true; // mark as such + // It could return here, but then m3u/url files would be unblockable + + int ptr = 0; // pointer within 'filetypes' + + while(filetypes[ptr] != 0) + { + if (StartString(xtn,filetypes+ptr)) // Check xtn with current filetype in list + return true; + else // No match; next type in list + { + while(filetypes[ptr] != 0 && filetypes[ptr] != ' ') + ptr++; + + if (filetypes[ptr] == ' ') + ptr++; // Space; move pointer to next type + } + } + + + return false; // Should never reach here! +} + +// -------------------------------------------------------------------------------- +// Wrapper around above for just doing filenames, not fileinfo structures +bool IsWinampFile(char * filename) +{ + int strlength=0; + while(filename[strlength] != 0) + strlength++; + + fileinfo file; + ZeroMemory(&file,sizeof(file)); + CopyMemory(file.name,filename,strlength); + + return IsWinampFile(&file); +} + + +// -------------------------------------------------------------------------------- +// Adds a file / directory etc. to the appropriate list +void AddFileToList(connection * conn,WIN32_FIND_DATA *find, char* mp3path, filesearch * search) +{ + char mp3pathout[MAX_PATH]; + + fileinfo *currentfile = search->firstfile; + fileinfo *currentdir = search->firstdir; + + // Directories + if ((find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) // dir + { + // Current directory '.' + if (StrComp(find->cFileName,".")) // this directory; do nothing + return; + + // Parent Directory '..' + if (StrComp(find->cFileName,"..")) // parent directory + { + if (mp3path[1]==0) // already at root directory + return; + UpDirectory(mp3path, (char*)&mp3pathout); + prints(conn, "<b><font color=red>[</font><a href=\"/browse?path="); + prints(conn, mp3pathout); + prints(conn, "\">Up</a><font color=red>]</font></b><br>\n"); + return; + } + + // Hidden directory + if ((find->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == FILE_ATTRIBUTE_HIDDEN) + { + return; + } + + // System directory? Eh? *** Look at this *** + if ((find->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) == FILE_ATTRIBUTE_SYSTEM) + { + return; + } + + // normal directory + fileinfo *newfile = new fileinfo; + search->dnodes++; + CopyMemory(&newfile->path,mp3path,MAX_PATH); + CopyMemory(&newfile->name,find->cFileName,MAX_PATH); + newfile->next = NULL; + newfile->prev = NULL; + + // No entries in list + if (!search->firstdir) + { + search->firstdir = newfile; + return; + } + else // already entries in list + { + if (GoesBefore(newfile->name,search->firstdir->name)) + { + search->firstdir->prev = newfile; + newfile->next = search->firstdir; + search->firstdir = newfile; + } + else // not first in list + { + Insert(newfile,search->firstdir); + } + } + } + else + { + // files + + /* + This new version with linked lists NO LONGER checks for Winamp files here! + All files are added to the list in the correct order. + */ + + fileinfo *newfile = new fileinfo; + search->fnodes++; + CopyMemory(&newfile->path,mp3path,MAX_PATH); + CopyMemory(&newfile->name,find->cFileName,MAX_PATH); + newfile->next = NULL; + newfile->prev = NULL; + + // No entries in list + if (!search->firstfile) + { + search->firstfile = newfile; + return; + } + else // already entries in list + { + if (GoesBefore(newfile->name,search->firstfile->name)) + { + search->firstfile->prev = newfile; + newfile->next = search->firstfile; + search->firstfile = newfile; + } + else // new file should not be first in list + { + Insert(newfile,search->firstfile); + } + } + } +} + +// -------------------------------------------------------------------------------- +// Checks for ../ to ensure selected directory cannot be higher than mp3root +bool GoodPath(char* mp3path) +{ + int i=0; + + while (mp3path[i] != 0 && i<MAX_PATH) + { + if (mp3path[i]=='.' && i<(MAX_PATH-2)) + if (mp3path[i+1]=='.' && mp3path[i+2]=='\\') + return false; + i++; + } + return true; +} + +// -------------------------------------------------------------------------------- +// Lists selected directory +int Browse(connection * conn,char * mp3path) +{ + filesearch search; + + search.firstfile = NULL; + search.firstdir = NULL; + + Unescape_url(mp3path); + char mp3cd[MAX_PATH]; // when it's finished with... + wsprintf(mp3cd,"%s%s",mp3root,mp3path); + + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + if (frames == 1) + LinkBar(conn); + + prints(conn,"<h3>\n<i>\n... Music Collection ...\n</i></h3>\n"); + prints(conn,"<h3>"); + prints(conn,mp3path); + prints(conn,"</h3>\n"); + + WIN32_FIND_DATA find; + HANDLE file; + + if (!GoodPath(mp3path)) + { + prints(conn,"<p><b>Error!</b></p>\n<p>The path requested is illegal.</p>\n<p>It contains the <b>..</b> directory, which could present a security risk.</p>\n"); + prints(conn,"<p>&nbsp;</p>\n"); + } + else + { + if (!SetCurrentDirectory(mp3cd)) + { + prints(conn,"<p><b>Error!</b></p>\n<p>Couldn't open directory. Ensure you haven't mistyped the path, and that the Music Collection root directory is correct.</p>\n"); + prints(conn,"<p>&nbsp;</p>\n"); + } + else + { + char temp[MAX_PATH], temp2[MAX_PATH]; + // Build linked list + file = FindFirstFile("*", &find); + if (file != INVALID_HANDLE_VALUE) + { + AddFileToList(conn,&find,mp3path,&search); + int done = 1; + while (done != 0) + { + done = FindNextFile(file, &find); + if (done != 0) + AddFileToList(conn,&find,mp3path,&search); + } + + FindClose(file); + + // Print out the linked list + prints(conn,"<p>\n\n"); + + // table format? + prints(conn,"<table border=\"0\" width=\"100%\" cellspacing=\"2\">\n"); + + + fileinfo *oldnode = NULL; + fileinfo *currentdir = search.firstdir; + + while (currentdir != NULL) + { + wsprintf(temp,"%s%s",currentdir->path,currentdir->name); + Escape_url(temp); + prints(conn,"<tr>\n"); + + // gap on the left + prints(conn,"<td width=\"50\">&nbsp;</td>\n"); + + prints(conn,"<td width=\"20\">"); + wsprintf(temp2,"/ld?path=%s", temp); + ImgLink(conn,temp2,IDR_PLAYDIR,"Load this directory",0,0,T_BOTTOM); + + prints(conn,"</td>\n"); + + prints(conn,"<td width=\"20\">"); // <a href="/browse?path= mp3path cFileName">cFileName</a><br> + wsprintf(temp2,"/browse?path=%s%%5c",temp); + ImgLink(conn,temp2,IDR_DIRECTORY,"Explore this directory",0,0,T_MAIN); + + prints(conn,"</td>\n<td width=\"520\"><a href=\"/browse?path="); + prints(conn,temp); // mp3path + name + prints(conn,"%5c\"><b>"); + prints(conn,currentdir->name); + prints(conn,"</b></a></td>\n"); + prints(conn,"</tr>\n"); + + oldnode = currentdir; + currentdir = currentdir->next; + + delete oldnode; + search.dnodes--; + + + } + + + + oldnode = NULL; + fileinfo *currentfile = search.firstfile; + while (currentfile != NULL) + { + wsprintf(temp,"%s%s",currentfile->path,currentfile->name); + Escape_url(temp); + + if (IsWinampFile(currentfile)) + { + + prints(conn,"<tr>\n"); + // gap on the left + prints(conn,"<td width=\"50\">&nbsp;</td>\n"); + + // Download link - disk picture + prints(conn,"<td width=\"20\">"); + + if (dl_wa_files == 1) + { + wsprintf(temp2,"/dl?file=%s",temp); + ImgLink(conn,temp2,IDR_DOWNLOAD,"Download this file",0,0,T_MAIN); + } + else + { + prints(conn,"&nbsp;"); + } + prints(conn,"</td>\n"); + + // Play link - WA file picture + prints(conn,"<td width=\"20\">"); + wsprintf(temp2,"/ld?path=%s",temp); + if (currentfile->playlist) + ImgLink(conn,temp2,IDR_PLAYLIST,"Load this playlist",0,0,T_BOTTOM); + else + if (currentfile->urlsct) + ImgLink(conn,temp2,IDR_URLSCT,"Load this URL",0,0,T_BOTTOM); + else + ImgLink(conn,temp2,IDR_WAFILE,"Load this track",0,0,T_BOTTOM); + + + // Play link - text name + wsprintf(temp2,"</td>\n<td width=\"520\"><a href=\"/ld?path=%s",temp); + prints(conn,temp2); + if (frames == 3) + prints(conn,"\" target=\"bottom\">"); + else + prints(conn,"\">"); + prints(conn,currentfile->name); + prints(conn,"</a></td>\n"); + prints(conn,"</tr>\n"); + } + else // not a winamp file + { + if (show_other_files == 1) + { + prints(conn,"<tr>\n"); + // gap on the left + prints(conn,"<td width=\"50\">&nbsp;</td>\n"); + + prints(conn,"<td width=\"20\">"); + if (dl_other_files == 1) + { + wsprintf(temp2,"/dl?file=%s",temp); + ImgLink(conn,temp2,IDR_DOWNLOAD,"Download this file",0,0,T_MAIN); + } + else + { + prints(conn,"&nbsp;"); + } + prints(conn,"</td>\n"); + + prints(conn,"<td width=\"20\">"); + Img(conn,IDR_FILE,"This is not a winamp file",0,0); + prints(conn,"</td>\n<td width=\"*\"><font color=\"#A0A0A0\">"); // non-winamp file - display greyed out + prints(conn,currentfile->name); + prints(conn,"</font></td>\n"); + + prints(conn,"</tr>\n"); + } + } + + oldnode = currentfile; + currentfile = currentfile->next; + delete oldnode; + search.fnodes--; + + } + + prints(conn,"</table>"); + + prints(conn,"\n</p>\n"); + + /* + // Undeleted nodes count + prints(conn,"<p>"); + printsi(conn,search.dnodes); + prints(conn,"&middot;"); + printsi(conn,search.fnodes); + prints(conn,"</p>\n"); + */ + + } + } + } + return ST_CLOSEBODY; +} + diff --git a/Wawi Source/browse.ico b/Wawi Source/browse.ico new file mode 100644 index 0000000..20f0217 Binary files /dev/null and b/Wawi Source/browse.ico differ diff --git a/Wawi Source/dir.gif b/Wawi Source/dir.gif new file mode 100644 index 0000000..a080e15 Binary files /dev/null and b/Wawi Source/dir.gif differ diff --git a/Wawi Source/download.gif b/Wawi Source/download.gif new file mode 100644 index 0000000..a871193 Binary files /dev/null and b/Wawi Source/download.gif differ diff --git a/Wawi Source/file.gif b/Wawi Source/file.gif new file mode 100644 index 0000000..c79d2de Binary files /dev/null and b/Wawi Source/file.gif differ diff --git a/Wawi Source/gen_httpServ.dsp b/Wawi Source/gen_httpServ.dsp new file mode 100644 index 0000000..c5ff4ed --- /dev/null +++ b/Wawi Source/gen_httpServ.dsp @@ -0,0 +1,407 @@ +# Microsoft Developer Studio Project File - Name="gen_httpServ" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=gen_httpServ - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gen_httpServ.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gen_httpServ.mak" CFG="gen_httpServ - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gen_httpServ - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gen_httpServ - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gen_httpServ - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GEN_HTTPSERV_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GEN_HTTPSERV_EXPORTS" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib mswsock.lib version.lib winmm.lib comctl32.lib /nologo /dll /machine:I386 /out:"Release/gen_httpSrv.dll" +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy Release\gen_httpsrv.dll "c:\program files\sound\winamp\plugins" +# End Special Build Tool + +!ELSEIF "$(CFG)" == "gen_httpServ - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GEN_HTTPSERV_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GEN_HTTPSERV_EXPORTS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib mswsock.lib version.lib winmm.lib comctrl32.lib /nologo /dll /debug /machine:I386 /out:"Debug/gen_httpSrv.dll" /pdbtype:sept +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy Debug\gen_httpsrv.dll "c:\program files\sound\winamp\plugins" +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "gen_httpServ - Win32 Release" +# Name "gen_httpServ - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\browse.cpp +# End Source File +# Begin Source File + +SOURCE=.\ClientConnection.cpp +# End Source File +# Begin Source File + +SOURCE=.\Config.cpp +# End Source File +# Begin Source File + +SOURCE=.\Config_users.cpp +# End Source File +# Begin Source File + +SOURCE=.\DeletePlaylistEntry.cpp +# End Source File +# Begin Source File + +SOURCE=.\html.cpp +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\net_http_html.cpp +# End Source File +# Begin Source File + +SOURCE=.\op_winamp.cpp +# End Source File +# Begin Source File + +SOURCE=.\Resource.rc +# End Source File +# Begin Source File + +SOURCE=.\security.cpp +# End Source File +# Begin Source File + +SOURCE=.\strings.cpp +# End Source File +# Begin Source File + +SOURCE=.\WebAdmin.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\html.h +# End Source File +# Begin Source File + +SOURCE=.\main.h +# End Source File +# Begin Source File + +SOURCE=.\op_winamp.h +# End Source File +# Begin Source File + +SOURCE=.\plugin.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\types.h +# End Source File +# Begin Source File + +SOURCE=.\wamessage.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\Images\about.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\admin.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\black.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\browse.gif +# End Source File +# Begin Source File + +SOURCE=.\browse.ico +# End Source File +# Begin Source File + +SOURCE=.\dir.gif +# End Source File +# Begin Source File + +SOURCE=.\download.gif +# End Source File +# Begin Source File + +SOURCE=.\file.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\frames_one.bmp +# End Source File +# Begin Source File + +SOURCE=.\Images\frames_one_lg.bmp +# End Source File +# Begin Source File + +SOURCE=.\Images\frames_three.bmp +# End Source File +# Begin Source File + +SOURCE=.\Images\frames_three_lg.bmp +# End Source File +# Begin Source File + +SOURCE=.\Images\frames_two.bmp +# End Source File +# Begin Source File + +SOURCE=.\Images\frames_two_lg.bmp +# End Source File +# Begin Source File + +SOURCE=.\icon1.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\list_delete.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\list_play.gif +# End Source File +# Begin Source File + +SOURCE=.\Log.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\main.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\next.gif +# End Source File +# Begin Source File + +SOURCE=".\Images\Title Graphic\No Background.bmp" +# End Source File +# Begin Source File + +SOURCE=.\Images\OK.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\pause.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\play.gif +# End Source File +# Begin Source File + +SOURCE=.\playdir.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\playlist.gif +# End Source File +# Begin Source File + +SOURCE=.\playlist.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\popup.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\prev.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\randomoff.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\randomon.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\repeatoff.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\repeaton.gif +# End Source File +# Begin Source File + +SOURCE=.\server.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\stop.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\stopslow.gif +# End Source File +# Begin Source File + +SOURCE=.\users.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\vol0.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol1.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol10.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol2.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol3.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol4.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol5.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol6.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol7.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol8.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\vol9.gif +# End Source File +# Begin Source File + +SOURCE=.\Images\wa.ico +# End Source File +# Begin Source File + +SOURCE=.\wa.ico +# End Source File +# Begin Source File + +SOURCE=.\wafile.gif +# End Source File +# Begin Source File + +SOURCE=.\webpage.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\winamp.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\world.gif +# End Source File +# End Group +# End Target +# End Project diff --git a/Wawi Source/gen_httpServ.dsw b/Wawi Source/gen_httpServ.dsw new file mode 100644 index 0000000..c15cfe3 --- /dev/null +++ b/Wawi Source/gen_httpServ.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gen_httpServ"=".\gen_httpServ.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Wawi Source/html.cpp b/Wawi Source/html.cpp new file mode 100644 index 0000000..4855339 --- /dev/null +++ b/Wawi Source/html.cpp @@ -0,0 +1,400 @@ +/* --- HTML.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> + +#include "types.h" +#include "main.h" +#include "resource.h" +#include "wamessage.h" +#include "html.h" + +extern int frames; + + +// -------------------------------------------------------------------------------- +// *** HTTP / HTML FUNCTIONS *** + +// Sends HTTP header +void OpenHTTPHeader(connection * conn, char * type, int length, char * filename) +{ + char openstring[200]; + prints(conn,"HTTP/1.0 200 OK\nConnection: close\n"); + + if (StrComp(type,"text/html")) + prints(conn,"Expires: -1\n"); + + if (type != NULL) + { + wsprintf(openstring,"Content-type: %s\n",type); + prints(conn,openstring); + } + if (length != 0) + { + wsprintf(openstring,"Content-length: %d\n",length); + prints(conn,openstring); + } + + if (filename != NULL) + { + wsprintf(openstring,"Content-Disposition: attachment; filename=\"%s\"\n",filename); + prints(conn,openstring); + } + + prints(conn,"\n"); + +} + +// Sends HTML header +void OpenHtmlHeader(connection * conn) +{ + prints(conn,"<html>\n<head>\n<title>\nWinamp Web Interface\n</title>\n"); +} + + +// Sends styles and ends header +void Style(connection * conn) +{ + prints(conn,"<link rel=STYLESHEET href=\"wawi.css\" type=\"text/css\">\n"); +} + +// Sends a header which refreshes to the given URL after a second +void RefreshHeader(connection * conn, char * url) +{ + prints(conn,"<meta http-equiv=\"Refresh\" content=\"1; url="); + prints(conn,url); + prints(conn,"\">\n"); +} + +// Close HTML Header +void CloseHeader(connection * conn) +{ + AboutSource(conn); + prints(conn,"</head>\n"); +} + +// Opens HTML page body +void OpenPageBody(connection * conn) +{ + prints(conn,"<body bgcolor=\"#"); + prints(conn,"EEEEEE"); + prints(conn,"\">"); + //OpenTable(conn); +} + +// Opens HTML header body +void OpenHeaderBody(connection * conn) +{ + prints(conn,"<body leftmargin=\"0\" rightmargin=\"0\" topmargin=\"0\" bgcolor=\"#000000\">\n"); + //OpenTable(conn); +} + +// Closes HTML body +void CloseBody(connection * conn) +{ + //CloseTable(conn); + prints(conn,"</body>\n</html>\n\n"); +} + + +// Open page table +void LinkTable(connection * conn) +{ + prints(conn,"<table border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">\n <tr>\n"); + prints(conn,"<td width=\"2%\" bgcolor=\"#000000\">&nbsp;</td>\n"); + prints(conn,"<td width=\"96%\" bgcolor=\"#000000\">"); + ImgLinkBar(conn); + prints(conn,"</td>\n<td width=\"2%\" bgcolor=\"#000000\">&nbsp;</td>\n</tr>\n</table>\n"); +} + + +// -------------------------------------------------------------------------------- +// Sticks a dot in... separator between stuff +void dot(connection * conn) +{ + prints(conn,"&middot;"); +} + +// Nonbreaking space +void nbsp(connection * conn) +{ + prints(conn,"&nbsp;"); +} + + +// -------------------------------------------------------------------------------- +// Image +void Img(connection * conn, int img, char * alt, int dx, int dy) +{ + prints(conn,"<img border=\"0\" src=\"img?image="); + printsi(conn,img); + prints(conn,"\" alt=\""); + prints(conn,alt); + prints(conn,"\""); + + if (dx != 0 || dy != 0) + { + prints(conn," width=\""); + printsi(conn,dx); + prints(conn,"\" height=\""); + printsi(conn,dy); + prints(conn,"\""); + } + prints(conn,">"); +} + + +// -------------------------------------------------------------------------------- +// Image link +void ImgLink(connection * conn, char * link, int img, char * alt, int dx, int dy, int target) +{ + prints(conn,"<a href=\""); + prints(conn,link); + prints(conn,"\""); + + switch(frames) + { + case 1: if (target == T_TOP) + prints(conn," target=\"_top\""); + break; + case 2: if (target == T_MAIN || target == T_BOTTOM) + prints(conn," target=\"main\""); + if (target == T_TOP) + prints(conn," target=\"_top\""); + break; + case 3: if (target == T_MAIN) + prints(conn," target=\"main\""); + if (target == T_BOTTOM) + prints(conn," target=\"bottom\""); + if (target == T_TOP) + prints(conn," target=\"_top\""); + break; + default: break; + } + + + prints(conn,"><img border=\"0\" src=\"img?image="); + printsi(conn,img); + prints(conn,"\" alt=\""); + prints(conn,alt); + prints(conn,"\">"); + + if (dx != 0 || dy != 0) + { + prints(conn," width=\""); + printsi(conn,dx); + prints(conn,"\" height=\""); + printsi(conn,dy); + prints(conn,"\">"); + } + prints(conn,"</a>"); +} + +// -------------------------------------------------------------------------------- +// Text Link +void Link(connection * conn, char * link, char * text, int target) +{ + prints(conn,"<a href=\""); + prints(conn,link); + prints(conn,"\""); + + switch(frames) + { + case 2: if (target == T_MAIN || target == T_BOTTOM) + prints(conn," target=\"main\""); + break; + case 3: if (target == T_MAIN) + prints(conn," target=\"main\""); + if (target == T_BOTTOM) + prints(conn," target=\"bottom\""); + break; + default: break; + } + + prints(conn,">"); + prints(conn,text); + prints(conn,"</a>"); +} + +// -------------------------------------------------------------------------------- +// Function source for javascript popup about window +void AboutSource(connection * conn) +{ + prints(conn,"<Script language=\"JavaScript\">\nfunction about()\n{\n window.open(\"about\",\"newWin\",\"width=300,height=150\");\n}\n</script>\n\n"); +} + +// -------------------------------------------------------------------------------- +// Displays the volume controls and link bar - Graphics version +void ImgLinkBar(connection * conn) +{ + prints(conn,"<p align=center>\n"); + + // Play control links + ImgLink(conn,"/prev",IDR_IMG_PREV,"Previous Track",0,0,T_BOTTOM); + Img(conn,IDR_IMG_BLACK,"",2,30); + //nbsp(conn); + ImgLink(conn,"/play",IDR_IMG_PLAY,"Play",0,0,T_BOTTOM); + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/pause",IDR_IMG_PAUSE,"Pause",0,0,T_BOTTOM); + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/stop",IDR_IMG_STOP,"Stop",0,0,T_BOTTOM); + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/stopslow",IDR_IMG_STOPSLOW,"Stop with fadeout",0,0,T_BOTTOM); + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/next",IDR_IMG_NEXT,"Next Track",0,0,T_BOTTOM); + + Img(conn,IDR_IMG_BLACK,"",8,30); + + // Volume control links + ImgLink(conn,"/vol?volume=0",IDR_VOL_00,"0/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=1",IDR_VOL_01,"1/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=2",IDR_VOL_02,"2/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=3",IDR_VOL_03,"3/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=4",IDR_VOL_04,"4/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=5",IDR_VOL_05,"5/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=6",IDR_VOL_06,"6/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=7",IDR_VOL_07,"7/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=8",IDR_VOL_08,"8/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=9",IDR_VOL_09,"9/10",0,0,T_BOTTOM); + ImgLink(conn,"/vol?volume=10",IDR_VOL_10,"10/10",0,0,T_BOTTOM); + + Img(conn,IDR_IMG_BLACK,"",8,30); + + // Page navigation links + ImgLink(conn,"/main",IDR_IMG_MAIN,"Main",0,0,T_MAIN); + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/list",IDR_IMG_PLAYLIST,"Playlist",0,0,T_MAIN); + + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/browse?path=%5c",IDR_IMG_BROWSE,"Music Collection",0,0,T_MAIN); + + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + prints(conn,"<script language=\"JavaScript\">\nvar shortcut = new String(document.location);\nvar len = shortcut.lastIndexOf('/');\nshortcut = shortcut.slice(0,len+1);\n"); + prints(conn,"document.write(\"<a href=\\\"javascript:void(weblog=open('\" + shortcut + \"','','width=600,height=360,toolbar=0,location=0,directories=0,status=0,menuBar=0,scrollBars=1,resizable=1'))\\\"><img src=/img?image=\");"); + prints(conn,"\ndocument.write("); + printsi(conn,IDR_IMG_POPUP); + prints(conn,");"); + prints(conn,"\ndocument.write(\" border=\\\"0\\\" alt=\\\"Winamp Web Interface Popup Window\\\"></a>\");\n</script>"); + + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/admin",IDR_IMG_ADMIN,"Wawi Admin",0,0,T_MAIN); + + //nbsp(conn); + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"javascript:about()",IDR_IMG_ABOUT,"About Winamp Web Interface",0,0,T_NONE); + prints(conn,"</p>\n"); + + +} + +// -------------------------------------------------------------------------------- +// Displays the volume controls and link bar - Noframes version +void LinkBar(connection * conn) +{ + prints(conn,"<p align=center>\n"); + + // Volume control links + prints(conn,"Volume: \n"); + for (int i=0;i<=10;i++) + { + prints(conn,"<a href=/vol?volume="); + printsi(conn,i); + prints(conn,">"); + printsi(conn,i); + prints(conn,"</a>\n"); + if (i != 10) + dot(conn); + + } + prints(conn,"<br>\n"); + + // Play control links + prints(conn,"<a href=\"/prev\">Previous</a>\n"); + dot(conn); + prints(conn," <a href=\"/play\">Play</a>\n"); + dot(conn); + prints(conn," <a href=\"/pause\">Pause</a>\n"); + dot(conn); + prints(conn," <a href=\"/stop\">Stop</a>\n"); + dot(conn); + prints(conn," <a href=\"/next\">Next</A>\n"); + + prints(conn,"<br><a href=\"/main\">Main</a>\n"); + dot(conn); + prints(conn," <a href=\"/list\">Playlist</a>\n"); + + dot(conn); + prints(conn," <a href=\"/browse?path=%5c\">Music Collection</a>\n"); + dot(conn); + prints(conn," <a href=\"/admin\">Admin</a>\n"); + + prints(conn,"</p>\n"); +} + +// -------------------------------------------------------------------------------- +// Retrieves and formats the information about the current song +void FullSongInfo(connection * conn) +{ + char tbuffer[255]; + + int status = SendMessage(WAwnd(),WM_USER, 0, WAU_STATUS); + int pos = SendMessage(WAwnd(),WM_USER, 0, WAU_GETPLPOS)+1; + char * trackname = (char*)SendMessage(WAwnd(),WM_USER, pos-1, WAU_GETTITLE); + + //MessageBox(NULL,"Still going!","gen_httpSrv debug",MB_OK); + switch(status) + { + case 1: if (trackname==NULL) + wsprintf(tbuffer,"Winamp is playing"); + else + wsprintf(tbuffer,"Playing track %d - %s - ", pos,trackname); + prints(conn,tbuffer); + PrintTrackTime(conn); + break; + case 3: if (trackname==NULL) + wsprintf(tbuffer,"Winamp is paused"); + else + wsprintf(tbuffer,"Paused in track %d - %s - ", pos,trackname); + prints(conn,tbuffer); + PrintTrackTime(conn); + break; + default: if (trackname==NULL) + wsprintf(tbuffer,"Winamp is stopped"); + else + wsprintf(tbuffer,"Winamp is stopped at track %d - %s", pos, trackname ); + prints(conn,tbuffer); + break; + } +} + +// -------------------------------------------------------------------------------- +// Retrieves and formats a tiny string of the current song information (for /smalltitle) +void SongInfo(connection * conn) +{ + + int status = SendMessage(WAwnd(),WM_USER, 0, WAU_STATUS); + int pos = SendMessage(WAwnd(),WM_USER, 0, WAU_GETPLPOS)+1; + char * trackname = (char*)SendMessage(WAwnd(),WM_USER, pos-1, WAU_GETTITLE); + + //MessageBox(NULL,"Still going!","gen_httpSrv debug",MB_OK); + switch(status) + { + case 1: if (trackname!=NULL) + { + //wsprintf(tbuffer,"%s", pos,trackname); + prints(conn,trackname); + } + break; + default: break; + } +} diff --git a/Wawi Source/html.h b/Wawi Source/html.h new file mode 100644 index 0000000..37d0474 --- /dev/null +++ b/Wawi Source/html.h @@ -0,0 +1,20 @@ +// html.cpp +void OpenHTTPHeader(connection * conn, char * type, int length, char * filename); +void OpenHtmlHeader(connection * conn); +void Style(connection * conn); +void RefreshHeader(connection * conn, char * url); +void CloseHeader(connection * conn); +void OpenPageBody(connection * conn); +void OpenHeaderBody(connection * conn); +void CloseBody(connection * conn); +void LinkTable(connection * conn); +void dot(connection * conn); +void nbsp(connection * conn); +void Img(connection * conn, int img, char * alt, int dx, int dy); +void ImgLink(connection * conn, char * link, int img, char * alt, int dx, int dy, int target); +void Link(connection * conn, char * link, char * text, int target); +void AboutSource(connection * conn); +void ImgLinkBar(connection * conn); +void LinkBar(connection * conn); +void FullSongInfo(connection * conn); +void SongInfo(connection * conn); diff --git a/Wawi Source/main.cpp b/Wawi Source/main.cpp new file mode 100644 index 0000000..60c08e1 --- /dev/null +++ b/Wawi Source/main.cpp @@ -0,0 +1,299 @@ +/* --- MAIN.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include <process.h> +#include <winver.h> +#include "types.h" +#include "plugin.h" +#include "resource.h" + +#include "main.h" + +char szAppName[] = "Winamp Web Interface"; +char szAppVer[10]; // now filled in automagically on startup + + +char mp3root[MAX_PATH]; +char playlistdir[MAX_PATH]; +char filetypes[255]; // file types which will show in the browse bit. +char pagetitle[255]; + +char logfiledir[MAX_PATH]; + +extern char bchars[]; // lookup table for base64 needs to be built on startup +extern char achars[256]; + +// All winamp needs to know about the plugin +winampGeneralPurposePlugin plugin = +{ + GPPHDR_VER, + "", + init, + config, + quit, +}; + + +// Globals for actual server (rather than random winamp things) + +LPDWORD client_thread; +SOCKET server_socket; +int con_port, hide_error, frames, title_refresh; +int show_other_files, dl_wa_files, dl_other_files; + +extern HWND ConfigWnd; + + + + +// -------------------------------------------------------------------------------- +// Entry point of DLL for windows; does nothing +BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + return TRUE; +} + +// -------------------------------------------------------------------------------- +// The interface which Winamp sees- +// It returns the plugin information struct +extern "C" +{ + __declspec( dllexport ) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() + { + return &plugin; + } +} + + + +// -------------------------------------------------------------------------------- +// Startup. This is where interesting things start happening +int init() +{ + + HANDLE newthread; + DWORD newthread_id; + static char c[512]; + char filename[512],*p; + GetModuleFileName(plugin.hDllInstance,filename,sizeof(filename)); + + // Retrieve version info + DWORD versize = GetFileVersionInfoSize(filename, NULL); + char * versiondata = new char[versize]; + GetFileVersionInfo(filename, NULL, versize, versiondata); + VS_FIXEDFILEINFO * info; + UINT verlen; + VerQueryValue(versiondata,"\\",(void**)&info,&verlen); + int ver_l = (int)info->dwFileVersionLS; + int ver_h = (int)info->dwFileVersionMS; + + int ver1, ver2, ver3, ver4; // version of form ver1,ver2,ver3,ver4 + /* + ver1 = (ver_h & 0xFFFF0000) >> 16; + ver2 = (ver_h & 0x0000FFFF); + ver3 = (ver_l & 0xFFFF0000) >> 16; + ver4 = (ver_l & 0x0000FFFF); + */ + ver1 = HIWORD(ver_h); + ver2 = LOWORD(ver_h); + ver3 = HIWORD(ver_l); + ver4 = LOWORD(ver_l); + if (ver3 == 0) + wsprintf(szAppVer,"%u.%u", ver1, ver2); + else + wsprintf(szAppVer,"%u.%u.%u", ver1, ver2, ver3); + + delete versiondata; + + ZeroMemory(achars,256); + for(int i = 0; i < 64; i++) // build lookup table for FromBase64() + achars[bchars[i]] = i; + + p = filename+lstrlen(filename); + while (p >= filename && *p != '\\') p--; + wsprintf((plugin.description=c),"%s Plugin v.%s (%s)",szAppName,szAppVer,p+1); + newthread = CreateThread(NULL,0,HTTPServerThread,0,0,&newthread_id); + return 0; +} + + +// -------------------------------------------------------------------------------- +// Config dialog please +void config() +{ + if (!ConfigWnd) + { + NewConfig(); + ConfigWnd = NULL; + } + else + SetActiveWindow(ConfigWnd); + +} + + +// -------------------------------------------------------------------------------- +// Winamp is saying goodbye +void quit() +{ + // Hmmm. Did there always used to be nothing in here? Curiouser and curiouser... +} + + +// -------------------------------------------------------------------------------- +// Opens the server socket +bool InitServerSocket() +{ + config_read(); + + WORD wVersionRequested = MAKEWORD(2,2); + WSADATA wsaData; + + if (WSAStartup(wVersionRequested, &wsaData ) != 0 ) + { + if (hide_error == 0) + MessageBox(plugin.hwndParent, "ERROR: Winsock not available", "Winamp Web Interface", MB_OK); + return false; + } + + server_socket = socket(AF_INET,SOCK_STREAM,0); + if (server_socket == INVALID_SOCKET) + { + if (hide_error == 0) + MessageBox(plugin.hwndParent, "ERROR: Couldn't create socket", "Winamp Web Interface", MB_OK); + return false; + } + + struct sockaddr_in server_address; + ZeroMemory(&server_address,sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_port = htons(con_port); + + if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) != 0) + { + if (hide_error == 0) + MessageBox(plugin.hwndParent, "ERROR: Couldn't open port", "Winamp Web Interface", MB_OK); + return false; + } + + if (listen(server_socket,5) != 0) + { + if (hide_error == 0) + MessageBox(plugin.hwndParent, "ERROR: Cannot act as server", "Winamp Web Interface", MB_OK); + return false; + } + + return true; // Server socket opened successfully +} + + + + +// -------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------- +// Server main thread entry point +DWORD WINAPI HTTPServerThread(LPVOID param) +{ + + // initialise winsock + if (InitServerSocket()) + { + + //printf("Server is listening for connections on port %d.\n",ntohs(server_address.sin_port)); + + struct sockaddr_in client_address; + SOCKET client_socket; + int client_address_length = sizeof(client_address); + while (true) + { + client_socket = accept(server_socket,(struct sockaddr *) &client_address, &client_address_length); + //printf("Connection request from %s:%d - ", (char*)inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port)); + if (client_socket != INVALID_SOCKET) + { + DWORD connection_id; + client_thread = (DWORD*)CreateThread(NULL,0,ClientConnection,(void*)client_socket, 0, &connection_id); + } + } + + closesocket(server_socket); + } + return true; +} + + + + + +// -------------------------------------------------------------------------------- +// *** WINAMP FUNCTIONS *** +// Returns handle to winamp window +HWND WAwnd() +{ + return plugin.hwndParent; +} + + +// -------------------------------------------------------------------------------- +// Insert a node into a list starting from 'current' +void Insert(fileinfo *newfile, fileinfo *current) +{ + if (GoesBefore(newfile->name,current->name)) // newfile goes before current + { + //wsprintf(tempstring,"%s goes before %s and after %s",newfile->name,current->name, current->prev->name); + //MessageBox(NULL,tempstring,"gen_httpsrv debug goes before",MB_OK); + + if (current->prev != NULL) + current->prev->next = newfile; + + newfile->prev = current->prev; + newfile->next = current; + current->prev = newfile; + + //wsprintf(tempstring,"Order is now %s, %s, %s",newfile->prev->name,newfile->name,newfile->next->name); + //MessageBox(NULL,tempstring,"gen_httpsrv debug goes before result",MB_OK); + } + else + { + if (current->next == NULL) // newfile is after current; current is the last node + { + //wsprintf(tempstring,"%s goes after %s and is the last record",newfile->name,current->name); + //MessageBox(NULL,tempstring,"gen_httpsrv debug after and last",MB_OK); + + current->next = newfile; + newfile->prev = current; + } + else + { // newfile is after current but before something else + Insert(newfile,current->next); // AAARGH! RECURSION! Like hell it'll work... + } + } +} + + +// -------------------------------------------------------------------------------- +// Compare two strings, return TRUE if the first one should be before the second alphabetically + +bool GoesBefore(char *file1, char *file2) +{ + if (file1 == NULL || file2 == NULL) + return true; + + int i=0; + while (ToLowerCase(file1[i]) == ToLowerCase(file2[i])) + { + if (file1[i] == 0) + return true; + i++; + } + if (ToLowerCase(file1[i]) > ToLowerCase(file2[i])) + return false; + else + return true; +} + + + diff --git a/Wawi Source/main.h b/Wawi Source/main.h new file mode 100644 index 0000000..7a43431 --- /dev/null +++ b/Wawi Source/main.h @@ -0,0 +1,96 @@ + +// browse.cpp +void UpDirectory(char * mp3path, char * mp3pathout); +bool IsWinampFile(fileinfo * file); +bool IsWinampFile(char * filename); +void AddFileToList(connection * conn,WIN32_FIND_DATA *find, char* mp3path, filesearch * search); +bool GoodPath(char* mp3path); +int Browse(connection * conn, char * mp3path); + + +// ClientConnection.cpp +DWORD WINAPI ClientConnection(LPVOID socket_param); +void MakeLogEntry(connection * conn); + +// Config.cpp +BOOL CALLBACK ConfigUsersWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +BOOL CALLBACK ConfigAboutWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +BOOL CALLBACK ConfigServerWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +BOOL CALLBACK ConfigWebPageWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +BOOL CALLBACK ConfigBrowseWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +BOOL CALLBACK ConfigLogWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); + +void config_read(); +void config_write(); +void ViewLog(); +void NewConfig(); + +// Config_users.cpp +BOOL CALLBACK ConfigUsersWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +void UpdateUserInfoBoxes(HWND hwndDlg, HWND hwndList, char * ini_file, int item); +void DisplayDlgAccess(HWND hwndDlg, int access); +int GetDlgAccess(HWND hwndDlg); +user * RetrieveUsers(user * users, char * ini_file); +void UpdateUserList(char * ini_file, HWND hwndList); +void UpdateDlgUser(char * ini_file, HWND hwndDlg, HWND hwndList); +void UpdateUser(char * ini_file,char * username, char * password, int access); +void DeleteDlgUser(char * ini_file, HWND hwndDlg, HWND hwndList); +void DeleteUser(char * ini_file, char * username); + +// DeletePlaylistEntry.cpp +int DeletePlaylistEntry(int track); +void FreePlaylist(playlistitem * startitem); +int DeletePlaylistEntry2(connection * conn, int track); + +// main.cpp +BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved); +int init(); +void config(); +void quit(); +bool InitServerSocket(); +DWORD WINAPI HTTPServerThread(LPVOID param); +HWND WAwnd(); +void Insert(fileinfo *file1, fileinfo *file2); +bool GoesBefore(char *file1, char *file2); + +//net_http_html.cpp +void prints(connection * conn, char * string); +void flush(connection * conn); +void printsi(connection * conn, int number); +void ReportError(connection * conn, char * errstring); +void Send400(connection * conn); +bool GetRequest(connection * conn); +bool DecodeUrl(connection * conn); +void ListArgs(connection * conn); +bool GetArgValue(connection * conn, char * name, char * value, int len); +void Unescape_url(char * url); +char x2c(char *what); +void Escape_url(char * url); + + +// security.cpp +bool MD5(char * input, char * output, int output_len); +int SendBasic401(connection * conn,char * realm); +char * FindSubString(char * buffer,char * target); +void FindBasicAuth(connection * conn, char * buffer); +void ToBase64(char * instr, char * outstr); +void FromBase64(char * instr, char * outstr); +int CheckCredentials(connection * conn, char * user, char * pass); +int GetUserAccess(char * ini_file,char * user); + +// strings.cpp +char * GetDelimitedString(char * buffer, char delimiter, char * result, int result_len); +bool GetUnquotedString(char * buffer, char * result, int result_len); +bool GetQuotedString(char * buffer, char * result, int result_len); +bool StartString(char* string1, char* string2); +char * GetAString(char* chptr, char* text); +void PrintTime(connection * conn, int mins, int seconds); +void PrintTrackTime(connection * conn); +void ToLowerCase(char * string); +char ToLowerCase(char c); +bool StrComp(char * string1, char * string2); +void ReplaceSlashes(char * string); +char * GetFilename(char * path); +int atoi2(const char *str ); +bool contains(char * echars,char ch); +char * strstr2(char *string, char *substring); diff --git a/Wawi Source/makepimp.exe b/Wawi Source/makepimp.exe new file mode 100644 index 0000000..1769337 Binary files /dev/null and b/Wawi Source/makepimp.exe differ diff --git a/Wawi Source/net_http_html.cpp b/Wawi Source/net_http_html.cpp new file mode 100644 index 0000000..820efa2 --- /dev/null +++ b/Wawi Source/net_http_html.cpp @@ -0,0 +1,280 @@ +/* --- NET_HTTP_HTML.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include "types.h" +#include "main.h" +#include "resource.h" +#include "html.h" + + +// -------------------------------------------------------------------------------- +// *** SOCKET FUNCTIONS *** +// Low level socket writing function - strings +void prints(connection * conn, char * string) +{ + if (lstrlen(conn->output) + lstrlen(string) >= BUF_LEN) + flush(conn); + lstrcat(conn->output, string); +} + +// Write full buffer down the socket +void flush(connection * conn) +{ + int i = lstrlen(conn->output); + + if (send(conn->socket,conn->output,i,0) == SOCKET_ERROR) + { + //MessageBox(NULL,"Socket send() error!","gen_httpsrv error",MB_OK); + } + // Clear buffer - set first char to null character + conn->output[0] = 0; +} + +// Low level socket writing function - integers +void printsi(connection * conn,int number) +{ + char buffer[256]; + wsprintf(buffer,"%d",number); // Stick it in a string and call prints() + prints(conn,(char*)&buffer); +} + + +// Report an error to the client +void ReportError(connection * conn, char * errstring) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<h3>Error!</h3>\n"); + prints(conn,errstring); + prints(conn,"<p>Back to <a href=\"\\\">main page</a></p>\n"); +} + + +// 400 Bad Request error +void Send400(connection * conn) +{ + prints(conn,"HTTP/1.0 400 Bad Request\nConnection: close\nContent-type: \"text/html\"\n\n"); + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<h3>403 Bad Request</h3>\n"); + prints(conn,"<p>Your browser sent a request that this server could not understand.</p>\n"); + prints(conn,"<p>Invalid URI in request "); + prints(conn,conn->http.request); + prints(conn," "); + prints(conn,conn->http.file); + prints(conn," "); + prints(conn,conn->http.http_version); + prints(conn,"</p>\n<hr>\n<address>Wawi - Winamp HTTP Server</address>\n"); + CloseBody(conn); +}; + + + + + +// -------------------------------------------------------------------------------- +// Receives HTTP header and puts relevant information into http_request structure +bool GetRequest(connection * conn) +{ + char buffer[2048]; + int buffer_len; + int buffer_filled = 0; + int buffer_left; + bool complete = false; + + while(true) + { + // receive data + buffer_len = sizeof(buffer); + buffer_left = buffer_len-buffer_filled; + if (buffer_left <= 0) + buffer_len = 0; + else + buffer_len = recv(conn->socket,buffer + buffer_filled,buffer_len-buffer_filled,0); + + if (buffer_len != SOCKET_ERROR && buffer_len != 0) + { + buffer_filled += buffer_len; + // scan for end of header + for (int i=0;i<=buffer_filled;i++) + if (buffer[i]=='\n' && (buffer[i+1]=='\n' || buffer[i+2]=='\n')) + { + buffer[i+1] = 0; + //MessageBox(NULL,buffer,"gen_httpsrv debug", MB_OK); + char * chptr = (char*)&buffer; + + chptr = GetAString(chptr,conn->http.request); + chptr = GetAString(chptr,conn->http.file); + chptr = GetAString(chptr,conn->http.http_version); + + FindBasicAuth(conn,chptr); + + if (StrComp(conn->http.request,"HEAD")) + conn->http.reqID = RID_HEAD; + else + conn->http.reqID = RID_GET; + + if (!DecodeUrl(conn)) + return false; + //ListArgs(conn); + + return true; + } + } + else + { + return false; + } + } +} + + +// -------------------------------------------------------------------------------- +// Faffs around with the URL; splits 'page' from 'file' and places args in array +bool DecodeUrl(connection * conn) +{ + lstrcpy(conn->http.page,conn->http.file); // make page = file + conn->http.num_args = 0; + char * chptr = conn->http.file; + while (chptr[0] != '?') // skip past '?' url?name=value + { + if (chptr[0] == 0) + { + //MessageBox(NULL,"No args","decodeurl",MB_TOPMOST | MB_OK); + return true; // no '?', no arguments + } + chptr++; + } + + chptr[0] = 0; + lstrcpy(conn->http.page,conn->http.file); // alter page to remove arguments + chptr[0] = '?'; + + chptr++; + + //char temp[100]; + + int x=0; + while(x < 50) // max name/value pairs; usually stopped by return in loop + { + chptr = GetDelimitedString(chptr,'=',conn->http.pairs[x].name,30); + if (chptr == NULL) + { + //MessageBox(NULL,"no value","decodeurl",MB_TOPMOST | MB_OK); + return false; + } + chptr++; + chptr = GetDelimitedString(chptr,'&',conn->http.pairs[x].value,128); + if (chptr == NULL) + { + //MessageBox(NULL,"All args","decodeurl",MB_TOPMOST | MB_OK); + conn->http.num_args = x+1; + return true; + } + chptr++; + //wsprintf(temp,"name: %s\nvalue: %s",conn->http.pairs[x].name,conn->http.pairs[x].value); + //MessageBox(NULL,temp,"arg",MB_OK | MB_TOPMOST); + + x++; + } + return false; +} + +// -------------------------------------------------------------------------------- +// Test function to list the arguments retrieved from the requested URL +void ListArgs(connection * conn) +{ + int x=0; + char string[100]; + while (conn->http.pairs[x].name[0] != 0) + { + wsprintf(string,"Name: %s\nValue: %s",conn->http.pairs[x].name,conn->http.pairs[x].value); + MessageBox(NULL,string,"args",MB_OK | MB_TOPMOST); + x++; + } +} + +// -------------------------------------------------------------------------------- +// Return the value of an argument +bool GetArgValue(connection * conn, char * name, char * value, int len) +{ + int x=0; + while(conn->http.pairs[x].name[0] != 0) + { + if (StrComp(name,conn->http.pairs[x].name)) + { + //MessageBox(NULL,conn->http.pairs[x].value,"found",MB_OK | MB_TOPMOST); + lstrcpyn(value,conn->http.pairs[x].value,len); + for (int i=0;i<lstrlen(value);i++) + if (value[i]=='+') + value[i] = ' '; + return true; + } + x++; + } + return false; +} + +// -------------------------------------------------------------------------------- +// Removes '%20's and the like from a string +void Unescape_url(char * url) +{ + int x,y; + + for(x=0,y=0;url[y];++x,++y) { + if((url[x] = url[y]) == '%') + { + url[x] = x2c(&url[y+1]); + y+=2; + } + } + url[x] = 0; +} + +// -------------------------------------------------------------------------------- +// Returns a single character from a '%xx' string +char x2c(char *what) +{ + char digit; + + digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0')); + return(digit); +} + +// -------------------------------------------------------------------------------- +// Formats string into a URL properly +void Escape_url(char * url) +{ + char echars[] = " <>#%{}|\\^~[]`;/?:@=&"; // characters which have to be escaped + char eurl[255]; + int x=0,y=0; + while (url[x] != 0) + { + if (contains(echars,url[x])) + { + wsprintf(eurl+y,"%%%2x",url[x]); + y+=3; + x++; + } + else + { + eurl[y] = url[x]; + y++; + x++; + } + } + eurl[y] = 0; + lstrcpy(url,eurl); +} + diff --git a/Wawi Source/op_winamp.cpp b/Wawi Source/op_winamp.cpp new file mode 100644 index 0000000..aff98b2 --- /dev/null +++ b/Wawi Source/op_winamp.cpp @@ -0,0 +1,1027 @@ +/* --- OP_WINAMP.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include "types.h" +#include "main.h" +#include "plugin.h" +#include "html.h" +#include "wamessage.h" +#include "op_winamp.h" +#include "resource.h" + +extern char mp3root[MAX_PATH], playlistdir[MAX_PATH], logfiledir[MAX_PATH], filetypes[255]; +extern int browse_enable, dl_wa_files, dl_other_files, show_other_files, frames, title_refresh, securepassword; + +extern char szAppVer[]; +extern char pagetitle[255]; + + +extern winampGeneralPurposePlugin plugin; + +// -------------------------------------------------------------------------------- +// Send an image from a resource +int CControl::Image(connection * conn,int type) +{ + //char * img = &conn->http.file[5]; + char img[30]; + GetArgValue(conn,"image",(char*)&img,30); + //MessageBox(NULL,img,"gen_httpSrv debug",MB_OK | MB_TOPMOST); + int imageid = atoi2(img); + + char dll[MAX_PATH]; + GetModuleFileName(plugin.hDllInstance,dll,sizeof(dll)); + HMODULE hm = GetModuleHandle(dll); + if (hm == NULL) + MessageBox(NULL,"gmh failed","gen_httpSrv debug",MB_OK); + + HRSRC resimage = FindResource(hm,MAKEINTRESOURCE(imageid),"Image"); + if (!resimage) // after an image that doesn't exist + { + + //MessageBox(NULL,"Bad image","gen_httpSrv debug",MB_OK); + return ST_CLOSE; + //closesocket(conn.socket); + //return true; + } + + HGLOBAL image = LoadResource(hm, resimage); + DWORD imglen = SizeofResource(hm, resimage); + + switch(type) + { + case IMG_GIF: + OpenHTTPHeader(conn,"image/gif",(int)imglen,NULL); + break; + case IMG_ICO: + OpenHTTPHeader(conn,"image/x-icon",(int)imglen,NULL); + break; + } + + if(conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + flush(conn); + send(conn->socket,(char*)image,imglen,0); + return ST_CLOSE; +} + +// -------------------------------------------------------------------------------- +// Sends top frame with buttons and the like +int CControl::TopFrame(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + CloseHeader(conn); + OpenHeaderBody(conn); + LinkTable(conn); + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Tiny title +int CControl::SmallTitle(connection * conn) +{ + conn->log = false; + OpenHTTPHeader(conn,"text/plain",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + SongInfo(conn); + prints(conn,"\n\n"); + + return ST_CLOSE; +} + +// -------------------------------------------------------------------------------- +// Sends full title information +int CControl::Title(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + else + { + OpenHtmlHeader(conn); + prints(conn,"<meta http-equiv=\"Refresh\" content=\""); + printsi(conn,title_refresh); + prints(conn,"; url=/title\">\n"); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + FullSongInfo(conn); + + prints(conn,"\n"); + + return ST_CLOSEBODY; + } +} + +// -------------------------------------------------------------------------------- +// Shuts down winamp and the computer, in theory. Doesn't, though... +int CControl::Shutdown(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Turning off...</p>\n"); + + ExitWindows(0,0); + PostMessage(WAwnd(),WM_CLOSE,0,0); + + return ST_CLOSEBODY; +} + + +// -------------------------------------------------------------------------------- +// Clears playlist +int CControl::Clear(connection * conn) +{ + SendMessage(WAwnd(),WM_USER,0,WAU_CLEARPLIST); + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + RefreshHeader(conn,"/list"); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Playlist cleared</p>\n"); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Download a song +int CControl::Download(connection * conn) +{ + // exactly the same filename processing as Load, below. + char filepath[MAX_PATH]; + GetArgValue(conn,"file",filepath,MAX_PATH); + + //char *relfilepath = &conn->http.file[4]; + Unescape_url(filepath); + ReplaceSlashes(filepath); + + if (!GoodPath(filepath)) + ReportError(conn,"<p>The path requested is illegal.</p>\n<p>It cotains the <b>..</b> directory, which could present a security risk.</p>\n"); + else + { + bool wafile = IsWinampFile(GetFilename(filepath)); + + if ((wafile && dl_wa_files==0) || (!wafile && dl_other_files==0)) + ReportError(conn,"<p>Downloading files of this type is not permitted from this server.</p>"); + else + { + char fullfilepath[MAX_PATH]; + int pathlen = wsprintf(fullfilepath,"%s%s",mp3root,filepath); + Unescape_url((char*)&fullfilepath); + + /* + - Open a header with the right MIME type - needs file size + - Call TransmitFile() + - Rockin'. + */ + + HANDLE hFile = CreateFile( fullfilepath, + GENERIC_READ, + 0, + 0, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + 0); + if (hFile == INVALID_HANDLE_VALUE) + ReportError(conn,"<p>Couldn't open the file.</p>\n<p>Check the file exists and the name is correct.</p>\n"); + else + { + DWORD dwSize = GetFileSize(hFile, NULL); + OpenHTTPHeader(conn,"audio/mpeg",dwSize,GetFilename(fullfilepath)); + + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + flush(conn); + + TransmitFile(conn->socket, hFile, dwSize, 0, NULL, NULL, NULL); + CloseHandle(hFile); + return ST_CLOSE; + } + } + } + return ST_CLOSEBODY; +} + + + + +// -------------------------------------------------------------------------------- +// Load a song into the playlist +int CControl::Load(connection * conn) +{ + char relfilepath[MAX_PATH]; + char filepath[MAX_PATH]; + char shortcutfilepath[MAX_PATH]; + char playmode[10]; + GetArgValue(conn,"path",relfilepath,MAX_PATH); + Unescape_url(relfilepath); + + char refreshto[MAX_PATH]; + + if (relfilepath[0] == '\\' && relfilepath[1] != '\\') // single slash - local file (not UNC '\\' or HTTP 'http://...') + { + if (!GoodPath(relfilepath)) + { + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p><b>Error!</b> The path requested is illegal.</p>\n"); + prints(conn,"<p>&nbsp;</p>\n"); + return ST_CLOSEBODY; + } + else // Local path is okay + { + // need to check whether it's a url shortcut file + fileinfo file; + lstrcpy(file.name,relfilepath); + IsWinampFile(&file); + if (file.urlsct) // url shortcut; load contained address into 'filepath' + { + wsprintf(shortcutfilepath,"%s%s",mp3root,relfilepath); + GetPrivateProfileString("InternetShortcut","URL","",filepath,MAX_PATH,shortcutfilepath); + } + else // not a shortcut; just put the right path into filepath + { + wsprintf(filepath,"%s%s",mp3root,relfilepath); + } + + // refresh to "/browse?path=<directory containing file>" + char * p; + if (frames == 3) + wsprintf(refreshto,"/title"); + else + { + char refreshtemp[MAX_PATH]; + wsprintf(refreshtemp,"%s",relfilepath); + + p=refreshtemp+lstrlen(refreshtemp); + while (p >= refreshtemp && *p != '\\') p--; + if (++p >= refreshtemp) *p = 0; + Escape_url(refreshtemp); + wsprintf(refreshto,"/browse?path=%s",refreshtemp); + } + } + } + else // HTTP or UNC name; load directly + { + wsprintf(filepath,"%s",relfilepath); + } + + //MessageBox(NULL,filepath,"filepath",MB_OK | MB_TOPMOST); + + + int pathlen = lstrlen(filepath); + COPYDATASTRUCT cds; + cds.dwData = IPC_PLAYFILE; + cds.lpData = (void *)&filepath; + cds.cbData = pathlen+1; + SendMessage(WAwnd(),WM_COPYDATA,(WPARAM)NULL,(LPARAM)&cds); + + if (GetArgValue(conn,"play",playmode,10)) + { + if (StrComp(playmode,"now")) + { + int pl_len = SendMessage(WAwnd(),WM_USER,0,WAU_PLCOUNT); + SendMessage(WAwnd(),WM_USER,pl_len-1,WAU_SETPLPOS); + SendMessage(WAwnd(),WM_COMMAND,WAC_PLAY,0); + } + } + + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + GetArgValue(conn,"refresh",refreshto,10); // will overwrite existing value if + // the param exists + + OpenHtmlHeader(conn); + Style(conn); + + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<p>Load file command sent: &nbsp; <b>"); + prints(conn,relfilepath); // actually relfilepath + prints(conn,"</b></p>\n"); + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Send playlist page +int CControl::List(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + + if (frames == 1) + LinkBar(conn); + + prints(conn,"<h3>\n<i>\n... Current Playlist ...\n</i></h3>\n"); + + prints(conn,"<form action=\"/list\" method=\"get\">\n"); + prints(conn,"Show only songs containing: <input type=\"text\" name=\"sub\" size=\"30\">\n"); + prints(conn,"<input type=\"submit\" value=\"Search\">\n"); + prints(conn,"</form>\n"); + + prints(conn,"<h6>\n<a href=\"#current\">Jump to Current Track</a>&nbsp;|&nbsp;"); + prints(conn,"<a href=\"/sort\">Sort Playlist</a>&nbsp;|&nbsp;<a href=\"/clear\">Clear Playlist</a>"); + prints(conn,"&nbsp;|&nbsp;<a href=\"save\">Save Playlist</a></h6>\n<ol>\n"); + + char song[255], lcasesong[255], substring[255]; + + bool restrict = GetArgValue(conn,"sub",substring,255); // search for substring? + if (restrict && substring[0] == 0) // if it's blank, show all + restrict = false; + + if (restrict) + { + Unescape_url(substring); + CharLower(substring); + prints(conn,"<p>Showing songs containing: "); + prints(conn,substring); + prints(conn,"</p>\n"); + } + + prints(conn,"<ol>\n"); + + int current = SendMessage(WAwnd(),WM_USER, 0, WAU_GETPLPOS); + char tbuffer[255]; + int t = SendMessage(WAwnd(),WM_USER, 0, WAU_PLCOUNT); + for (int count=0;count<t;count++) + { + lstrcpy(song,(char*)SendMessage(WAwnd(),WM_USER, count, WAU_GETTITLE)); + lstrcpy(lcasesong,song); + CharLower(lcasesong); + if (strstr2(lcasesong,substring) || restrict == false) + { + if (count == current) + prints(conn,"<b><a name=\"current\"></a>"); + + prints(conn,"<li>"); + + wsprintf(tbuffer,"/delete?track=%d",count+1); + ImgLink(conn,tbuffer,IDR_IMG_LIST_DEL,"Remove",0,0,T_MAIN); + wsprintf(tbuffer,"/play?track=%d",count+1); + ImgLink(conn,tbuffer,IDR_IMG_LIST_PLAY,"Play",0,0,T_BOTTOM); + + if (frames == 3) + wsprintf(tbuffer,"<a href=\"/play?track=%d\" target=\"bottom\">%s</a></li>\n", count+1, song); + else + wsprintf(tbuffer,"<a href=\"/play?track=%d\" >%s</a></li>\n", count+1, song); + + prints(conn,tbuffer); + if (count == current) + prints(conn,"</b>"); + } + + } + + prints(conn,"</ol>\n</p>"); + if (frames == 1) + LinkBar(conn); + prints(conn,"<p>&nbsp;</p>"); + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Next track +int CControl::Next(connection * conn) +{ + SendMessage(WAwnd(),WM_COMMAND,WAC_NEXT,0); + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Next track command sent</p>\n"); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Previous track +int CControl::Prev(connection * conn) +{ + SendMessage(WAwnd(),WM_COMMAND,WAC_PREV,0); + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + RefreshHeader(conn,refreshto); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Previous track command sent</p>\n"); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Start playback +int CControl::Play(connection * conn) +{ + char strtrack[10]; + if (GetArgValue(conn,"track",strtrack,10)) + { + int track = atoi2(strtrack) - 1; + if (track >= 0) + SendMessage(WAwnd(),WM_USER,track,WAU_SETPLPOS); + } + + SendMessage(WAwnd(),WM_COMMAND,WAC_PLAY,0); + + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Play command sent</p>\n"); + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Stop playback +int CControl::Stop(connection * conn) +{ + SendMessage(WAwnd(),WM_COMMAND,WAC_STOP,0); + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + OpenHtmlHeader(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + RefreshHeader(conn,refreshto); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Stop command sent</p>\n"); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Stop with fadeout +int CControl::StopSlow(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Stopping..."); + flush(conn); + SendMessage(WAwnd(),WM_COMMAND,WAC_STOPFADE,0); + prints(conn," OK!</p>\n"); + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Pause. Why am I even bothering to comment these?!? +int CControl::Pause(connection * conn) +{ + SendMessage(WAwnd(),WM_COMMAND,WAC_PAUSE,0); + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + RefreshHeader(conn,refreshto); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Pause command sent</p>\n"); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Change volume +int CControl::Volume(connection * conn) +{ + char strvol[20]; + GetArgValue(conn,"volume",strvol,20); + + int vol = atoi2(strvol); // Mwuahaha, die Clib + vol = (int)(vol * 25.5); + SendMessage(WAwnd(),WM_USER,vol,122); + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + { + if (frames == 3) + wsprintf(refreshto,"/title"); + else + wsprintf(refreshto,"/main"); + } + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<p>Change volume command sent</p>\n"); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Change repeat / random modes +int CControl::Playmode(connection * conn) +{ + char repeat[10], random[10]; + if (!GetArgValue(conn,"repeat",repeat,10)) + wsprintf(repeat,"none"); + if (!GetArgValue(conn,"random",random,10)) + wsprintf(random,"none"); + + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + wsprintf(refreshto,"/main"); + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + + if (StrComp(repeat,"on")) + { + SendMessage(WAwnd(),WM_USER,1,WAU_SETREPEAT); + prints(conn,"<p>Repeat set to <b>ON</b></p>"); + } + if (StrComp(repeat,"off")) + { + SendMessage(WAwnd(),WM_USER,0,WAU_SETREPEAT); + prints(conn,"<p>Repeat set to <b>OFF</b></p>"); + } + if (StrComp(repeat,"toggle")) + { + SendMessage(WAwnd(),WM_COMMAND,WAC_REPEATT,0); + prints(conn,"<p>Repeat toggled</p>"); + } + + if (StrComp(random,"on")) + { + SendMessage(WAwnd(),WM_USER,1,WAU_SETRANDOM); + prints(conn,"<p>Random set to <b>ON</b></p>"); + } + if (StrComp(random,"off")) + { + SendMessage(WAwnd(),WM_USER,0,WAU_SETRANDOM); + prints(conn,"<p>Random set to <b>OFF</b></p>"); + } + if (StrComp(random,"toggle")) + { + SendMessage(WAwnd(),WM_COMMAND,WAC_RANDOMT,0); + prints(conn,"<p>Random toggled</p>"); + } + + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// About box +int CControl::About(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + prints(conn,"<body>\n"); + prints(conn,"<p align=center><b>Winamp Web Interface</b><br>\nVersion "); + prints(conn,szAppVer); + prints(conn,"</p>\n"); + prints(conn,"<p align=center>\n<i>\nPhil Himsworth 2002<br>\n"); + prints(conn,"<a href=mailto:contact@flippet.net>contact@flippet.net</a>&nbsp;&middot;&nbsp;<a href=http://www.flippet.net target=\"AnotherWindow\">www.flippet.net</a>\n</i>\n</p>\n\n"); + prints(conn,"</body>\n"); + flush(conn); + closesocket(conn->socket); + return ST_CLOSEBODY; +} + +// -------------------------------------------------------------------------------- +// Main window +int CControl::Main(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<h1 align=center>\n<i>\n"); + prints(conn,pagetitle); + prints(conn,"\n</i>\n\n</h1>\n"); + + prints(conn,"<h6 align=center>\n<a href=\"JavaScript:about()\">About Winamp Web Interface v."); + prints(conn,szAppVer); + prints(conn,"</a></h6>"); + + prints(conn,"<hr>\n"); + + prints(conn,"<h3>\n<i>\n... Winamp Status ...\n</i></h3>\n"); + prints(conn,"<p>\n"); + + FullSongInfo(conn); + prints(conn,"</p>\n"); + + int repeat = SendMessage(WAwnd(),WM_USER,0,WAU_GETREPEAT); + int random = SendMessage(WAwnd(),WM_USER,0,WAU_GETRANDOM); + + prints(conn,"<p>Repeat is "); + if (repeat == 1) + prints(conn,"<b>on</b> "); + if (repeat == 0) + prints(conn,"<b>off</b> "); + + prints(conn,"[ "); + Link(conn,"/playmode?repeat=on","on",T_NONE); + prints(conn," | "); + Link(conn,"/playmode?repeat=off","off",T_NONE); + prints(conn," | "); + Link(conn,"/playmode?repeat=toggle","toggle",T_NONE); + prints(conn," ]"); + + prints(conn,"<br>Random is "); + if (random == 1) + prints(conn,"<b>on</b> "); + if (random == 0) + prints(conn,"<b>off</b> "); + + prints(conn,"[ "); + Link(conn,"/playmode?random=on","on",T_NONE); + prints(conn," | "); + Link(conn,"/playmode?random=off","off",T_NONE); + prints(conn," | "); + Link(conn,"/playmode?random=toggle","toggle",T_NONE); + prints(conn," ]"); + + prints(conn,"</p>\n"); + + if (frames == 1) + LinkBar(conn); + + return ST_CLOSEBODY; +} + + +// -------------------------------------------------------------------------------- +// PDA mode - small +int CControl::pda(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + CloseHeader(conn); + prints(conn,"<body bgcolor=\"#000000\">\n"); + prints(conn,"<p align=\"center\">\n"); + + ImgLink(conn,"/prev?refresh=pda",IDR_IMG_PREV,"Previous Track",0,0,T_NONE); + + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/play?refresh=pda",IDR_IMG_PLAY,"Play",0,0,T_NONE); + + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/pause?refresh=pda",IDR_IMG_PAUSE,"Pause",0,0,T_NONE); + + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/stop?refresh=pda",IDR_IMG_STOP,"Stop",0,0,T_NONE); + + Img(conn,IDR_IMG_BLACK,"",2,30); + ImgLink(conn,"/next?refresh=pda",IDR_IMG_NEXT,"Next Track",0,0,T_NONE); + + prints(conn,"</p>\n<p align=\"center\">\n"); + // Volume control links + ImgLink(conn,"/vol?volume=0&refresh=pda",IDR_VOL_00,"0/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=1&refresh=pda",IDR_VOL_01,"1/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=2&refresh=pda",IDR_VOL_02,"2/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=3&refresh=pda",IDR_VOL_03,"3/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=4&refresh=pda",IDR_VOL_04,"4/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=5&refresh=pda",IDR_VOL_05,"5/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=6&refresh=pda",IDR_VOL_06,"6/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=7&refresh=pda",IDR_VOL_07,"7/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=8&refresh=pda",IDR_VOL_08,"8/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=9&refresh=pda",IDR_VOL_09,"9/10",0,0,T_NONE); + ImgLink(conn,"/vol?volume=10&refresh=pda",IDR_VOL_10,"10/10",0,0,T_NONE); + + prints(conn,"\n</p>\n<p align=\"center\">\n"); + + int repeat = SendMessage(WAwnd(),WM_USER,0,WAU_GETREPEAT); + int random = SendMessage(WAwnd(),WM_USER,0,WAU_GETRANDOM); + + if (repeat) + ImgLink(conn,"/playmode?repeat=toggle&refresh=pda",IDR_IMG_RPT_ON,"Toggle Repeat",0,0,T_NONE); + else + ImgLink(conn,"/playmode?repeat=toggle&refresh=pda",IDR_IMG_RPT_OFF,"Toggle Repeat",0,0,T_NONE); + + if (random) + ImgLink(conn,"/playmode?random=toggle&refresh=pda",IDR_IMG_RND_ON,"Toggle Random",0,0,T_NONE); + else + ImgLink(conn,"/playmode?random=toggle&refresh=pda",IDR_IMG_RND_OFF,"Toggle Random",0,0,T_NONE); + + prints(conn,"</p>\n"); + + return ST_CLOSEBODY; +} + + + +// -------------------------------------------------------------------------------- +// Delete playlist entry. Uses DeletePlaylistEntry2() +int CControl::Delete(connection * conn) // using Playlist Window message +{ + char strtrack[20]; + GetArgValue(conn,"track",strtrack,20); + int track = atoi2(strtrack); + return DeletePlaylistEntry2(conn,track-1); +} + +// -------------------------------------------------------------------------------- +// Returns wawi.css +int CControl::UserStyle(connection * conn) +{ + OpenHTTPHeader(conn,"text/plain",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + char style_file[MAX_PATH], *p; + GetModuleFileName(plugin.hDllInstance,style_file,sizeof(style_file)); + p=style_file+lstrlen(style_file); + while (p >= style_file && *p != '\\') p--; + if (++p >= style_file) *p = 0; + lstrcat(style_file,"wawi.css"); + + HANDLE hFile = CreateFile( style_file, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + prints(conn,"BODY\n{\nFONT-FAMILY: arial,sans-serif\n}\nA:link\n{\nCOLOR: blue;\nTEXT-DECORATION: none\n}\nA:visited\n{\nCOLOR: blue;\nTEXT-DECORATION: none\n}\nA:active\n{\nCOLOR: #ff9050;\nTEXT-DECORATION: none\n}\nA:hover\n{\nCOLOR: #e4a029;\nTEXT-DECORATION: none\n}\n\n"); + return ST_CLOSE; + } + + DWORD dwSize = GetFileSize(hFile, NULL); + + flush(conn); + + TransmitFile(conn->socket, hFile, dwSize, 0, NULL, NULL, NULL); + CloseHandle(hFile); + prints(conn,"\n\n"); + return ST_CLOSE; + +} + +// -------------------------------------------------------------------------------- +// Sorts playlist +int CControl::Sort(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + wsprintf(refreshto,"/list"); + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<p>Sorting..."); + flush(conn); + HWND playlistwnd = FindWindow("Winamp PE","Winamp Playlist Editor"); + if (playlistwnd == NULL) + prints(conn,"<b>Error</b>: Couldn't find Winamp Playlist window...</p>"); + else + { + SendMessage(playlistwnd,WM_COMMAND,PLC_SORTTITLE,0); + prints(conn," OK!</p>\n"); + } + + return ST_CLOSEBODY; + +} + +// -------------------------------------------------------------------------------- +// Saves playlist +int CControl::SavePlaylist(connection * conn) +{ + OpenHTTPHeader(conn,"text/html",0,NULL); + if (conn->http.reqID == RID_HEAD) + return ST_CLOSE; + + OpenHtmlHeader(conn); + Style(conn); + + char location[MAX_PATH]; + char nicelocation[MAX_PATH]; + char fulllocation[MAX_PATH]; + + // see if a location is specified; ask if not + if (!GetArgValue(conn,"location",location,MAX_PATH)) + { + // no location; pop up form + + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<h3><i>... Save Playlist ... </i></h3>\n"); + prints(conn,"<form action=\"/save\" method=\"get\">\n"); + prints(conn,"<p> Playlist Name: <input type=\"text\" name=\"location\" size=\"40\">\n"); + prints(conn,"<input type=\"submit\" value=\"Save\"></p>\n"); + prints(conn,"</form>\n"); + prints(conn,"<p>&nbsp;</p>\n"); + Link(conn,"/list","Return to Playlist",T_NONE); + } + else + { + char refreshto[MAX_PATH]; + if (!GetArgValue(conn,"refresh",refreshto,10)) + wsprintf(refreshto,"/list"); + + // location given; save it to mp3root \ playlist directory \ location + int dirlen = strlen(playlistdir); + if (dirlen == 0) + wsprintf(nicelocation,"%s.m3u",location); + else + wsprintf(nicelocation,"%s\\%s.m3u",playlistdir,location); + + wsprintf(fulllocation,"%s\\%s",mp3root,nicelocation); + + //MessageBox(NULL,fulllocation,nicelocation,MB_OK | MB_TOPMOST); + + SendMessage(WAwnd(),WM_USER,0,WAU_PLSAVE); + + // Find winamp.m3u; it's in the same dir as exe of current process. + DWORD wapid = GetWindowThreadProcessId(WAwnd(),NULL); + HMODULE hMod = (HMODULE)OpenProcess(PROCESS_ALL_ACCESS,false,wapid); + + char playlistfile[MAX_PATH], *p; + GetModuleFileName(hMod,playlistfile,sizeof(playlistfile)); + CloseHandle(hMod); + + // Make \path\winamp.exe into \path\winamp.m3u + p=playlistfile+lstrlen(playlistfile); + while (p >= playlistfile && *p != '\\') p--; + if (++p >= playlistfile) *p = 0; + lstrcat(playlistfile,"winamp.m3u"); + + if (CopyFile(playlistfile,fulllocation,true) == 0) + { + // function failed; try again + if (CopyFile(playlistfile,fulllocation,false) == 0) + { + // failed totally; tell them + + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<p><b>Error!</b></p><p>Couldn't save the playlist to <b>"); + prints(conn,nicelocation); + prints(conn,"</b></p>\n<p>Does the directory exist?</p>"); + Link(conn,"list","Back to Playlist",T_NONE); + } + else + { + // file overwritten + + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<p>Playlist saved to <b>"); + prints(conn,nicelocation); + prints(conn,"<b>\n<p>Previous playlist overwritten.</p>\n"); + } + } + else + { + // file copied ok + + RefreshHeader(conn,refreshto); + CloseHeader(conn); + OpenPageBody(conn); + + prints(conn,"<p>Playlist saved to <b>"); + prints(conn,nicelocation); + prints(conn,"</b></p>\n"); + } + + } + + if (frames == 1) + LinkBar(conn); + + return ST_CLOSEBODY; + +} \ No newline at end of file diff --git a/Wawi Source/op_winamp.h b/Wawi Source/op_winamp.h new file mode 100644 index 0000000..5f00395 --- /dev/null +++ b/Wawi Source/op_winamp.h @@ -0,0 +1,35 @@ +// op_winamp.cpp + +class CControl +{ +public: + int Image(connection * conn,int type); + int TopFrame(connection * conn); + int SmallTitle(connection * conn); + int Title(connection * conn); + int Shutdown(connection * conn); + int Clear(connection * conn); + int Download(connection * conn); + int Load(connection * conn); + int List(connection * conn); + int Next(connection * conn); + int Prev(connection * conn); + int Play(connection * conn); + int Stop(connection * conn); + int StopSlow(connection * conn); + int Pause(connection * conn); + int Volume(connection * conn); + int Playmode(connection * conn); + int About(connection * conn); + int Main(connection * conn); + int WebAdmin(connection * conn); + int ApplyAdmin(connection * conn); + int pda(connection * conn); + int Delete(connection * conn); + int User(connection * conn); + int SetUser(connection * conn); + int UserStyle(connection * conn); + int Sort(connection * conn); + int SavePlaylist(connection * conn); + +}; diff --git a/Wawi Source/pimp.bat b/Wawi Source/pimp.bat new file mode 100644 index 0000000..022391f --- /dev/null +++ b/Wawi Source/pimp.bat @@ -0,0 +1,2 @@ +@echo off +makepimp gen_httpsrv.psc diff --git a/Wawi Source/playdir.gif b/Wawi Source/playdir.gif new file mode 100644 index 0000000..be8c184 Binary files /dev/null and b/Wawi Source/playdir.gif differ diff --git a/Wawi Source/playlist.gif b/Wawi Source/playlist.gif new file mode 100644 index 0000000..a755577 Binary files /dev/null and b/Wawi Source/playlist.gif differ diff --git a/Wawi Source/plugin.h b/Wawi Source/plugin.h new file mode 100644 index 0000000..d37ca7c --- /dev/null +++ b/Wawi Source/plugin.h @@ -0,0 +1,14 @@ +typedef struct { + int version; + char *description; + int (*init)(); + void (*config)(); + void (*quit)(); + HWND hwndParent; + HINSTANCE hDllInstance; +} winampGeneralPurposePlugin; + +#define GPPHDR_VER 0x10 + +extern winampGeneralPurposePlugin *gen_plugins[256]; +typedef winampGeneralPurposePlugin * (*winampGeneralPurposePluginGetter)(); diff --git a/Wawi Source/resource.h b/Wawi Source/resource.h new file mode 100644 index 0000000..fb86592 --- /dev/null +++ b/Wawi Source/resource.h @@ -0,0 +1,118 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Resource.rc +// +#define IDABOUT 3 +#define IDC_VIEWLOG 4 +#define IDUSERS 5 +#define IDD_DIALOG1 101 +#define IDR_DIRECTORY 107 +#define IDR_WAFILE 110 +#define IDR_PLAYLIST 111 +#define IDR_FILE 112 +#define IDR_DOWNLOAD 113 +#define IDR_IMG_ABOUT 114 +#define IDR_IMG_STOP 115 +#define IDR_IMG_MAIN 116 +#define IDR_IMG_NEXT 117 +#define IDR_IMG_PAUSE 118 +#define IDR_IMG_PLAY 119 +#define IDR_IMG_PLAYLIST 120 +#define IDR_IMG_PREV 121 +#define IDR_IMG_BROWSE 122 +#define IDR_IMG_BLACK 123 +#define IDR_VOL_09 124 +#define IDR_VOL_10 125 +#define IDR_VOL_02 126 +#define IDR_VOL_03 127 +#define IDR_VOL_04 128 +#define IDR_VOL_05 129 +#define IDR_VOL_06 130 +#define IDR_VOL_07 131 +#define IDR_VOL_08 132 +#define IDR_VOL_01 133 +#define IDR_VOL_00 134 +#define IDR_IMG_POPUP 135 +#define IDR_IMG_STOPSLOW 136 +#define IDR_PLAYDIR 137 +#define IDD_USERS 138 +#define IDR_ICO_WINAMP 141 +#define IDR_URLSCT 142 +#define IDR_IMG_ADMIN 143 +#define IDR_IMG_OK 144 +#define IDR_IMG_RPT_ON 145 +#define IDR_IMG_RND_ON 146 +#define IDR_IMG_RPT_OFF 147 +#define IDR_IMG_RND_OFF 148 +#define IDR_IMAGE1 150 +#define IDR_IMG_LIST_DEL 151 +#define IDR_IMG_LIST_PLAY 152 +#define IDD_SERVER 153 +#define IDD_WEBPAGE 154 +#define IDD_BROWSE 156 +#define IDD_ABOUT 157 +#define IDD_LOG 158 +#define IDI_USERS 159 +#define IDI_SERVER 160 +#define IDI_WEBPAGE 161 +#define IDI_BROWSE 162 +#define IDI_LOG 163 +#define IDB_FRAMES_TWO 164 +#define IDB_FRAMES_THREE 165 +#define IDB_FRAMES_ONE 166 +#define IDI_WINAMP 168 +#define IDB_TITLE 170 +#define IDC_PORT_EDIT 1000 +#define IDC_HIDE_ERROR 1001 +#define IDC_MP3_ROOT 1002 +#define IDC_PLAYLISTDIR 1003 +#define IDC_FILETYPES 1004 +#define IDC_FILETYPEHELP 1005 +#define IDC_ROOTDIRHELP 1006 +#define IDC_HIDEOTHERFILES 1007 +#define IDC_OTHER_FILES_SHOW 1007 +#define IDC_OTHER_FILES_DL 1008 +#define IDC_WA_FILES_DL 1009 +#define IDC_PLAYLISTDIRHELP 1010 +#define IDC_WA_FILES_SHOW 1011 +#define IDC_PAGETITLE 1012 +#define IDC_PAGETITLEHELP 1013 +#define IDC_TEXTMODE 1014 +#define IDC_PORT_EDIT2 1015 +#define IDC_USERNAME 1015 +#define IDC_SECUREPASSWORD 1015 +#define IDC_PASSWORD 1016 +#define IDC_LOGFILEPATH 1018 +#define IDC_REFRESH 1019 +#define IDC_USERS 1020 +#define IDC_BUTTON1 1023 +#define IDC_UPDATE 1023 +#define IDC_SECUREPASSWORDHELP 1023 +#define IDC_AUTH_SHUTDOWN 1024 +#define IDC_AUTH_SERVER 1024 +#define IDC_AUTH_CONTROL 1025 +#define IDC_AUTH_PLAYLIST 1026 +#define IDC_AUTH_DOWNLOAD 1027 +#define IDC_BROWSE 1028 +#define IDC_AUTH_BROWSE 1028 +#define IDC_DELETE 1029 +#define IDC_ADD 1030 +#define IDC_AUTH_CLEAR 1031 +#define IDC_PASS_DEBUG 1032 +#define IDC_NOFRAMES 1035 +#define IDC_TWOFRAMES 1036 +#define IDC_THREEFRAMES 1037 +#define IDC_FRAMEIMG 1040 +#define IDC_MAINIMAGE 1042 +#define IDC_ABOUT_TITLE 1043 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 171 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1044 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Wawi Source/security.cpp b/Wawi Source/security.cpp new file mode 100644 index 0000000..27a0315 --- /dev/null +++ b/Wawi Source/security.cpp @@ -0,0 +1,312 @@ +/* --- SECURITY.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include <wincrypt.h> +#include <mmsystem.h> + +#include "types.h" +#include "main.h" +#include "html.h" +#include "plugin.h" + +extern char password[], username[]; +extern int securepassword; + +extern winampGeneralPurposePlugin plugin; + + + +// Base64 character array +// 0 1 2 3 4 5 6 +// 01234567890123456789012345678901234567890123456789012345678901234 +char bchars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+*"; +char achars[256]; + +// -------------------------------------------------------------------------------- +// Calculates MD5 of a string +bool MD5(char * input, char * output, int output_len) +{ + //MessageBox(NULL,input,"MD5 input",MB_TOPMOST | MB_OK); + HCRYPTPROV hProv = 0; + HCRYPTHASH Hash; + + if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + // Process any inserts in lpMsgBuf. + // ... + // Display the string. + MessageBox( NULL, (LPCTSTR)lpMsgBuf, "MD5 AcquireContext Error", MB_OK | MB_ICONINFORMATION ); + // Free the buffer. + LocalFree( lpMsgBuf ); + + return false; + } + + CryptCreateHash(hProv,CALG_MD5, 0, 0, &Hash); + + int input_len = lstrlen(input); + + BYTE md5raw[2048]; + int md5raw_len = 2048; + CryptHashData(Hash,(unsigned char*)input,input_len, 0); // md5 of "<time>:<password>" + CryptGetHashParam(Hash, HP_HASHVAL, md5raw,(DWORD*)&md5raw_len,0); + + wsprintf(output,""); // Make output a terminated string + + char temp[4]; + //wsprintf(temp,"%d",md5raw_len); + //MessageBox(NULL,temp,"gen_httpSrv md5raw_len",MB_OK); + + for (int i=0;i<md5raw_len;i++) + { + wsprintf(temp,"%2.2x", md5raw[i]); + lstrcat(output,temp); + } + + //MessageBox(NULL,output,"gen_httpSrv debug MD5", MB_OK); + + + + + CryptReleaseContext(hProv,0); + return true; +} + + + + +// -------------------------------------------------------------------------------- +// Sends a 401 for Basic authentication +int SendBasic401(connection * conn, char * realm) +{ + prints(conn,"HTTP/1.0 401 Unauthorized\nWWW-Authenticate: Basic realm=\""); + prints(conn,realm); + prints(conn,"\"\n"); + prints(conn,"Content-Type: text/html\n\n<html>\n<head>\n<title>Login Failed</title>\n"); + Style(conn); + CloseHeader(conn); + OpenPageBody(conn); + prints(conn,"<h1>Login Failed</h1>\n<p><b>Winamp Web Interface could not log you in.</b></p>\n<p><a href=\"/main\">Back to main page</a></p>"); + CloseBody(conn); + conn->http.responsecode = 401; + return ST_CLOSE; +} + +// -------------------------------------------------------------------------------- +// Finds a substring in another string. Probably should be in strings.cpp... +char * FindSubString(char * buffer,char * target) +{ + //MessageBox(NULL,buffer,"gen_httpSrv FindSubString",MB_OK); + int len = lstrlen(buffer) - lstrlen(target); + for (int i=0;i<=len;i++) + { + if (StartString(target,buffer+i)) + return (char*)(buffer+i); + } + return NULL; +} + + + + +// -------------------------------------------------------------------------------- +// Finds auth headers in a request +void FindBasicAuth(connection * conn, char * buffer) +{ + //int ptr; + //MessageBox(NULL,buffer,"gen_httpSrv FindBasicAuth: buffer",MB_OK); + char * chptr = FindSubString(buffer,"Authorization:"); // Look for auth + if (!chptr) + { // Not found + chptr = FindSubString(buffer,"Authorisation:"); // Misspellings? + if (!chptr) // Still no; fail + { + //MessageBox(NULL,"No Auth","gen_httpSrv debug FindBasicAuth",MB_OK); + conn->http.auth = CheckCredentials(conn,"anon",""); + return; + } + } + + // Authorisation section found + //MessageBox(NULL,chptr,"gen_httpSrv debug",MB_OK); + + char temp[100]; + + + char * cl_user; + char * cl_pass; + + chptr = GetAString(chptr,(char*)&temp); // chptr now points at Authorisation, so get it + chptr = GetAString(chptr,(char*)&temp); // get auth mode - 'basic' + chptr = GetAString(chptr,(char*)&temp); // get user/pass string + + char userpass[100]; + FromBase64((char*)&temp,(char*)&userpass); + + int i=0; + while(userpass[i] != ':') + { + if (userpass[i] == 0) + { + conn->http.auth = CheckCredentials(conn,"anon",""); + return; + } + i++; + } + userpass[i] = 0; + cl_pass = &userpass[i+1]; + cl_user = (char*)&userpass; + + + //wsprintf(temp,"User: %s\nPassword: %s",cl_user,cl_pass); + //MessageBox(NULL,temp,"user/password",MB_TOPMOST | MB_OK); + //MessageBox(NULL,temp,"gen_httpSrv debug base64 from client",MB_OK); + + conn->http.auth = CheckCredentials(conn, cl_user, cl_pass); + + +} +// -------------------------------------------------------------------------------- +// Converts a string to Base64 +void ToBase64(char * instr, char * outstr) +{ + //MessageBox(NULL,instr,"instr",MB_OK); + + int i=0; + int o=0; + int j = lstrlen(instr); + + bool done = false; + + while(instr[i] != 0 && done == false) + { + outstr[o] = bchars[(instr[i] & 0xFC) / 4]; + outstr[o+1] = bchars[((instr[i] & 0x03) * 16) + ((instr[i+1] & 0xF0) / 16)]; + if (instr[i+1] == 0) + { + outstr[o+2] = '='; + outstr[o+3] = '='; + done = true; + } + else + { + outstr[o+2] = bchars[((instr[i+1] & 0x0F) * 4) + ((instr[i+2] & 0xC0) /64)]; + if (instr[i+2] == 0) + { + outstr[o+3] = '='; + done = true; + } + else + outstr[o+3] = bchars[(instr[i+2] & 0x3F)]; + } + + o += 4; + i += 3; + } + + outstr[o] = 0; +} + +// -------------------------------------------------------------------------------- +// Converts a Base64 string to plaintext +void FromBase64(char * instr,char * outstr) +{ + int i=0; + int o=0; + int j=lstrlen(instr); + + for (int n=0;n<j;n++) // reduce ascii codes to numbers + { + if (instr[n] != '=') + instr[n] = achars[instr[n]]; + else + instr[n] = (char)255; + } + + while(instr[i] != 0) + { + outstr[o] = ((instr[i] & 0x3F) * 4) + ((instr[i+1] & 0x30) / 16); + + if (instr[i+2] == (char)255) + outstr[o+1] = 0; + else + { + outstr[o+1] = ((instr[i+1] & 0x0F) * 16) + ((instr[i+2] & 0x3C) / 4); + + if (instr[i+3] == (char)255) + outstr[o+2] = 0; + else + outstr[o+2] = ((instr[i+2] & 0x03) * 64) + (instr[i+3] & 0x3F); + } + + i += 4; + o += 3; + } + outstr[o] = 0; +} + +// -------------------------------------------------------------------------------- +// Checks credentials with those in ini file +int CheckCredentials(connection * conn, char * user, char * pass) +{ + + char ini_file[MAX_PATH], *p; + GetModuleFileName(plugin.hDllInstance,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"gen_httpsrv.ini"); + + if (StrComp(user,"anon")) + return GetUserAccess(ini_file,user); + + char password[40]; + + GetPrivateProfileString("Users",user,"",(char*)&password,40,ini_file); + + char md5pass[40]; + if (securepassword == 1) + MD5(pass,(char*)&md5pass,40); + else + ToBase64(pass,md5pass); + + //if (password[0] == 0) + // return AUTH_ANON; + + //char temp[150]; + //wsprintf(temp,"file: %s\nrecv: %s",password,md5pass); + //MessageBox(NULL,temp,"auth",MB_OK | MB_TOPMOST); + + if (StrComp(password,md5pass)) + { + wsprintf(conn->http.user,user); + return GetUserAccess(ini_file, user); + } + else + return AUTH_ANON; +} + +// -------------------------------------------------------------------------------- +// Gets access rights from the ini file +int GetUserAccess(char * ini_file,char * user) +{ + char useraccesskey[30]; + wsprintf(useraccesskey, "#%s_access", user); + return GetPrivateProfileInt("Users",useraccesskey,AUTH_ANON,ini_file); +} diff --git a/Wawi Source/server.ico b/Wawi Source/server.ico new file mode 100644 index 0000000..cded087 Binary files /dev/null and b/Wawi Source/server.ico differ diff --git a/Wawi Source/strings.cpp b/Wawi Source/strings.cpp new file mode 100644 index 0000000..310f823 --- /dev/null +++ b/Wawi Source/strings.cpp @@ -0,0 +1,265 @@ +/* --- STRINGS.CPP --- +/ +/ Written by Phil Himsworth, 2001-2002. +/ +/*/ + +#include <windows.h> +#include "wamessage.h" +#include "types.h" +#include "main.h" + +// This would be so much easier if Clib didn't have memory leaks within CreateThread... +// Oh well, here are the random string doodles + +// (And if I had found the Win32 string functions first...!) + + +// Returns a substring ending with the delimiter +char * GetDelimitedString(char * buffer, char delimiter, char * result, int result_len) +{ + int ptr = 0; + while(buffer[ptr] != delimiter && ptr < result_len) + { + result[ptr] = buffer[ptr]; + if (buffer[ptr] == 0) // Check for end of string + return NULL; + ptr++; + } + result[ptr] = 0; + + return buffer+ptr; +} + + +// -------------------------------------------------------------------------------- +// Gets a string not in quotes +bool GetUnquotedString(char * buffer, char * result, int result_len) +{ + int resptr = 0, ptr = 0; + while(buffer[ptr] != ' ' && buffer[ptr] != ',' && buffer[ptr] != 0 && ptr != result_len) // copy string + { + result[resptr] = buffer[ptr]; + ptr++; + resptr++; + } + result[resptr] = 0; + + return true; +} + +// -------------------------------------------------------------------------------- +// Gets a string within quotes +bool GetQuotedString(char * buffer, char * result, int result_len) +{ + int ptr = 0; + while(buffer[ptr] != '\"') // find first " + { + if (buffer[ptr] == 0) // end of string and no quote start found; fail + return false; + ptr++; + } + + // ptr points to first "; move on 1 to start of string + ptr++; + + int resptr = 0; + while(buffer[ptr] != '\"' && buffer[ptr] != 0 && ptr != result_len) // copy string until closing " + { // or end of buffer + result[resptr] = buffer[ptr]; + ptr++; + resptr++; + } + result[resptr] = 0; // make last char 0 + + return true; +} + + + +// -------------------------------------------------------------------------------- +// Checks if string2 begins with string1 +bool StartString(char* string1, char* string2) +{ + //char temp[2048]; + //wsprintf(temp,"1: %s\n2:%s",string1,string2); + //MessageBox(NULL,temp,"gen_httpSrv StartString",MB_OK); + int ptr = 0; + + while(ToLowerCase(string1[ptr]) == ToLowerCase(string2[ptr])) // Keep going until they're different + { + if (string1[ptr] == 0) // if string1 finishes, they're the same + return true; + ptr++; + } + + if (string1[ptr] == 0) // If they're different because string1 has ended, yes + return true; + else + return false; // If they're different and string1 has not ended, no +} + +// -------------------------------------------------------------------------------- +// Retrieves next token from buffer +char * GetAString(char* chptr, char* text) // Old GetAString - only accepts single words +{ + int bptr = 0; + int tptr = 0; + while (chptr[bptr] == ' ' || chptr[bptr] == '\n' || chptr[bptr] == '\r') // skip leading spaces and stuff + bptr++; + + while (chptr[bptr] != 0 && chptr[bptr] != ' ' && chptr[bptr] != '\n' && chptr[bptr] != '\r' && bptr < 255) // while current char is a letter + { + text[tptr] = chptr[bptr]; // add letter to text[] + bptr++; + tptr++; + } + text[tptr] = 0; + chptr = chptr + bptr; + return chptr; // return pointer to the end of this string +} + +// -------------------------------------------------------------------------------- +// Mangles the time into a displayable format +void PrintTime(connection * conn, int mins,int seconds) +{ + char tbuffer[20]; + if (seconds<10) // Avoids it printing eg. '4:2' when it should be '4:02' + wsprintf(tbuffer,"%d:0%d",mins,seconds); + else + wsprintf(tbuffer,"%d:%d",mins,seconds); + prints(conn,tbuffer); +} + + +void PrintTrackTime(connection * conn) +{ + int tracklen; + int trackpos = SendMessage(WAwnd(),WM_USER, 0, WAU_TRACKPOS) / 1000; + int mins = trackpos / 60; + int seconds = trackpos % 60; + prints(conn, " ("); + + PrintTime(conn,mins,seconds); + + tracklen = SendMessage(WAwnd(),WM_USER, 1, WAU_TRACKLENGTH); + mins = tracklen / 60; + seconds = tracklen % 60; + prints(conn, " / "); + PrintTime(conn,mins,seconds); + prints(conn, ")\n\r"); +} + +// -------------------------------------------------------------------------------- +// Convert a string to lower case +void ToLowerCase(char * string) +{ + int i=0; + while (string[i] != 0 && i < 255) + { + if (string[i] >= 'A' && string[i] <= 'Z') + string[i] += 32; + i++; + } +} + +// -------------------------------------------------------------------------------- +// Convert a char to lower case +char ToLowerCase(char c) +{ + if (c >= 'A' && c <= 'Z') + c += 32; + return c; +} + + +// -------------------------------------------------------------------------------- +// Blatantly better Strcmp using win32 lstrcmp +bool StrComp(char * string1, char * string2) +{ + if (lstrcmp(string1, string2) == 0) // Converts result from lstrcmp to a bool + return true; + else + return false; +} + +// -------------------------------------------------------------------------------- +// Converts '/' characters to '\'... it's Opera trying to be helpful, dammit! +void ReplaceSlashes(char * string) +{ + int ptr=0; + while (string[ptr]!=0) + { + if (string[ptr]=='/') + string[ptr] = '\\'; + ptr++; + } +} + +// -------------------------------------------------------------------------------- +// Retrieves a filename from a full path +char * GetFilename(char * path) +{ + char * filename; + + for (int i=0;path[i] != 0;i++) + if (path[i]=='\\') + filename = path+i; + + return filename+1; // ignore leading slash +} + +// -------------------------------------------------------------------------------- +// Non-clib version of atoi +int atoi2(const char *str ) +{ + int val = 0, mlt = 1; + char *p; + p = (char *) (str + lstrlen( str ) - 1); + for( ; p >= str; --p, mlt *= 10 ) { + val += (mlt * ((int)*p - '0')); + } + return val; +} + +// -------------------------------------------------------------------------------- +// Checks if string contains a character +bool contains(char * echars,char ch) +{ + int x=0; + while(echars[x] != 0) + { + if (echars[x] == ch) + return true; + x++; + } + return false; +} + +// -------------------------------------------------------------------------------- +// Finds substring +char * strstr2(char *string, char *substring) +{ + char *a, *b; + + b = substring; + if (*b == 0) { + return string; + } + for ( ; *string != 0; string += 1) { + if (*string != *b) { + continue; + } + a = string; + while (1) { + if (*b == 0) { + return string; + } + if (*a++ != *b++) { + break; + } + } + b = substring; + } + return NULL; +} diff --git a/Wawi Source/types.h b/Wawi Source/types.h new file mode 100644 index 0000000..0308673 --- /dev/null +++ b/Wawi Source/types.h @@ -0,0 +1,108 @@ +// Global types and definitions + +// list to store user information from ini file +struct user +{ + char name[20]; + user * next; +}; + + +// return values from DeletePlaylistEntry +#define DPE_OK 1 +#define DPE_NOREAD 2 +#define DPE_NOWRITE 3 + + +// playlist for deleting items +struct playlistitem +{ + int number; + char time[10]; + char name[MAX_PATH]; + char path[MAX_PATH]; + playlistitem * next; +}; + +struct fileinfo +{ + char path[MAX_PATH]; + char name[MAX_PATH]; + bool playlist; + bool urlsct; + fileinfo *next; + fileinfo *prev; +}; + +struct filesearch +{ + fileinfo *firstfile; + fileinfo *firstdir; + int dnodes; + int fnodes; +}; + +// Request IDs +#define RID_GET 101 +#define RID_HEAD 102 + +// Image types +#define IMG_GIF 301 +#define IMG_ICO 302 + +// Access level IDs. These get OR-ed together to come up with a single value +#define AUTH_ANON 0 +#define AUTH_BROWSE 1 +#define AUTH_DOWNLOAD 2 +#define AUTH_PLAYLIST 4 +#define AUTH_CLEAR 8 +#define AUTH_CONTROL 16 +#define AUTH_SERVER 32 + +// Target frames +#define T_NONE 601 +#define T_MAIN 602 +#define T_BOTTOM 603 +#define T_TOP 604 + +// holds information about 1 name/value pair ...?<name>=<value>&... +struct argument +{ + char name[30]; + char value[128]; +}; + +// Main connection information structure +struct http_request +{ + char user[20]; // logged on user (or 'anon') + char request[10]; // 'GET', 'HEAD' etc + int reqID; // integer representing the above + char file[512]; // full requested url + char page[MAX_PATH]; // just the page, without arguments + char http_version[10]; // HTTP Version; eg. "HTTP/1.0" + int responsecode; // HTTP response; 200, 400, 401 etc + char realm[50]; // authentication realm + int auth; // access level + argument pairs[50]; // name/value pairs for arguments + int num_args; // number of arguments +}; + + +#define BUF_LEN 10000 + +// Return states +#define ST_NONE 200 +#define ST_CLOSE 201 +#define ST_CLOSEBODY 202 + +struct connection +{ + char output[BUF_LEN]; + http_request http; + SOCKET socket; + sockaddr_in remote_host; + int state; + bool log; + +}; \ No newline at end of file diff --git a/Wawi Source/users.ico b/Wawi Source/users.ico new file mode 100644 index 0000000..202165d Binary files /dev/null and b/Wawi Source/users.ico differ diff --git a/Wawi Source/wafile.gif b/Wawi Source/wafile.gif new file mode 100644 index 0000000..3f8b324 Binary files /dev/null and b/Wawi Source/wafile.gif differ diff --git a/Wawi Source/wamessage.h b/Wawi Source/wamessage.h new file mode 100644 index 0000000..9e4c444 --- /dev/null +++ b/Wawi Source/wamessage.h @@ -0,0 +1,45 @@ +// defines for winamp API messages. + +// WM_COMMAND winamp play control messages + +#define WAC_PLAY 40045 +#define WAC_PAUSE 40046 +#define WAC_STOP 40047 +#define WAC_NEXT 40048 +#define WAC_PREV 40044 +#define WAC_EXIT 40001 +#define WAC_STOPFADE 40147 +#define WAC_STOPNEXT 40157 +// WM_COMMAND winamp misc control messages + +#define WAC_HIDEMAIN 40258 +#define WAC_HIDEPLAY 40040 +#define WAC_HIDEEQ 40036 +#define WAC_RANDOMT 40023 +#define WAC_REPEATT 40022 +#define WAC_QUIT 40001 + +// WM_USER winamp messages + +#define WAU_CLEARPLIST 101 +#define WAU_STATUS 104 +#define WAU_SETPLPOS 121 +#define WAU_GETPLPOS 125 +#define WAU_TRACKLENGTH 105 // data = 1 +#define WAU_TRACKPOS 105 // data = 0 +#define WAU_GETRANDOM 250 +#define WAU_GETREPEAT 251 +#define WAU_SETRANDOM 252 +#define WAU_SETREPEAT 253 +#define WAU_GETTITLE 212 +#define WAU_PLCOUNT 124 +#define WAU_PLSAVE 120 +#define WAU_UPDTITLE 243 + +// COPYDATASTRUCT winamp messages + +#define IPC_PLAYFILE 100 + +// Playlist window WM_COMMAND messages + +#define PLC_SORTTITLE 40209 diff --git a/Wawi Source/wawi_large.gif b/Wawi Source/wawi_large.gif new file mode 100644 index 0000000..1fde292 Binary files /dev/null and b/Wawi Source/wawi_large.gif differ diff --git a/Wawi Source/wawi_small.gif b/Wawi Source/wawi_small.gif new file mode 100644 index 0000000..005d599 Binary files /dev/null and b/Wawi Source/wawi_small.gif differ diff --git a/Wawi Source/webpage.ico b/Wawi Source/webpage.ico new file mode 100644 index 0000000..d76dcf0 Binary files /dev/null and b/Wawi Source/webpage.ico differ diff --git a/Wawi Source/winamp.m3u b/Wawi Source/winamp.m3u new file mode 100644 index 0000000..fcdf93c --- /dev/null +++ b/Wawi Source/winamp.m3u @@ -0,0 +1,261 @@ +#EXTM3U +#EXTINF:239,Beautiful South - 36D +D:\Music\Albums\Beautiful South- Carry On Up The Charts\36D.mp3 +#EXTINF:177,Beautiful South - A Little Time +D:\Music\Albums\Beautiful South- Carry On Up The Charts\A Little Time.mp3 +#EXTINF:272,Beautiful South - Bell Bottomed Tear +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Bell Bottomed Tear.mp3 +#EXTINF:213,Beautiful South - Dream A Little Dream Of Me +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Dream A Little Dream Of Me.mp3 +#EXTINF:155,Beautiful South - Everybody's Talkin' +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Everybody's Talkin'.mp3 +#EXTINF:226,Beautiful South - Good As Gold (Stupid As Mud) +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Good As Gold (Stupid As Mud).mp3 +#EXTINF:243,Beautiful South - I'll Sail This Ship Alone +D:\Music\Albums\Beautiful South- Carry On Up The Charts\I'll Sail This Ship Alone.mp3 +#EXTINF:256,Beautiful South - Let Love Speak Up Itself +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Let Love Speak Up Itself.mp3 +#EXTINF:170,Beautiful South - My Book +D:\Music\Albums\Beautiful South- Carry On Up The Charts\My Book.mp3 +#EXTINF:212,Beautiful South - Old Red Eyes Is Back +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Old Red Eyes Is Back.mp3 +#EXTINF:212,Beautiful South - One Last Love Song +D:\Music\Albums\Beautiful South- Carry On Up The Charts\One Last Love Song.mp3 +#EXTINF:225,Beautiful South - Prettiest Eyes +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Prettiest Eyes.mp3 +#EXTINF:242,Beautiful South - Song For Whoever +D:\Music\Albums\Beautiful South- Carry On Up The Charts\Song For Whoever.mp3 +#EXTINF:214,Beautiful South - We Are Each Other +D:\Music\Albums\Beautiful South- Carry On Up The Charts\We Are Each Other.mp3 +#EXTINF:171,Beautiful South - You Keep It All In +D:\Music\Albums\Beautiful South- Carry On Up The Charts\You Keep It All In.mp3 +#EXTINF:233,Dido - All You Want +D:\Music\Albums\Dido - No Angel\All You Want.mp3 +#EXTINF:272,Dido - Don't Think Of Me +D:\Music\Albums\Dido - No Angel\Don't Think Of Me.mp3 +#EXTINF:255,Dido - Here With Me +D:\Music\Albums\Dido - No Angel\Here With Me.mp3 +#EXTINF:278,Dido - Honestly OK +D:\Music\Albums\Dido - No Angel\Honestly OK.mp3 +#EXTINF:237,Dido - Hunter +D:\Music\Albums\Dido - No Angel\Hunter.mp3 +#EXTINF:235,Dido - I'm No Angel +D:\Music\Albums\Dido - No Angel\I'm No Angel.mp3 +#EXTINF:234,Dido - Isobel +D:\Music\Albums\Dido - No Angel\Isobel.mp3 +#EXTINF:189,Dido - My Life +D:\Music\Albums\Dido - No Angel\My Life.mp3 +#EXTINF:267,Dido - My Love's Gone +D:\Music\Albums\Dido - No Angel\My Love's Gone.mp3 +#EXTINF:292,Dido - Slide +D:\Music\Albums\Dido - No Angel\Slide.mp3 +#EXTINF:402,Dido - Take My Hand +D:\Music\Albums\Dido - No Angel\Take My Hand.mp3 +#EXTINF:218,Dido - Thank You +D:\Music\Albums\Dido - No Angel\Thank You.mp3 +#EXTINF:239,Elton John - Can You Feel The Love Tonight +D:\Music\Albums\Elton John\Can You Feel The Love Tonight.mp3 +#EXTINF:288,Elton John - Circle Of Life +D:\Music\Albums\Elton John\Circle Of Life.mp3 +#EXTINF:348,Elton John & George Michael - Don't Let The Sun Go Down On Me +D:\Music\Albums\Elton John\Don't Let The Sun Go Down On Me.mp3 +#EXTINF:281,Elton John - I Guess That's Why They Call This The Blues +D:\Music\Albums\Elton John\I Guess That's Why They Call It The Blues.mp3 +#EXTINF:308,Elton John - Sacrifice +D:\Music\Albums\Elton John\Sacrifice.mp3 +#EXTINF:227,Elton John - Sorry Seems To Be The Hardest Word +D:\Music\Albums\Elton John\Sorry Seems To Be The Hardest Word.mp3 +#EXTINF:351,Elton John - The One +D:\Music\Albums\Elton John\The One.mp3 +#EXTINF:258,Yesterday Went Too Soon +D:\Music\Albums\Feeder\Yesterday Went Too Soon.mp3 +#EXTINF:191,Buck Rogers +D:\Music\Albums\Feeder - Echo Park\Buck Rogers.mp3 +#EXTINF:222,Bug +D:\Music\Albums\Feeder - Echo Park\Bug.mp3 +#EXTINF:199,Choke +D:\Music\Albums\Feeder - Echo Park\Choke.mp3 +#EXTINF:259,Oxygen +D:\Music\Albums\Feeder - Echo Park\Oxygen.mp3 +#EXTINF:228,Piece By Piece +D:\Music\Albums\Feeder - Echo Park\Piece By Piece.mp3 +#EXTINF:325,Satellite News +D:\Music\Albums\Feeder - Echo Park\Satellite News.mp3 +#EXTINF:218,Seven Days In The Sun +D:\Music\Albums\Feeder - Echo Park\Seven Days In The Sun.mp3 +#EXTINF:191,Standing On The Edge +D:\Music\Albums\Feeder - Echo Park\Standing On The Edge.mp3 +#EXTINF:175,Tell All Your Friends +D:\Music\Albums\Feeder - Echo Park\Tell All Your Friends.mp3 +#EXTINF:270,Turn +D:\Music\Albums\Feeder - Echo Park\Turn.mp3 +#EXTINF:213,Under The Weather +D:\Music\Albums\Feeder - Echo Park\Under The Weather.mp3 +#EXTINF:230,We Can't Rewind +D:\Music\Albums\Feeder - Echo Park\We Can't Rewind.mp3 +#EXTINF:114,Feeder - 20th Century Trip +D:\Music\Albums\Feeder - Polythene\20th Century Trip.mp3 +#EXTINF:206,Feeder - Cement +D:\Music\Albums\Feeder - Polythene\Cement.mp3 +#EXTINF:206,Feeder - Change +D:\Music\Albums\Feeder - Polythene\Change.mp3 +#EXTINF:252,Feeder - Crash +D:\Music\Albums\Feeder - Polythene\Crash.mp3 +#EXTINF:321,Feeder - Descend +D:\Music\Albums\Feeder - Polythene\Descend.mp3 +#EXTINF:284,Feeder - Forgive +D:\Music\Albums\Feeder - Polythene\Forgive.mp3 +#EXTINF:264,Feeder - High +D:\Music\Albums\Feeder - Polythene\High.mp3 +#EXTINF:263,Feeder - My Perfect Day +D:\Music\Albums\Feeder - Polythene\My Perfect Day.mp3 +#EXTINF:207,Feeder - Polythene Girl +D:\Music\Albums\Feeder - Polythene\Polythene Girl.mp3 +#EXTINF:274,Feeder - Radiation +D:\Music\Albums\Feeder - Polythene\Radiation.mp3 +#EXTINF:206,Feeder - Stereo World +D:\Music\Albums\Feeder - Polythene\Stereo World.mp3 +#EXTINF:229,Feeder - Suffocate +D:\Music\Albums\Feeder - Polythene\Suffocate.mp3 +#EXTINF:229,Feeder - Tangerine +D:\Music\Albums\Feeder - Polythene\Tangerine.mp3 +#EXTINF:254,Ain't It The Life +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Ain't It The Life.mp3 +#EXTINF:348,Aurora +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Aurora.mp3 +#EXTINF:200,Breakout +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Breakout.mp3 +#EXTINF:227,Generator +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Generator.mp3 +#EXTINF:221,Gimme Stitches +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Gimme Stitches.mp3 +#EXTINF:276,Headwires +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Headwires.mp3 +#EXTINF:234,Learn To Fly +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Learn To Fly.mp3 +#EXTINF:232,Live-In Skin +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Live-In Skin.mp3 +#EXTINF:242,MIA!!s +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\MIA!!s.mp3 +#EXTINF:275,Next Year +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Next Year.mp3 +#EXTINF:255,Stacked Actors +D:\Music\Albums\Foo Fighters - There Is Nothing Left To Lose\Stacked Actors.mp3 +#EXTINF:251,Bliss +D:\Music\Albums\Muse - Origin Of Symmetry\Bliss.mp3 +#EXTINF:438,Citizen Erased +D:\Music\Albums\Muse - Origin Of Symmetry\Citizen Erased.mp3 +#EXTINF:287,Darkshines +D:\Music\Albums\Muse - Origin Of Symmetry\Darkshines.mp3 +#EXTINF:199,Feeling Good +D:\Music\Albums\Muse - Origin Of Symmetry\Feeling Good.mp3 +#EXTINF:200,Hyper Music +D:\Music\Albums\Muse - Origin Of Symmetry\Hyper Music.mp3 +#EXTINF:277,Megalomania +D:\Music\Albums\Muse - Origin Of Symmetry\Megalomania.mp3 +#EXTINF:217,Micro Cuts +D:\Music\Albums\Muse - Origin Of Symmetry\Micro Cuts.mp3 +#EXTINF:362,New Born +D:\Music\Albums\Muse - Origin Of Symmetry\New Born.mp3 +#EXTINF:219,Muse - Plug In Baby +D:\Music\Albums\Muse - Origin Of Symmetry\Plug In Baby.mp3 +#EXTINF:259,Screenager +D:\Music\Albums\Muse - Origin Of Symmetry\Screenager.mp3 +#EXTINF:379,Space Dementia +D:\Music\Albums\Muse - Origin Of Symmetry\Space Dementia.mp3 +#EXTINF:196,Simon & Garfunkel - Baby Driver +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Baby Driver.mp3 +#EXTINF:290,Simon & Garfunkel - Bridge Over Troubled Water +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Bridge Over Troubled Water.mp3 +#EXTINF:175,Simon & Garfunkel - Bye Bye Love +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Bye Bye Love.mp3 +#EXTINF:174,Simon & Garfunkel - Cecilia +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Cecilia.mp3 +#EXTINF:186,Simon & Garfunkel - El Condor Pasa +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\El Condor Pasa.mp3 +#EXTINF:153,Simon & Garfunkel - Keep The Customer Satisfied +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Keep The Customer Satisfied.mp3 +#EXTINF:221,Simon & Garfunkel - So Long, Frank Lloyd Wright +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\So Long, Frank Lloyd Wright.mp3 +#EXTINF:108,Simon & Garfunkel - Song For The Asking +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Song For The Asking.mp3 +#EXTINF:308,Simon & Garfunkel - The Boxer +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\The Boxer.mp3 +#EXTINF:236,Simon & Garfunkel - The Only Living Boy In New York +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\The Only Living Boy In New York.mp3 +#EXTINF:164,Simon & Garfunkel - Why Don't You Write Me +D:\Music\Albums\Simon & Garfunkel - Bridge Over Troubled Water\Why Don't You Write Me.mp3 +#EXTINF:225,Stereophonics - A Minute Longer +D:\Music\Albums\Stereophonics- Performance And Cocktails\A Minute Longer.mp3 +#EXTINF:175,Stereophonics - Half Of The Lies You Tell Ain't True +D:\Music\Albums\Stereophonics- Performance And Cocktails\Half Of The Lies You Tell Ain't True.mp3 +#EXTINF:279,Stereophonics - Hurry Up And Wait +D:\Music\Albums\Stereophonics- Performance And Cocktails\Hurry Up And Wait.mp3 +#EXTINF:267,Stereophonics - I Stopped To Fill My Car Up +D:\Music\Albums\Stereophonics- Performance And Cocktails\I Stopped To Fill My Car Up.mp3 +#EXTINF:229,Stereophonics - I Wouldn't Believe You Radio +D:\Music\Albums\Stereophonics- Performance And Cocktails\I Wouldn't Believe You Radio.mp3 +#EXTINF:241,Stereophonics - Is Yesterday, Tomorrow, Today? +D:\Music\Albums\Stereophonics- Performance And Cocktails\Is Yesterday, Tomorrow, Today.mp3 +#EXTINF:252,Stereophonics - Just Looking +D:\Music\Albums\Stereophonics- Performance And Cocktails\Just Looking.mp3 +#EXTINF:213,Stereophonics - Pick A Part That's New +D:\Music\Albums\Stereophonics- Performance And Cocktails\Pick A Part That's New.mp3 +#EXTINF:270,Stereophonics - Plastic California +D:\Music\Albums\Stereophonics- Performance And Cocktails\Plastic California.mp3 +#EXTINF:237,Stereophonics - Roll Up And Shine +D:\Music\Albums\Stereophonics- Performance And Cocktails\Roll Up And Shine.mp3 +#EXTINF:235,Stereophonics - She Takes Her Clothes Off +D:\Music\Albums\Stereophonics- Performance And Cocktails\She Takes Her Clothes Off.mp3 +#EXTINF:244,Stereophonics - T-Shirt Sun Tan +D:\Music\Albums\Stereophonics- Performance And Cocktails\T-Shirt Sun Tan.mp3 +#EXTINF:174,Stereophonics - The Bartender And The Thief +D:\Music\Albums\Stereophonics- Performance And Cocktails\The Bartender And The Thief.mp3 +#EXTINF:124,The Beatles - Eleanor Rigby +D:\Music\Albums\The Beatles\Eleanor Rigby.mp3 +#EXTINF:185,The Beatles - Here Comes the Sun +D:\Music\Albums\The Beatles\Here Comes the Sun.mp3 +#EXTINF:426,The Beatles - Hey Jude +D:\Music\Albums\The Beatles\Hey Jude.mp3 +#EXTINF:104,The Beatles - I Will +D:\Music\Albums\The Beatles\I Will.mp3 +#EXTINF:229,The Beatles - Let It Be +D:\Music\Albums\The Beatles\Let It Be.mp3 +#EXTINF:213,The Beatles - She's Leaving Home +D:\Music\Albums\The Beatles\She's Leaving Home.mp3 +#EXTINF:216,The Beatles - The Long And Winding Road +D:\Music\Albums\The Beatles\The Long And Winding Road.mp3 +#EXTINF:125,The Beatles - Yesterday +D:\Music\Albums\The Beatles\Yesterday.mp3 +#EXTINF:181,The Levellers - Belaruse +D:\Music\Albums\The Levellers - One Way Of Life\Belaruse.mp3 +#EXTINF:196,The Levellers - Bozos +D:\Music\Albums\The Levellers - One Way Of Life\Bozos.mp3 +#EXTINF:284,The Levellers - Carry Me +D:\Music\Albums\The Levellers - One Way Of Life\Carry Me.mp3 +#EXTINF:245,The Levellers - Celebrate +D:\Music\Albums\The Levellers - One Way Of Life\Celebrate.mp3 +#EXTINF:215,The Levellers - Dog Train +D:\Music\Albums\The Levellers - One Way Of Life\Dog Train.mp3 +#EXTINF:196,The Levellers - Fantasy +D:\Music\Albums\The Levellers - One Way Of Life\Fantasy.mp3 +#EXTINF:209,The Levellers - Far From Home +D:\Music\Albums\The Levellers - One Way Of Life\Far From Home.mp3 +#EXTINF:187,The Levellers - Fifteen Years +D:\Music\Albums\The Levellers - One Way Of Life\Fifteen Years.mp3 +#EXTINF:265,The Levellers - Hope Street +D:\Music\Albums\The Levellers - One Way Of Life\Hope Street.mp3 +#EXTINF:231,The Levellers - Julie +D:\Music\Albums\The Levellers - One Way Of Life\Julie.mp3 +#EXTINF:168,The Levellers - Just The One +D:\Music\Albums\The Levellers - One Way Of Life\Just The One.mp3 +#EXTINF:204,The Levellers - One Way +D:\Music\Albums\The Levellers - One Way Of Life\One Way.mp3 +#EXTINF:242,The Levellers - Shadow On The Sun +D:\Music\Albums\The Levellers - One Way Of Life\Shadow On The Sun.mp3 +#EXTINF:240,The Levellers - This Garden +D:\Music\Albums\The Levellers - One Way Of Life\This Garden.mp3 +#EXTINF:331,The Levellers - Too Real (12") +D:\Music\Albums\The Levellers - One Way Of Life\Too Real.mp3 +#EXTINF:241,The Levellers - What A Beautiful Day +D:\Music\Albums\The Levellers - One Way Of Life\What A Beautiful Day.mp3 diff --git a/Wawi_7-5-13.exe b/Wawi_7-5-13.exe new file mode 100644 index 0000000..91939a7 Binary files /dev/null and b/Wawi_7-5-13.exe differ diff --git a/gen_httpSrv_systray/Images/SECUR08.ICO b/gen_httpSrv_systray/Images/SECUR08.ICO new file mode 100644 index 0000000..02cecfa Binary files /dev/null and b/gen_httpSrv_systray/Images/SECUR08.ICO differ diff --git a/gen_httpSrv_systray/Images/Title.bmp b/gen_httpSrv_systray/Images/Title.bmp new file mode 100644 index 0000000..8dcdf9b Binary files /dev/null and b/gen_httpSrv_systray/Images/Title.bmp differ diff --git a/gen_httpSrv_systray/Images/auth2.ico b/gen_httpSrv_systray/Images/auth2.ico new file mode 100644 index 0000000..d35debc Binary files /dev/null and b/gen_httpSrv_systray/Images/auth2.ico differ diff --git a/gen_httpSrv_systray/Images/next.bmp b/gen_httpSrv_systray/Images/next.bmp new file mode 100644 index 0000000..40cf9ea Binary files /dev/null and b/gen_httpSrv_systray/Images/next.bmp differ diff --git a/gen_httpSrv_systray/Images/next.ico b/gen_httpSrv_systray/Images/next.ico new file mode 100644 index 0000000..0325845 Binary files /dev/null and b/gen_httpSrv_systray/Images/next.ico differ diff --git a/gen_httpSrv_systray/Images/pause.ICO b/gen_httpSrv_systray/Images/pause.ICO new file mode 100644 index 0000000..53069b6 Binary files /dev/null and b/gen_httpSrv_systray/Images/pause.ICO differ diff --git a/gen_httpSrv_systray/Images/pause.bmp b/gen_httpSrv_systray/Images/pause.bmp new file mode 100644 index 0000000..5cc1b85 Binary files /dev/null and b/gen_httpSrv_systray/Images/pause.bmp differ diff --git a/gen_httpSrv_systray/Images/play.bmp b/gen_httpSrv_systray/Images/play.bmp new file mode 100644 index 0000000..a1d48df Binary files /dev/null and b/gen_httpSrv_systray/Images/play.bmp differ diff --git a/gen_httpSrv_systray/Images/play.ico b/gen_httpSrv_systray/Images/play.ico new file mode 100644 index 0000000..53069b6 Binary files /dev/null and b/gen_httpSrv_systray/Images/play.ico differ diff --git a/gen_httpSrv_systray/Images/prev.bmp b/gen_httpSrv_systray/Images/prev.bmp new file mode 100644 index 0000000..0c3bb47 Binary files /dev/null and b/gen_httpSrv_systray/Images/prev.bmp differ diff --git a/gen_httpSrv_systray/Images/prev.ico b/gen_httpSrv_systray/Images/prev.ico new file mode 100644 index 0000000..246278f Binary files /dev/null and b/gen_httpSrv_systray/Images/prev.ico differ diff --git a/gen_httpSrv_systray/Images/server.ico b/gen_httpSrv_systray/Images/server.ico new file mode 100644 index 0000000..cded087 Binary files /dev/null and b/gen_httpSrv_systray/Images/server.ico differ diff --git a/gen_httpSrv_systray/Images/stop.bmp b/gen_httpSrv_systray/Images/stop.bmp new file mode 100644 index 0000000..350aa3a Binary files /dev/null and b/gen_httpSrv_systray/Images/stop.bmp differ diff --git a/gen_httpSrv_systray/Images/stop.ico b/gen_httpSrv_systray/Images/stop.ico new file mode 100644 index 0000000..1824785 Binary files /dev/null and b/gen_httpSrv_systray/Images/stop.ico differ diff --git a/gen_httpSrv_systray/Images/winamp.ico b/gen_httpSrv_systray/Images/winamp.ico new file mode 100644 index 0000000..3f19ac6 Binary files /dev/null and b/gen_httpSrv_systray/Images/winamp.ico differ diff --git a/gen_httpSrv_systray/WawiTray Readme.txt b/gen_httpSrv_systray/WawiTray Readme.txt new file mode 100644 index 0000000..68607a1 --- /dev/null +++ b/gen_httpSrv_systray/WawiTray Readme.txt @@ -0,0 +1,64 @@ +A Really Quick Readme For The WawiTray Thingy +------------------------------------------------------- + +(Because I'm hungry and I want to go make dinner!) + + + +Based on a suggestion from Bill Kearney, it's a really teeny HTTP client which will send the right commands to the Winamp HTTP Server plugin to make it do stuff. This way you can control your winamp from another computer without using the big browser window if all you want it to do is control playback. + +Stick the right host (in IPv4 dotted format only, for example your local machine is always 127.0.0.1) and port number in (so it matches the value in the HTTP Server config window, 80 by default); stick a username and password in if required and click away. It'll either make winamp do stuff, or (hopefully) tell you why it can't. + +This is something I've only worked on for an hour or two, and as such probably has a few teething problems. If you do find anything, please drop me a mail (contact@flippet.net) to tell me what, and I'll see what I can do. Or feel free to send suggestions, jokes, cash et cetera... + + + + +Disclaimer +---------- + +While I've gone to every effort to make sure this doesn't cause harmful effects - I don't want to fry my own computer! - I cannot say for sure that it will not fry yours. I will not be responsible for any damage or loss of anything even slightly relating to this program. You use it ENTIRELY AT YOUR OWN RISK. Don't run to me if things break. I'll fix bits of the program if you spot bugs if I want to, but I'm under no obligation to do so at all. And don't you forget it. + +Besides that, I hope it's useful. Have fun! + + + + +Version History +--------------- + +2.1 +* Made it work with recent versions of Wawi +* Added a prettier config window +* A few little tweaks here and there... + +1.5 +* Tooltip of systray icon tells the song title. Set how often it updates in the Config window. + +1.4 +* Fancy-pants little icons for the play options in the menu + +1.3 +* The default action when left clicking on the icon can now be changed + +1.2 +* Added shortcuts to the Browse and Playlist pages + +1.1 +* Added a volume slider +* Added better error messages if it gets HTTP responses that it shouldn't + +1.0 +* Initial release + + + +Me +-- + +Phil Himsworth, UK + +web: http://www.flippet.org +email: contact@flippet.net + +September, 2002 \ No newline at end of file diff --git a/gen_httpSrv_systray/client.ini b/gen_httpSrv_systray/client.ini new file mode 100644 index 0000000..9d040ea --- /dev/null +++ b/gen_httpSrv_systray/client.ini @@ -0,0 +1,15 @@ +[Wawi Tray] +port=800 +default=105 +updatedelay=10 +auth=1 +host=10.2.169.200 +username=bob +password=password +[Winamp HTTP Server Client Applet] +port=800 +default=105 +updatedelay=10 +host=127.0.0.1 +username=anon +password= diff --git a/gen_httpSrv_systray/config.cpp b/gen_httpSrv_systray/config.cpp new file mode 100644 index 0000000..ab05ec3 --- /dev/null +++ b/gen_httpSrv_systray/config.cpp @@ -0,0 +1,453 @@ +#include <windows.h> +#include <prsht.h> +#include <mmsystem.h> +#include <commctrl.h> +#include "resource.h" +#include "main.h" + +extern HINSTANCE inst; +extern HWND hwnd; + +extern char host[255], username[20], password[20]; +extern int port, default_action, update_delay; +extern UINT timer_id; +extern bool use_auth; + +extern char szAppName[], AboutText[]; + +extern HWND ConfigWnd, VolumeWnd; + + +// -------------------------------------------------------------------------------- +// Entry point for new Config window, using Property Sheets instead of a single dialog. +void NewConfig() +{ + PROPSHEETPAGE psp[4]; + PROPSHEETHEADER psh; + + psp[0].dwSize = sizeof(PROPSHEETPAGE); + psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[0].hInstance = inst; + psp[0].pszTemplate = MAKEINTRESOURCE(IDD_ABOUT); + psp[0].pszIcon = MAKEINTRESOURCE(IDI_WINAMP); + psp[0].pfnDlgProc = ConfigAboutWndProc; + psp[0].pszTitle = "About"; + psp[0].lParam = 0; + psp[0].pfnCallback = NULL; + + psp[1].dwSize = sizeof(PROPSHEETPAGE); + psp[1].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[1].hInstance = inst; + psp[1].pszTemplate = MAKEINTRESOURCE(IDD_SERVER); + psp[1].pszIcon = MAKEINTRESOURCE(IDI_SERVER); + psp[1].pfnDlgProc = ConfigServerWndProc; + psp[1].pszTitle = "Server"; + psp[1].lParam = 0; + psp[1].pfnCallback = NULL; + + psp[2].dwSize = sizeof(PROPSHEETPAGE); + psp[2].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[2].hInstance = inst; + psp[2].pszTemplate = MAKEINTRESOURCE(IDD_SYSTRAY); + psp[2].pszIcon = MAKEINTRESOURCE(GetIconID()); + psp[2].pfnDlgProc = ConfigSystrayWndProc; + psp[2].pszTitle = "Tray Icon"; + psp[2].lParam = 0; + psp[2].pfnCallback = NULL; + + psp[3].dwSize = sizeof(PROPSHEETPAGE); + psp[3].dwFlags = PSP_USEICONID | PSP_USETITLE; + psp[3].hInstance = inst; + psp[3].pszTemplate = MAKEINTRESOURCE(IDD_AUTH); + psp[3].pszIcon = MAKEINTRESOURCE(IDI_AUTH2); + psp[3].pfnDlgProc = ConfigAuthWndProc; + psp[3].pszTitle = "Authentication"; + psp[3].lParam = 0; + psp[3].pfnCallback = NULL; + + + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE; + psh.hwndParent = hwnd; + psh.hInstance = inst; + psh.pszIcon = NULL; + psh.pszCaption = "WawiTray Config"; + psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); + psh.nStartPage = 0; + psh.ppsp = (LPCPROPSHEETPAGE) &psp; + psh.pfnCallback = NULL; + + PropertySheet(&psh); + config_write(); + ConfigWnd = NULL; + return; +} + + +// -------------------------------------------------------------------------------- +// Server options window proc +BOOL CALLBACK ConfigServerWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + char TempString[10]; + int port_temp; + switch(uMsg) + { + case WM_INITDIALOG: + wsprintf(TempString,"%d",port); + SetDlgItemText(hwndDlg,IDC_HOST,host); + SetDlgItemText(hwndDlg,IDC_PORT,TempString); + break; + + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: port_temp = GetDlgItemInt(hwndDlg,IDC_PORT,NULL,false); + if (port_temp > 0 && port_temp < 65536) + { + port = port_temp; + GetDlgItemText(hwndDlg,IDC_HOST,host,255); + } + else + { + MessageBox(hwndDlg,"Port must be from 1 to 65535!","Winamp Web Interface",MB_OK); + SetDlgItemInt(hwndDlg,IDC_PORT,port,false); + SetWindowLong(hwndDlg,DWL_MSGRESULT,true); + return true; + } + break; + } + break; + } + return false; +} + +// -------------------------------------------------------------------------------- +// Systray options window proc +BOOL CALLBACK ConfigSystrayWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + char temp[5]; + switch(uMsg) + { + case WM_INITDIALOG: + int def_button; + switch(default_action) + { + case WA_PREV: + def_button = IDC_DEF_PREV; + break; + case WA_PLAY: + def_button = IDC_DEF_PLAY; + break; + case WA_PAUSE: + def_button = IDC_DEF_PAUSE; + break; + case WA_STOP: + def_button = IDC_DEF_STOP; + break; + case WA_NEXT: + def_button = IDC_DEF_NEXT; + break; + } + + CheckRadioButton(hwndDlg,IDC_DEF_PREV,IDC_DEF_NEXT,def_button); + + wsprintf(temp,"%d",update_delay); + SetDlgItemText(hwndDlg,IDC_UPDATEDELAY,temp); + break; + + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: update_delay = GetDlgItemInt(hwndDlg,IDC_UPDATEDELAY,NULL,false); + KillTimer(hwnd,timer_id); + timer_id = SetTimer(hwnd,TIMER_ID,update_delay*1000,NULL); + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED) + default_action = WA_PREV; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED) + default_action = WA_PREV; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PLAY) == BST_CHECKED) + default_action = WA_PLAY; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PAUSE) == BST_CHECKED) + default_action = WA_PAUSE; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_STOP) == BST_CHECKED) + default_action = WA_STOP; + else + default_action = WA_NEXT; + + systray_modify(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(GetIconID())),szAppName); + + break; + } + break; + } + return false; +} + + +// -------------------------------------------------------------------------------- +// Authentication options window proc +BOOL CALLBACK ConfigAuthWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int use_auth_int; + switch(uMsg) + { + case WM_INITDIALOG: + SetDlgItemText(hwndDlg,IDC_USERNAME,username); + SetDlgItemText(hwndDlg,IDC_PASSWORD,password); + if (use_auth) + CheckDlgButton(hwndDlg,IDC_AUTH,1); + else + CheckDlgButton(hwndDlg,IDC_AUTH,0); + + + break; + + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: GetDlgItemText(hwndDlg,IDC_USERNAME,username,20); + GetDlgItemText(hwndDlg,IDC_PASSWORD,password,20); + use_auth_int = IsDlgButtonChecked(hwndDlg,IDC_AUTH); + if (use_auth_int == 0) + use_auth = false; + else + use_auth = true; + + break; + } + break; + } + return false; +} + + +// -------------------------------------------------------------------------------- +// About window proc +BOOL CALLBACK ConfigAboutWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + break; + + + case WM_NOTIFY: + switch (((NMHDR FAR *) lParam)->code) + { + case PSN_APPLY: break; + } + break; + } + return false; +} + +// -------------------------------------------------------------------------------- +// WindowProc for Config dialog +BOOL CALLBACK ConfigWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + ConfigWnd = hwndDlg; // Keep global pointer to window so no more than one is active + char temp[100]; + switch (uMsg) + { + case WM_INITDIALOG: + int def_button; + switch(default_action) + { + case WA_PREV: + def_button = IDC_DEF_PREV; + break; + case WA_PLAY: + def_button = IDC_DEF_PLAY; + break; + case WA_PAUSE: + def_button = IDC_DEF_PAUSE; + break; + case WA_STOP: + def_button = IDC_DEF_STOP; + break; + case WA_NEXT: + def_button = IDC_DEF_NEXT; + break; + } + SetDlgItemText(hwndDlg,IDC_HOST,host); + wsprintf(temp,"%d",port); + SetDlgItemText(hwndDlg,IDC_PORT,temp); + wsprintf(temp,"%d",update_delay); + SetDlgItemText(hwndDlg,IDC_UPDATEDELAY,temp); + SetDlgItemText(hwndDlg,IDC_USERNAME,username); + SetDlgItemText(hwndDlg,IDC_PASSWORD,password); + CheckRadioButton(hwndDlg,IDC_DEF_PREV,IDC_DEF_NEXT,def_button); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDCANCEL: EndDialog(hwndDlg,0); + break; + case IDABOUT: MessageBox(hwnd,AboutText,szAppName,MB_OK | MB_ICONINFORMATION); + break; + case IDOK: GetDlgItemText(hwndDlg,IDC_HOST,host,255); + port = GetDlgItemInt(hwndDlg,IDC_PORT,NULL,false); + update_delay = GetDlgItemInt(hwndDlg,IDC_UPDATEDELAY,NULL,false); + KillTimer(hwnd,timer_id); + timer_id = SetTimer(hwnd,TIMER_ID,update_delay*1000,NULL); + GetDlgItemText(hwndDlg,IDC_USERNAME,username,20); + GetDlgItemText(hwndDlg,IDC_PASSWORD,password,20); + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED) + default_action = WA_PREV; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED) + default_action = WA_PREV; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PLAY) == BST_CHECKED) + default_action = WA_PLAY; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PAUSE) == BST_CHECKED) + default_action = WA_PAUSE; + else + if (IsDlgButtonChecked(hwndDlg,IDC_DEF_STOP) == BST_CHECKED) + default_action = WA_STOP; + else + default_action = WA_NEXT; + + systray_modify(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(GetIconID())),szAppName); + config_write(); + EndDialog(hwndDlg,0); + break; + + } + } + return FALSE; +} + + + + + +// -------------------------------------------------------------------------------- +// write config +void config_write() +{ + char ini_file[MAX_PATH], *p; + char string[32]; + GetModuleFileName(inst,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"client.ini"); + + wsprintf(string,"%d",port); + WritePrivateProfileString(szAppName,"port",string,ini_file); + + wsprintf(string,"%d",default_action); + WritePrivateProfileString(szAppName,"default",string,ini_file); + + wsprintf(string,"%d",update_delay); + WritePrivateProfileString(szAppName,"updatedelay",string,ini_file); + + if (use_auth) + WritePrivateProfileString(szAppName,"auth","1",ini_file); + else + WritePrivateProfileString(szAppName,"auth","0",ini_file); + + + WritePrivateProfileString(szAppName,"host",host,ini_file); + WritePrivateProfileString(szAppName,"username",username,ini_file); + WritePrivateProfileString(szAppName,"password",password,ini_file); + + +} + +// -------------------------------------------------------------------------------- +// read config (port and password) +void config_read() +{ + char ini_file[MAX_PATH], *p; + GetModuleFileName(inst,ini_file,sizeof(ini_file)); + p=ini_file+lstrlen(ini_file); + while (p >= ini_file && *p != '\\') p--; + if (++p >= ini_file) *p = 0; + lstrcat(ini_file,"client.ini"); + + GetPrivateProfileString(szAppName,"host","127.0.0.1",(char*)&host,255,ini_file); + GetPrivateProfileString(szAppName,"username","user",(char*)&username,20,ini_file); + GetPrivateProfileString(szAppName,"password","password",(char*)&password,20,ini_file); + + port = GetPrivateProfileInt(szAppName,"port",80,ini_file); + default_action = GetPrivateProfileInt(szAppName,"default",WA_NEXT,ini_file); + update_delay = GetPrivateProfileInt(szAppName,"updatedelay",10,ini_file); + + int use_auth_int = GetPrivateProfileInt(szAppName,"auth",0,ini_file); + if (use_auth_int == 1) + use_auth = true; + else + use_auth = false; + +} + + +// -------------------------------------------------------------------------------- +// WindowProc for Volume dialog +BOOL CALLBACK VolumeWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + char temp[50]; + VolumeWnd = hwndDlg; + HWND SliderWnd; + POINT mousepos; + + switch(uMsg) + { + case WM_INITDIALOG: + GetCursorPos(&mousepos); + SetWindowPos(hwndDlg,HWND_TOP,mousepos.x-46,mousepos.y-95,0,0,SWP_NOSIZE); + SliderWnd = GetDlgItem(hwndDlg,IDC_VOLUME); + SendMessage(SliderWnd, TBM_SETRANGE, (WPARAM) true, (LPARAM) MAKELONG(0,10)); + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDC_DONE: + EndDialog(hwndDlg,0); + break; + } + break; + + + case WM_VSCROLL: + DWORD dwPos; + + switch(LOWORD(wParam)) + { + case TB_THUMBTRACK: + case TB_LINEDOWN: + case TB_LINEUP: + case TB_PAGEDOWN: + case TB_PAGEUP: + + SliderWnd = GetDlgItem(hwndDlg,IDC_VOLUME); + dwPos = SendMessage(SliderWnd, TBM_GETPOS, 0, 0); + wsprintf(temp,"/vol?volume=%d",10-dwPos); + //MessageBox(SliderWnd,temp,"Slider Position",MB_OK | MB_TOPMOST); + WASend(temp); + return 0; + break; + + default: + break; + + } + break; + + + } + return false; +} + diff --git a/gen_httpSrv_systray/connection.cpp b/gen_httpSrv_systray/connection.cpp new file mode 100644 index 0000000..1fdf807 --- /dev/null +++ b/gen_httpSrv_systray/connection.cpp @@ -0,0 +1,340 @@ +#include <windows.h> +#include <winsock.h> + +#include "resource.h" +#include "main.h" + +extern char szAppName[]; +extern char username[20], password[20], title[255]; +extern char host[255]; +extern int port; + +extern bool use_auth; + +extern HWND hwnd; + + +// Base64 character array +// 0 1 2 3 4 5 6 +// 01234567890123456789012345678901234567890123456789012345678901234 +const char bchars[] = "=BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+*"; + + +// -------------------------------------------------------------------------------- +// Start winsock +bool StartWinSock() +{ + WORD wVersionRequested = MAKEWORD(2,2); + WSADATA wsaData; + + if (WSAStartup(wVersionRequested, &wsaData ) != 0 ) + { + MessageBox(NULL, "ERROR: Winsock not available", szAppName, MB_OK); + return false; + } + return true; +} + + +// -------------------------------------------------------------------------------- +// Low level socket writing function - strings +void prints(SOCKET socket, char * string) +{ + int i=0; + while (string[i] != 0) + i++; + + if (send(socket,string,i,0) == SOCKET_ERROR) + { + //MessageBox(NULL,"Socket send() error!",szAppName,MB_OK); + } +} + +// Low level socket writing function - integers +void printsi(SOCKET socket,int number) +{ + char buffer[256]; + wsprintf(buffer,"%d",number); // Stick it in a string and call prints() + prints(socket,(char*)&buffer); +} + + +// -------------------------------------------------------------------------------- +// Opens socket +bool MakeRequest(char * host, int port, char * url, bool verbose, bool auth, bool gettitle) +{ + //MessageBox(NULL,"Entering MakeRequest","wawitray",MB_OK | MB_TOPMOST); + + SOCKET ssocket = socket(AF_INET,SOCK_STREAM,0); + if (ssocket == INVALID_SOCKET) + { + if (verbose) + MessageBox(NULL, "ERROR: Couldn't create socket", szAppName, MB_OK); + return false; + } + + + struct sockaddr_in server_address; + ZeroMemory(&server_address,sizeof(server_address)); + + server_address.sin_family = AF_INET; + + server_address.sin_addr.s_addr = inet_addr(host); + server_address.sin_port = htons(port); + + if (SOCKET_ERROR == connect(ssocket,(sockaddr*)&server_address,sizeof(sockaddr_in))) + { + if (verbose) + MessageBox(hwnd,"Couldn't connect to remote Winamp!\n\nCheck you have the address and port right.",szAppName,MB_OK|MB_ICONERROR); + return false; + } + + char method[6]; + if (gettitle) + wsprintf(method,"GET"); + else + wsprintf(method,"HEAD"); + + char request[100]; + + if (auth) + { + char b64userpass[100], userpass[100]; + wsprintf(userpass,"%s:%s",username,password); + ToBase64(userpass,b64userpass); + wsprintf(request,"%s %s HTTP/1.0\nAuthorisation: Basic %s\n\n",method,url,b64userpass); + } + else + { + wsprintf(request,"%s %s HTTP/1.0\nConnection: Close\n\n",method,url); + } + prints(ssocket,request); + + int res = GetResponse(ssocket,gettitle); + + closesocket(ssocket); + + switch(res) + { + case RES_OK: + break; + case RES_AUTH: + if (verbose) + MessageBox(hwnd,"Incorrect username or password!\n\nCheck the details are right in the Config window.",szAppName,MB_OK|MB_ICONERROR | MB_TOPMOST); + break; + case RES_NOTFOUND: + if (verbose) + MessageBox(hwnd,"Received a 404 Page Not Found response, which the Winamp HTTP Server does not produce!\n\nAre you sure your host and port settings are correct?",szAppName,MB_OK | MB_ICONERROR | MB_TOPMOST); + break; + case RES_BADREQUEST: + if (verbose) + MessageBox(hwnd,"Received a 400 Bad Request message, which the Winamp HTTP Server does not produce!\n\nCheck your Host and Port settings are correct.",szAppName, MB_OK | MB_ICONERROR | MB_TOPMOST); + case RES_UNKNOWN: + case RES_FAIL: + if (verbose) + MessageBox(hwnd,"Unknown HTTP Response",szAppName,MB_OK | MB_ICONWARNING | MB_TOPMOST); + break; + } + + //MessageBox(hwnd,"Leaving MakeRequest","wawitray",MB_OK | MB_TOPMOST); + return true; +} + + +int WASend(char * command) +{ + MakeRequest(host,port,command,true,use_auth,false); + return 1; +} + + + + +// -------------------------------------------------------------------------------- +// Converts a string to Base64 +void ToBase64(char * instr, char * outstr) +{ + //MessageBox(NULL,instr,"instr",MB_OK); + + int i=0; + int o=0; + int j = lstrlen(instr); + + bool done = false; + + while(instr[i] != 0 && done == false) + { + outstr[o] = bchars[(instr[i] & 0xFC) / 4]; + outstr[o+1] = bchars[((instr[i] & 0x03) * 16) + ((instr[i+1] & 0xF0) / 16)]; + if (instr[i+1] == 0) + { + outstr[o+2] = '='; + outstr[o+3] = '='; + done = true; + } + else + { + outstr[o+2] = bchars[((instr[i+1] & 0x0F) * 4) + ((instr[i+2] & 0xC0) /64)]; + if (instr[i+2] == 0) + { + outstr[o+3] = '='; + done = true; + } + else + outstr[o+3] = bchars[(instr[i+2] & 0x3F)]; + } + + o += 4; + i += 3; + } + + outstr[o] = 0; +} + + +// -------------------------------------------------------------------------------- +// Receives return HTTP header +int GetResponse(SOCKET socket, bool gettitle) +{ + char buffer[2048],http_version[20],response[5],text[100]; + int buffer_len; + int buffer_filled = 0; + int buffer_left; + bool complete = false; + + int breaks; + if (gettitle) + breaks = 1; + else + breaks = 0; + + + while(true) + { + // receive data + buffer_len = sizeof(buffer); + buffer_left = buffer_len-buffer_filled; + if (buffer_left <= 0) + buffer_len = 0; + else + buffer_len = recv(socket,buffer + buffer_filled,buffer_len-buffer_filled,0); + + if (buffer_len != SOCKET_ERROR && buffer_len != 0) + { + buffer_filled += buffer_len; + // scan for end of header + for (int i=0;i<=buffer_filled;i++) + if (buffer[i]=='\n' && (buffer[i+1]=='\n' || buffer[i+2]=='\n')) + { + if (breaks == 0) + { + buffer[i+1] = 0; + //MessageBox(NULL,buffer,"gen_httpsrv debug", MB_OK); + char * chptr = (char*)&buffer; + + chptr = GetAString(chptr,http_version); + chptr = GetAString(chptr,response); + chptr = GetAString(chptr,text); + chptr = SkipHeader(chptr); + + if (StrComp(response,"200")) + { + if (gettitle) + GetALine(chptr,title); + return RES_OK; + } + if (StrComp(response,"401")) + return RES_AUTH; + if (StrComp(response,"404")) + return RES_NOTFOUND; + if (StrComp(response,"400")) + return RES_BADREQUEST; + + return RES_UNKNOWN; + } + else + breaks--; + } + } + else + { + return RES_FAIL; + } + } +} + + + + +// -------------------------------------------------------------------------------- +// Retrieves next token from buffer +char * GetAString(char* chptr, char* text) // Old GetAString - only accepts single words +{ + int bptr = 0; + int tptr = 0; + while (chptr[bptr] == ' ' || chptr[bptr] == '\n' || chptr[bptr] == '\r') // skip leading spaces and stuff + bptr++; + + while (chptr[bptr] != 0 && chptr[bptr] != ' ' && chptr[bptr] != '\n' && chptr[bptr] != '\r' && bptr < 255) // while current char is a letter + { + text[tptr] = chptr[bptr]; // add letter to text[] + bptr++; + tptr++; + } + text[tptr] = 0; + chptr = chptr + bptr; + return chptr; // return pointer to the end of this string +} + +// -------------------------------------------------------------------------------- +// Skips the rest of the HTTP header +char * SkipHeader(char * chptr) +{ + while (chptr[0] != '\n' || (chptr[1] != '\n' && chptr[2] != '\r')) + chptr++; + return chptr; +} +// -------------------------------------------------------------------------------- +// Gets a whole line +char * GetALine(char * chptr, char * text) +{ + int bptr = 0; + int tptr = 0; + while (chptr[bptr] == ' ' || chptr[bptr] == '\n' || chptr[bptr] == '\r') // skip leading spaces and stuff + bptr++; + + while (chptr[bptr] != 0 && chptr[bptr] != '\n' && chptr[bptr] != '\r' && bptr < 255) // while current char is a letter + { + text[tptr] = chptr[bptr]; // add letter to text[] + bptr++; + tptr++; + } + text[tptr] = 0; + chptr = chptr + bptr; + return chptr; // return pointer to the end of this string +} + + +// -------------------------------------------------------------------------------- +// Strcmp() without using Clib +bool StrComp(char * string1, char * string2) +{ + int ptr=0; + + while (ToLowerCase(string1[ptr]) == ToLowerCase(string2[ptr])) // while the strings are the same, keep going + { + if (string1[ptr] == 0) // if they're the same and 0, they're identical null terminated strings + return true; + ptr++; + } + return false; // if not the same, they're... not the same +} + +// -------------------------------------------------------------------------------- +// Convert a char to lower case +char ToLowerCase(char c) +{ + if (c >= 'A' && c <= 'Z') + c += 32; + return c; +} diff --git a/gen_httpSrv_systray/gen_httpSrv_systray.dsp b/gen_httpSrv_systray/gen_httpSrv_systray.dsp new file mode 100644 index 0000000..95aa081 --- /dev/null +++ b/gen_httpSrv_systray/gen_httpSrv_systray.dsp @@ -0,0 +1,188 @@ +# Microsoft Developer Studio Project File - Name="gen_httpSrv_systray" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=gen_httpSrv_systray - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gen_httpSrv_systray.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gen_httpSrv_systray.mak" CFG="gen_httpSrv_systray - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gen_httpSrv_systray - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "gen_httpSrv_systray - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gen_httpSrv_systray - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib winmm.lib comctl32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/wawitray.exe" + +!ELSEIF "$(CFG)" == "gen_httpSrv_systray - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib winmm.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/wawitray.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gen_httpSrv_systray - Win32 Release" +# Name "gen_httpSrv_systray - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\config.cpp +# End Source File +# Begin Source File + +SOURCE=.\connection.cpp +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\resource1.rc +# End Source File +# Begin Source File + +SOURCE=.\title.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\main.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\Images\auth2.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\next.bmp +# End Source File +# Begin Source File + +SOURCE=.\next.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\pause.bmp +# End Source File +# Begin Source File + +SOURCE=.\pause.ICO +# End Source File +# Begin Source File + +SOURCE=.\Images\play.bmp +# End Source File +# Begin Source File + +SOURCE=.\play.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\prev.bmp +# End Source File +# Begin Source File + +SOURCE=.\prev.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\SECUR08.ICO +# End Source File +# Begin Source File + +SOURCE=.\Images\server.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\stop.bmp +# End Source File +# Begin Source File + +SOURCE=.\stop.ico +# End Source File +# Begin Source File + +SOURCE=.\Images\Title.bmp +# End Source File +# Begin Source File + +SOURCE=.\Images\winamp.ico +# End Source File +# End Group +# End Target +# End Project diff --git a/gen_httpSrv_systray/gen_httpSrv_systray.dsw b/gen_httpSrv_systray/gen_httpSrv_systray.dsw new file mode 100644 index 0000000..0bcb1fb --- /dev/null +++ b/gen_httpSrv_systray/gen_httpSrv_systray.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gen_httpSrv_systray"=.\gen_httpSrv_systray.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/gen_httpSrv_systray/main.cpp b/gen_httpSrv_systray/main.cpp new file mode 100644 index 0000000..4a1f3ec --- /dev/null +++ b/gen_httpSrv_systray/main.cpp @@ -0,0 +1,333 @@ +#include <windows.h> +#include <winsock.h> + +#include "main.h" +#include "resource.h" + +char szAppName[] = "Wawi Tray"; +char szWndClass[] = "WawiTrayApp"; + +char AboutText[] = "Winamp Web Interface\n\nRemote SysTray Client\n\n© 2002 Phil Himsworth\n\nWeb: http://www.flippet.org\nEmail: contact@flippet.net"; + +HINSTANCE inst = NULL; +HWND hwnd = NULL; +HWND ConfigWnd = NULL; +HWND VolumeWnd = NULL; + +UINT timer_id; + +bool done = false; + +char username[20]; +char password[20]; +char host[255]; + +char title[255]; + +bool use_auth = false; + +int port; +int default_action; +int update_delay; + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + + inst = hInstance; + + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = inst; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = (HBRUSH)COLOR_BACKGROUND; + wc.lpszMenuName = NULL; //MAKEINTRESOURCE(IDR_MENU); + wc.lpszClassName = szWndClass; + wc.hIconSm = NULL; + + if (RegisterClassEx(&wc)==0) + MessageBox(NULL,"RegisterClassEx error!", szAppName,MB_OK); + + + hwnd = CreateWindowEx( 0, + szWndClass, + szAppName, + WS_CAPTION | WS_SYSMENU, + CW_USEDEFAULT, + CW_USEDEFAULT, + 200, + 100, + NULL, + NULL, + inst, + NULL); + + + // Shows the window. Used only for message debugging + //ShowWindow(hwnd,nShowCmd); + + StartWinSock(); + + config_read(); + + int default_icon = GetIconID(); + + if (systray_add(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(default_icon)),szAppName) == 0) + MessageBox(hwnd,"systray_add error",szAppName,MB_OK); + + /* + UINT SetTimer( + HWND hWnd, // handle of window for timer messages + UINT nIDEvent, // timer identifier + UINT uElapse, // time-out value + TIMERPROC lpTimerFunc // address of timer procedure + ); + */ + + timer_id = SetTimer(hwnd,TIMER_ID,update_delay*1000,NULL); + + + //HANDLE titlethread; + //DWORD titlethread_id; + + //titlethread = CreateThread(NULL,0,TitleThread,0,0,&titlethread_id); + + MSG msg; + ZeroMemory(&msg,sizeof(msg)); + + while(done == false) + { + GetMessage(&msg,hwnd,0,0); + DispatchMessage(&msg); + } + + + systray_del(hwnd,1030); + return 0; + +} + +void SendDefaultAction() +{ + switch(default_action) + { + case WA_PREV: + WASend("/prev"); + break; + case WA_PLAY: + WASend("/play"); + break; + case WA_PAUSE: + WASend("/pause"); + break; + case WA_STOP: + WASend("/stop"); + break; + case WA_NEXT: + WASend("/next"); + break; + } +} + +int GetIconID() +{ + switch(default_action) + { + case WA_PREV: + return IDI_PREV; + break; + case WA_PLAY: + return IDI_PLAY; + break; + case WA_PAUSE: + return IDI_PAUSE; + break; + case WA_STOP: + return IDI_STOP; + break; + case WA_NEXT: + return IDI_NEXT; + break; + default: + return 0; + } +} + + + +LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + UINT mousemsg; + HMENU menu; + char path[MAX_PATH]; + + switch(uMsg) + { + case WM_DESTROY: + PostQuitMessage(0); + done = true; + break; + + case WM_USER+3: + mousemsg = (UINT)lParam; + switch(mousemsg) + { + case WM_LBUTTONDOWN: + SendDefaultAction(); + break; + + case WM_RBUTTONDOWN: + menu = GetSubMenu(LoadMenu(inst,MAKEINTRESOURCE(IDR_MENU)),0); + POINT pt; + GetCursorPos(&pt); + SetForegroundWindow(hwnd); + SetMenuItemBitmaps(menu,IDM_PREV,MF_BYCOMMAND,LoadBitmap(inst,MAKEINTRESOURCE(IDB_PREV)),NULL); + SetMenuItemBitmaps(menu,IDM_PLAY,MF_BYCOMMAND,LoadBitmap(inst,MAKEINTRESOURCE(IDB_PLAY)),NULL); + SetMenuItemBitmaps(menu,IDM_PAUSE,MF_BYCOMMAND,LoadBitmap(inst,MAKEINTRESOURCE(IDB_PAUSE)),NULL); + SetMenuItemBitmaps(menu,IDM_STOP,MF_BYCOMMAND,LoadBitmap(inst,MAKEINTRESOURCE(IDB_STOP)),NULL); + SetMenuItemBitmaps(menu,IDM_NEXT,MF_BYCOMMAND,LoadBitmap(inst,MAKEINTRESOURCE(IDB_NEXT)),NULL); + + TrackPopupMenu(menu,0,pt.x,pt.y,0,hwnd,NULL); + //SetMenuDefaultItem(menu,IDM_NEXT,FALSE); + PostMessage(hwnd,WM_NULL,0,0); + break; + + default: + break; + } + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDM_QUIT: + done = true; + DestroyWindow(hwnd); + break; + case IDM_ABOUT: + MessageBox(hwnd,AboutText,szAppName,MB_OK | MB_ICONINFORMATION); + break; + case IDM_CONFIG: + if (!ConfigWnd) + { + NewConfig(); + ConfigWnd = NULL; + } + else + SetActiveWindow(ConfigWnd); + break; + + case IDM_VOLUME: + if (!VolumeWnd) + { + DialogBox(inst,MAKEINTRESOURCE(IDD_VOLUME),hwnd,VolumeWndProc); + VolumeWnd = NULL; + } + else + SetActiveWindow(VolumeWnd); + break; + + case IDM_BROWSE: + wsprintf(path,"http://%s:%d/winamp?page=browse",host,port); + //MessageBox(hwnd,path,"Browse Path",MB_OK | MB_TOPMOST); + ShellExecute(hwnd,"open",path,NULL,NULL,0); + break; + + case IDM_PLAYLIST: + wsprintf(path,"http://%s:%d/winamp?page=list",host,port); + //MessageBox(hwnd,path,"Browse Path",MB_OK | MB_TOPMOST); + ShellExecute(hwnd,"open",path,NULL,NULL,0); + break; + + // Winamp Control Items + case IDM_PREV: + WASend("/prev"); + break; + case IDM_PLAY: + WASend("/play"); + break; + case IDM_PAUSE: + WASend("/pause"); + break; + case IDM_STOP: + WASend("/stop"); + break; + case IDM_NEXT: + WASend("/next"); + break; + + + } + break; + + case WM_TIMER: + if ((UINT)wParam == timer_id) + { + MakeRequest(host,port,"/smalltitle",false,false,true); + if (StrComp(title,"")) + wsprintf(title,"%s",szAppName); + systray_modify(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(GetIconID())),title); + } + break; + + + default: + return DefWindowProc(hwnd,uMsg,wParam,lParam); + break; + } + + return 0; + +} + + + + + + + + +int systray_modify(HWND hwnd, UINT uID, HICON hIcon, LPSTR lpszTip) +{ + NOTIFYICONDATA tnid; + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hwnd; + tnid.uID = uID; + tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; + tnid.uCallbackMessage = WM_USER+3; + tnid.hIcon = hIcon; + lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip)-1); + return (Shell_NotifyIcon(NIM_MODIFY, &tnid)); +} + + + +int systray_add(HWND hwnd, UINT uID, HICON hIcon, LPSTR lpszTip) +{ + NOTIFYICONDATA tnid; + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hwnd; + tnid.uID = uID; + tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; + tnid.uCallbackMessage = WM_USER+3; + tnid.hIcon = hIcon; + lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip)-1); + return (Shell_NotifyIcon(NIM_ADD, &tnid)); +} + +int systray_del(HWND hwnd, UINT uID) +{ + NOTIFYICONDATA tnid; + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hwnd; + tnid.uID = uID; + return (Shell_NotifyIcon(NIM_DELETE, &tnid)); +} diff --git a/gen_httpSrv_systray/main.h b/gen_httpSrv_systray/main.h new file mode 100644 index 0000000..f3c156d --- /dev/null +++ b/gen_httpSrv_systray/main.h @@ -0,0 +1,61 @@ + +// Winamp actions +#define WA_PREV 101 +#define WA_PLAY 102 +#define WA_PAUSE 103 +#define WA_STOP 104 +#define WA_NEXT 105 + +#define RES_OK 201 +#define RES_AUTH 202 +#define RES_NOTFOUND 205 +#define RES_BADREQUEST 206 +#define RES_UNKNOWN 203 +#define RES_FAIL 204 + +#define TIMER_ID 30 + + +// config.cpp +void NewConfig(); +BOOL CALLBACK ConfigServerWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK ConfigSystrayWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK ConfigAuthWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK ConfigAboutWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +BOOL CALLBACK ConfigWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); +void config_write(); +void config_read(); +BOOL CALLBACK VolumeWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); + + + +// connection.cpp +bool StartWinSock(); +void prints(SOCKET socket, char * string); +void printsi(SOCKET socket,int number); +bool MakeRequest(char * host, int port, char * url, bool verbose, bool auth, bool gettitle); +int WASend(char * command); +void ToBase64(char * instr, char * outstr); +int GetResponse(SOCKET socket, bool gettitle); +char * GetAString(char* chptr, char* text); +char * SkipHeader(char * chptr); +char * GetALine(char * chptr, char * text); +bool StrComp(char * string1, char * string2); +char ToLowerCase(char c); + +// main.cpp +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow); + +void SendDefaultAction(); +int GetIconID(); +LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +int systray_modify(HWND hwnd, UINT uID, HICON hIcon, LPSTR lpszTip); +int systray_add(HWND hwnd, UINT uID, HICON hIcon, LPSTR lpszTip); +int systray_del(HWND hwnd, UINT uID); + + +// title.cpp +DWORD WINAPI TitleThread(LPVOID param); diff --git a/gen_httpSrv_systray/next.ico b/gen_httpSrv_systray/next.ico new file mode 100644 index 0000000..96fa9bd Binary files /dev/null and b/gen_httpSrv_systray/next.ico differ diff --git a/gen_httpSrv_systray/pause.ICO b/gen_httpSrv_systray/pause.ICO new file mode 100644 index 0000000..9c87a87 Binary files /dev/null and b/gen_httpSrv_systray/pause.ICO differ diff --git a/gen_httpSrv_systray/play.ico b/gen_httpSrv_systray/play.ico new file mode 100644 index 0000000..5f47614 Binary files /dev/null and b/gen_httpSrv_systray/play.ico differ diff --git a/gen_httpSrv_systray/prev.ico b/gen_httpSrv_systray/prev.ico new file mode 100644 index 0000000..198c6b2 Binary files /dev/null and b/gen_httpSrv_systray/prev.ico differ diff --git a/gen_httpSrv_systray/resource.h b/gen_httpSrv_systray/resource.h new file mode 100644 index 0000000..40ae1b8 --- /dev/null +++ b/gen_httpSrv_systray/resource.h @@ -0,0 +1,67 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resource1.rc +// +#define IDABOUT 3 +#define IDI_ICON1 101 +#define IDI_NEXT 101 +#define IDI_ICON2 102 +#define IDI_PAUSE 102 +#define IDI_ICON3 103 +#define IDI_PLAY 103 +#define IDI_ICON4 104 +#define IDI_PREV 104 +#define IDI_ICON5 105 +#define IDI_STOP 105 +#define IDD_CONFIG 106 +#define IDR_MENU 107 +#define IDD_VOLUME 108 +#define IDB_STOP 109 +#define IDB_PAUSE 110 +#define IDB_PLAY 111 +#define IDB_PREV 112 +#define IDB_NEXT 113 +#define IDD_SERVER 114 +#define IDD_AUTH 115 +#define IDD_SYSTRAY 116 +#define IDD_ABOUT 117 +#define IDB_TITLE 119 +#define IDI_WINAMP 120 +#define IDI_SERVER 121 +#define IDI_AUTH 122 +#define IDI_AUTH2 123 +#define IDC_HOST 1001 +#define IDC_PORT 1002 +#define IDC_USERNAME 1003 +#define IDC_PASSWORD 1005 +#define IDC_VOLUME 1006 +#define IDC_DONE 1007 +#define IDC_DEF_PREV 1008 +#define IDC_DEF_PLAY 1009 +#define IDC_DEF_PAUSE 1010 +#define IDC_DEF_STOP 1011 +#define IDC_DEF_NEXT 1012 +#define IDC_UPDATEDELAY 1013 +#define IDC_AUTH 1014 +#define IDM_PREV 40001 +#define IDM_PLAY 40002 +#define IDM_PAUSE 40003 +#define IDM_STOP 40004 +#define IDM_NEXT 40005 +#define IDM_CONFIG 40006 +#define IDM_QUIT 40007 +#define IDM_ABOUT 40008 +#define IDM_VOLUME 40009 +#define IDM_PLAYLIST 40010 +#define IDM_BROWSE 40011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 124 +#define _APS_NEXT_COMMAND_VALUE 40012 +#define _APS_NEXT_CONTROL_VALUE 1017 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/gen_httpSrv_systray/resource1.aps b/gen_httpSrv_systray/resource1.aps new file mode 100644 index 0000000..4f51c12 Binary files /dev/null and b/gen_httpSrv_systray/resource1.aps differ diff --git a/gen_httpSrv_systray/resource1.rc b/gen_httpSrv_systray/resource1.rc new file mode 100644 index 0000000..a926aeb --- /dev/null +++ b/gen_httpSrv_systray/resource1.rc @@ -0,0 +1,363 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_PAUSE ICON DISCARDABLE "pause.ICO" +IDI_PLAY ICON DISCARDABLE "play.ico" +IDI_PREV ICON DISCARDABLE "prev.ico" +IDI_STOP ICON DISCARDABLE "stop.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU MENU DISCARDABLE +BEGIN + POPUP "Menu" + BEGIN + MENUITEM "&Config...", IDM_CONFIG + MENUITEM "&Quit", IDM_QUIT + MENUITEM SEPARATOR + MENUITEM "Music Collection...", IDM_BROWSE + MENUITEM "Playlist...", IDM_PLAYLIST + MENUITEM "Volume...", IDM_VOLUME + MENUITEM SEPARATOR + MENUITEM "P&revious Track", IDM_PREV + MENUITEM "&Play", IDM_PLAY + MENUITEM "Pa&use", IDM_PAUSE + MENUITEM "&Stop", IDM_STOP + MENUITEM "&Next Track", IDM_NEXT + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_NEXT ICON DISCARDABLE "next.ico" +IDI_WINAMP ICON DISCARDABLE "Images\\winamp.ico" +IDI_SERVER ICON DISCARDABLE "Images\\server.ico" +IDI_AUTH ICON DISCARDABLE "Images\\SECUR08.ICO" +IDI_AUTH2 ICON DISCARDABLE "images\\auth2.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_CONFIG DIALOGEX 0, 0, 286, 212 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Winamp HTTP Server Systray Client Config" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,229,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,229,39,50,14 + PUSHBUTTON "About",IDABOUT,229,23,50,14 + GROUPBOX "Remote Winamp Properties",IDC_STATIC,7,7,218,43 + EDITTEXT IDC_HOST,13,29,98,12,ES_AUTOHSCROLL | NOT WS_BORDER, + WS_EX_STATICEDGE + EDITTEXT IDC_PORT,120,29,35,12,ES_AUTOHSCROLL | ES_NUMBER | NOT + WS_BORDER,WS_EX_STATICEDGE + LTEXT "Remote Computer",IDC_STATIC,13,19,72,9 + LTEXT "Port",IDC_STATIC,120,19,24,9 + EDITTEXT IDC_USERNAME,13,75,98,12,ES_AUTOHSCROLL | NOT WS_BORDER, + WS_EX_STATICEDGE + EDITTEXT IDC_PASSWORD,120,75,98,12,ES_PASSWORD | ES_AUTOHSCROLL | + NOT WS_BORDER,WS_EX_STATICEDGE + LTEXT "Username",IDC_STATIC,13,65,59,8 + LTEXT "Password",IDC_STATIC,120,65,50,8 + GROUPBOX "Systray Settings",IDC_STATIC,7,97,218,65 + CONTROL "Previous",IDC_DEF_PREV,"Button",BS_AUTORADIOBUTTON,15, + 122,45,10 + CONTROL "Play",IDC_DEF_PLAY,"Button",BS_AUTORADIOBUTTON,15,132, + 50,10 + CONTROL "Pause",IDC_DEF_PAUSE,"Button",BS_AUTORADIOBUTTON,71,122, + 50,10 + CONTROL "Stop",IDC_DEF_STOP,"Button",BS_AUTORADIOBUTTON,71,132, + 45,10 + CONTROL "Next",IDC_DEF_NEXT,"Button",BS_AUTORADIOBUTTON,131,122, + 50,10 + LTEXT "Default Action (single click on tray icon)",IDC_STATIC, + 16,109,140,10 + EDITTEXT IDC_UPDATEDELAY,120,145,35,12,ES_AUTOHSCROLL | ES_NUMBER | + NOT WS_BORDER,WS_EX_STATICEDGE + RTEXT "Tooltip update delay (s)",IDC_STATIC,39,147,75,10 + GROUPBOX "Authentication",IDC_STATIC,7,53,218,44 +END + +IDD_VOLUME DIALOGEX 0, 0, 46, 95 +STYLE DS_SYSMODAL | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION +EXSTYLE WS_EX_TOOLWINDOW +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Slider1",IDC_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | + TBS_VERT | TBS_TOP | WS_TABSTOP,20,5,20,70 + PUSHBUTTON "Done",IDC_DONE,8,80,27,10 + LTEXT "100%",IDC_STATIC,1,9,18,10 + LTEXT "0%",IDC_STATIC,9,64,10,10 +END + +IDD_SERVER DIALOGEX 0, 0, 220, 129 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + GROUPBOX "Winamp Server",IDC_STATIC,7,7,206,54 + EDITTEXT IDC_HOST,13,29,118,12,ES_AUTOHSCROLL | NOT WS_BORDER, + WS_EX_STATICEDGE + EDITTEXT IDC_PORT,141,29,35,12,ES_AUTOHSCROLL | ES_NUMBER | NOT + WS_BORDER,WS_EX_STATICEDGE + LTEXT "Remote Computer IP Address",IDC_STATIC,13,19,100,9 + LTEXT "Port",IDC_STATIC,141,19,24,9 +END + +IDD_AUTH DIALOGEX 0, 0, 220, 129 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + EDITTEXT IDC_USERNAME,13,44,86,12,ES_AUTOHSCROLL | NOT WS_BORDER, + WS_EX_STATICEDGE + EDITTEXT IDC_PASSWORD,107,44,98,12,ES_PASSWORD | ES_AUTOHSCROLL | + NOT WS_BORDER,WS_EX_STATICEDGE + LTEXT "Username",IDC_STATIC,13,33,59,8 + LTEXT "Password",IDC_STATIC,107,33,50,8 + GROUPBOX "Authentication",IDC_STATIC,7,7,206,58 + CONTROL "Use Authentication",IDC_AUTH,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,14,19,165,11 +END + +IDD_SYSTRAY DIALOGEX 0, 0, 220, 129 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + GROUPBOX "Systray Settings",IDC_STATIC,7,7,206,70 + CONTROL "Previous",IDC_DEF_PREV,"Button",BS_AUTORADIOBUTTON,26, + 34,45,10 + CONTROL "Play",IDC_DEF_PLAY,"Button",BS_AUTORADIOBUTTON,26,44,50, + 10 + CONTROL "Pause",IDC_DEF_PAUSE,"Button",BS_AUTORADIOBUTTON,90,34, + 50,10 + CONTROL "Stop",IDC_DEF_STOP,"Button",BS_AUTORADIOBUTTON,90,44,45, + 10 + CONTROL "Next",IDC_DEF_NEXT,"Button",BS_AUTORADIOBUTTON,151,34, + 50,10 + LTEXT "Default Action (single click on tray icon)",IDC_STATIC, + 16,21,140,10 + EDITTEXT IDC_UPDATEDELAY,120,57,35,12,ES_AUTOHSCROLL | ES_NUMBER | + NOT WS_BORDER,WS_EX_STATICEDGE + RTEXT "Tooltip update delay (s)",IDC_STATIC,39,59,75,10 +END + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 220, 129 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + CONTROL 119,IDC_STATIC,"Static",SS_BITMAP,7,7,20,20 + CTEXT "Wawi Remote Systray Thingy\n\nPhil Himsworth, 2002\nhttp://www.flippet.org || contact@flippet.net", + IDC_STATIC,7,81,206,34 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 279 + TOPMARGIN, 7 + BOTTOMMARGIN, 205 + END + + IDD_VOLUME, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 39 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END + + IDD_SERVER, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 122 + END + + IDD_AUTH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 122 + END + + IDD_SYSTRAY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 122 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 213 + TOPMARGIN, 7 + BOTTOMMARGIN, 122 + END +END +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,1,0,1 + PRODUCTVERSION 2,1,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "Remote Systray Applet for the Winamp Web Interface Plugin\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "WawiTray\0" + VALUE "FileVersion", "2, 1, 0, 1\0" + VALUE "InternalName", "WawiTray\0" + VALUE "LegalCopyright", "Copyright © 2002 Phil Himsworth\0" + VALUE "LegalTrademarks", "It's mine, dammit, MINE!!!\0" + VALUE "OriginalFilename", "WawiTray.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "WawiTray\0" + VALUE "ProductVersion", "2, 1, 0, 1\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_STOP BITMAP DISCARDABLE "Images\\stop.bmp" +IDB_PAUSE BITMAP DISCARDABLE "Images\\pause.bmp" +IDB_PLAY BITMAP DISCARDABLE "Images\\play.bmp" +IDB_PREV BITMAP DISCARDABLE "Images\\prev.bmp" +IDB_NEXT BITMAP DISCARDABLE "Images\\next.bmp" +IDB_TITLE BITMAP DISCARDABLE "Images\\Title.bmp" +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/gen_httpSrv_systray/stop.ico b/gen_httpSrv_systray/stop.ico new file mode 100644 index 0000000..6756fd9 Binary files /dev/null and b/gen_httpSrv_systray/stop.ico differ diff --git a/gen_httpSrv_systray/title.cpp b/gen_httpSrv_systray/title.cpp new file mode 100644 index 0000000..4f311aa --- /dev/null +++ b/gen_httpSrv_systray/title.cpp @@ -0,0 +1,32 @@ +#include <windows.h> +#include <winsock.h> + +#include "main.h" + +extern HINSTANCE inst; +extern HWND hwnd; + +extern char host[255], username[20], password[20], title[255]; +extern int port, default_action, update_delay; + +extern char szAppName[], AboutText[]; + +extern HWND ConfigWnd, VolumeWnd; + +// -------------------------------------------------------------------------------- +// Thread to update title in systray tooltip +DWORD WINAPI TitleThread(LPVOID param) +{ + while(true) + { + MakeRequest(host,port,"/smalltitle",false,false,true); + if (StrComp(title,"")) + wsprintf(title,"%s",szAppName); + systray_modify(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(GetIconID())),title); + //MessageBox(hwnd,title,"Title",MB_OK | MB_TOPMOST); + Sleep(update_delay*1000); + } + + return true; +} + diff --git a/gen_httpSrv_systray/wawitray.exe b/gen_httpSrv_systray/wawitray.exe new file mode 100644 index 0000000..36bd520 Binary files /dev/null and b/gen_httpSrv_systray/wawitray.exe differ diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..12d7010 --- /dev/null +++ b/install.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Winamp MPRIS Bridge Installer (FreeDesktop/XDG compliant) + +set -e + +# Configuration +BIN_DIR="$HOME/.local/bin" +SERVICE_NAME="winamp-mpris.service" +SYSTEMD_USER_DIR="$HOME/.config/systemd/user" + +echo "Installing Winamp MPRIS Bridge..." + +# 1. Create necessary directories +echo "Creating directories..." +mkdir -p "$BIN_DIR" +mkdir -p "$SYSTEMD_USER_DIR" + +# 2. Copy files to the correct locations +echo "Copying files..." +# Install the script to ~/.local/bin/winamp-mpris (removing .py extension for cleaner usage) +cp winamp_mpris.py "$BIN_DIR/winamp-mpris" +chmod +x "$BIN_DIR/winamp-mpris" + +# Install the service file +cp "$SERVICE_NAME" "$SYSTEMD_USER_DIR/" + +# 3. Reload systemd and enable/start the service +echo "Configuring systemd service..." +systemctl --user daemon-reload +systemctl --user enable "$SERVICE_NAME" +systemctl --user restart "$SERVICE_NAME" + +echo "Installation complete!" +echo "Script installed to: $BIN_DIR/winamp-mpris" +echo "Logs available at: ~/.local/state/winamp-mpris/bridge.log" +echo "PID file at: \$XDG_RUNTIME_DIR/winamp-mpris.pid" + +systemctl --user status "$SERVICE_NAME" --no-pager diff --git a/winamp-mpris.service b/winamp-mpris.service index 827c0af..5e9f95c 100644 --- a/winamp-mpris.service +++ b/winamp-mpris.service @@ -4,7 +4,7 @@ After=network.target [Service] Type=simple -ExecStart=/usr/bin/python3 %h/Scripts/winamp-mpris/winamp_mpris.py +ExecStart=%h/.local/bin/winamp-mpris Restart=always RestartSec=5 diff --git a/winamp_mpris.py b/winamp_mpris.py index eef0076..5f798b5 100755 --- a/winamp_mpris.py +++ b/winamp_mpris.py @@ -3,18 +3,49 @@ import requests import time import re import subprocess +import os +import logging from threading import Thread from pydbus import SessionBus from pydbus.generic import signal from gi.repository import GLib from bs4 import BeautifulSoup -# --- CONFIGURATION --- +# --- CONFIGURATION & XDG PATHS --- BASE_URL = "http://localhost:5666" AUTH = ('winamp', 'llama') APP_ID = "org.mpris.MediaPlayer2.winamp" DEFAULT_ART = "https://webamp.org/favicon.ico" +# XDG Standard Paths +XDG_STATE_HOME = os.environ.get("XDG_STATE_HOME", os.path.expanduser("~/.local/state")) +XDG_RUNTIME_DIR = os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}") + +LOG_DIR = os.path.join(XDG_STATE_HOME, "winamp-mpris") +LOG_FILE = os.path.join(LOG_DIR, "bridge.log") +PID_FILE = os.path.join(XDG_RUNTIME_DIR, "winamp-mpris.pid") + +# Ensure log directory exists +os.makedirs(LOG_DIR, exist_ok=True) + +# Configure Logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s', + handlers=[ + logging.FileHandler(LOG_FILE), + logging.StreamHandler() + ] +) +logger = logging.getLogger("winamp-mpris") + +def write_pid_file(): + try: + with open(PID_FILE, "w") as f: + f.write(str(os.getpid())) + except Exception as e: + logger.error(f"Failed to write PID file: {e}") + class WinampMPRIS: """ MPRIS2 specification implementation for Winamp Web Interface. @@ -94,16 +125,20 @@ class WinampMPRIS: self._volume = 1.0 def _request(self, endpoint): - print(f"COMMAND RECEIVED: {endpoint}") + logger.info(f"COMMAND RECEIVED: {endpoint}") try: r = requests.get(f"{BASE_URL}/{endpoint}", auth=AUTH, timeout=2) - if r.status_code != 200: + if r.status_code == 401: + msg = "401 Unauthorized: Check gen_httpsrv.dll plugin config. Ensure user 'winamp' has correct password and 'Play' permissions in Users tab." + logger.warning(f"ERROR: {msg}") + subprocess.run(["notify-send", "-u", "critical", "-t", "10000", "Winamp Bridge Auth Error", msg]) + elif r.status_code != 200: msg = f"Failed to send '{endpoint}' to Winamp (Status {r.status_code})." - print(f"ERROR: {msg}") + logger.error(f"ERROR: {msg}") subprocess.run(["notify-send", "-u", "critical", "-t", "3000", "Winamp Bridge Error", msg]) except Exception as e: msg = f"Connection error while sending '{endpoint}': {e}" - print(f"ERROR: {msg}") + logger.warning(f"ERROR: {msg}") subprocess.run(["notify-send", "-u", "critical", "-t", "3000", "Winamp Bridge Offline", msg]) # MPRIS Methods @@ -264,6 +299,7 @@ def update_loop(player): last_known_shuffle = False last_known_loop = "None" offline_logged = False + auth_error_logged = False while True: try: @@ -301,6 +337,7 @@ def update_loop(player): r = requests.get(f"{BASE_URL}/main", auth=AUTH, timeout=1) if r.status_code == 200: offline_logged = False + auth_error_logged = False soup = BeautifulSoup(r.text, 'html.parser') p_tags = soup.find_all('p') status_raw = p_tags[0].text if p_tags else "" @@ -357,10 +394,17 @@ def update_loop(player): player._title = status_raw.split('-')[0].replace("Playing track ", "").strip() player._artist = "Unknown" player._album = "" + elif r.status_code == 401: + if not auth_error_logged: + msg = "401 Unauthorized: Check gen_httpsrv.dll plugin config. Ensure user 'winamp' has correct password and 'Play' permissions in Users tab." + logger.warning(f"ERROR: {msg}") + subprocess.run(["notify-send", "-u", "critical", "-t", "10000", "Winamp Bridge Auth Error", msg]) + auth_error_logged = True + player._status = "Stopped" except requests.exceptions.RequestException: if not window_title: if not offline_logged: - print("Winamp Web Interface offline and no window found.") + logger.info("Winamp Web Interface offline and no window found.") offline_logged = True player._status = "Stopped" @@ -383,7 +427,7 @@ def update_loop(player): last_known_loop = player._loop_status album_str = f" [{player._album}]" if player._album else "" - print(f"UPDATE: [{player._status}] Shuffle: {player._shuffle}, Loop: {player._loop_status}, {player._artist}{album_str} - {player._title}") + logger.info(f"UPDATE: [{player._status}] Shuffle: {player._shuffle}, Loop: {player._loop_status}, {player._artist}{album_str} - {player._title}") player.PropertiesChanged( "org.mpris.MediaPlayer2.Player", @@ -398,12 +442,13 @@ def update_loop(player): ) except Exception as e: - print(f"Update error: {e}") + logger.error(f"Update error: {e}") time.sleep(1) if __name__ == "__main__": + write_pid_file() bus = SessionBus() player_logic = WinampMPRIS() bus.publish(APP_ID, ("/org/mpris/MediaPlayer2", player_logic)) @@ -420,7 +465,7 @@ if __name__ == "__main__": thread = Thread(target=update_loop, args=(player_logic,), daemon=True) thread.start() - print(f"--- Winamp Bridge Started (Window Title + Web UI + Album Art) ---") + logger.info(f"--- Winamp Bridge Started (Window Title + Web UI + Album Art) ---") loop = GLib.MainLoop() try: loop.run()