Imported from SVN by Bitbucket
24
ajquery/config
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
; ajquery template configuration file
|
||||||
|
;
|
||||||
|
; check readme.txt for usage details
|
||||||
|
;
|
||||||
|
[foo_httpcontrol]
|
||||||
|
url=/index.html
|
||||||
|
; defines formatting of a playlist row using foobar2000 titleformatting.
|
||||||
|
playlist_row={"a":"$fix_eol($replace(%artist%,\,\\,",\"))","b":"$fix_eol($replace(%album%,\,\\,",\"))","n":"$if(%queue_indexes%,'('%queue_indexes%') ',)$ifgreater(%totaldiscs%,1,D%discnumber%.,)%tracknumber%","t":"$fix_eol($replace(%title%,\,\\,",\"))","l":"%length%","ls":"%length_seconds%","d":"%date%"}
|
||||||
|
; defines formatting of a helper macros using foobar2000 titleformatting.
|
||||||
|
helper1=[%title% - ]
|
||||||
|
helper2=[%artist% - %title%]
|
||||||
|
helper3=[%codec% | %bitrate%kbps | %samplerate%Hz | %channels%]
|
||||||
|
; specifies wildcards where we should look for albumart files, separated by |. foobar2000 titleformatting is available there as well.
|
||||||
|
albumart=$directory_path(%path%)\folder.jpg|$directory_path(%path%)\*.jpg
|
||||||
|
; specifies path of a picture to show when albumart is not found.
|
||||||
|
albumart_not_found=ajquery/img/icon1rx.png
|
||||||
|
; specifies path of a picture to show when albumart is requested but not currently available (no playing track).
|
||||||
|
albumart_not_available=ajquery/img/icon1rx.png
|
||||||
|
; limits maximum albumart size to download, in bytes.
|
||||||
|
albumart_limit_size=0
|
||||||
|
; setting to 1 prefers embedded albumart over external.
|
||||||
|
albumart_prefer_embedded=0
|
||||||
|
; controls size of a playlist 'page'. setting to 0 completely disables playlist generation.
|
||||||
|
playlist_items_per_page=30
|
||||||
BIN
ajquery/css/smoothness/images/animated-overlay.gif
Executable file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
ajquery/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
Executable file
|
After Width: | Height: | Size: 212 B |
BIN
ajquery/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
Executable file
|
After Width: | Height: | Size: 208 B |
BIN
ajquery/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
Executable file
|
After Width: | Height: | Size: 335 B |
BIN
ajquery/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
Executable file
|
After Width: | Height: | Size: 207 B |
BIN
ajquery/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
Executable file
|
After Width: | Height: | Size: 262 B |
BIN
ajquery/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
Executable file
|
After Width: | Height: | Size: 262 B |
BIN
ajquery/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
Executable file
|
After Width: | Height: | Size: 332 B |
BIN
ajquery/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Executable file
|
After Width: | Height: | Size: 280 B |
BIN
ajquery/css/smoothness/images/ui-icons_222222_256x240.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
ajquery/css/smoothness/images/ui-icons_2e83ff_256x240.png
Executable file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
ajquery/css/smoothness/images/ui-icons_454545_256x240.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
ajquery/css/smoothness/images/ui-icons_888888_256x240.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
ajquery/css/smoothness/images/ui-icons_cd0a0a_256x240.png
Executable file
|
After Width: | Height: | Size: 4.4 KiB |
840
ajquery/css/smoothness/jquery-ui-1.10.4.custom.css
vendored
Executable file
@@ -0,0 +1,840 @@
|
|||||||
|
/*! jQuery UI - v1.10.4 - 2014-03-02
|
||||||
|
* http://jqueryui.com
|
||||||
|
* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.button.css, jquery.ui.dialog.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.tabs.css, jquery.ui.theme.css
|
||||||
|
* To view and modify this theme, visit http://jqueryui.com/themeroller/
|
||||||
|
* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
|
||||||
|
|
||||||
|
/* Layout helpers
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-helper-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-helper-hidden-accessible {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
.ui-helper-reset {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
line-height: 1.3;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 100%;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix:before,
|
||||||
|
.ui-helper-clearfix:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix:after {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.ui-helper-clearfix {
|
||||||
|
min-height: 0; /* support: IE7 */
|
||||||
|
}
|
||||||
|
.ui-helper-zfix {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
filter:Alpha(Opacity=0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-front {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Interaction Cues
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-disabled {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Icons
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* states and images */
|
||||||
|
.ui-icon {
|
||||||
|
display: block;
|
||||||
|
text-indent: -99999px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc visuals
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.ui-widget-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-resizable {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ui-resizable-handle {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 0.1px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.ui-resizable-disabled .ui-resizable-handle,
|
||||||
|
.ui-resizable-autohide .ui-resizable-handle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ui-resizable-n {
|
||||||
|
cursor: n-resize;
|
||||||
|
height: 7px;
|
||||||
|
width: 100%;
|
||||||
|
top: -5px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-resizable-s {
|
||||||
|
cursor: s-resize;
|
||||||
|
height: 7px;
|
||||||
|
width: 100%;
|
||||||
|
bottom: -5px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-resizable-e {
|
||||||
|
cursor: e-resize;
|
||||||
|
width: 7px;
|
||||||
|
right: -5px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-resizable-w {
|
||||||
|
cursor: w-resize;
|
||||||
|
width: 7px;
|
||||||
|
left: -5px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-resizable-se {
|
||||||
|
cursor: se-resize;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
right: 1px;
|
||||||
|
bottom: 1px;
|
||||||
|
}
|
||||||
|
.ui-resizable-sw {
|
||||||
|
cursor: sw-resize;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
left: -5px;
|
||||||
|
bottom: -5px;
|
||||||
|
}
|
||||||
|
.ui-resizable-nw {
|
||||||
|
cursor: nw-resize;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
left: -5px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
.ui-resizable-ne {
|
||||||
|
cursor: ne-resize;
|
||||||
|
width: 9px;
|
||||||
|
height: 9px;
|
||||||
|
right: -5px;
|
||||||
|
top: -5px;
|
||||||
|
}
|
||||||
|
.ui-button {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
line-height: normal;
|
||||||
|
margin-right: .1em;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
overflow: visible; /* removes extra width in IE */
|
||||||
|
}
|
||||||
|
.ui-button,
|
||||||
|
.ui-button:link,
|
||||||
|
.ui-button:visited,
|
||||||
|
.ui-button:hover,
|
||||||
|
.ui-button:active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
/* to make room for the icon, a width needs to be set here */
|
||||||
|
.ui-button-icon-only {
|
||||||
|
width: 2.2em;
|
||||||
|
}
|
||||||
|
/* button elements seem to need a little more width */
|
||||||
|
button.ui-button-icon-only {
|
||||||
|
width: 2.4em;
|
||||||
|
}
|
||||||
|
.ui-button-icons-only {
|
||||||
|
width: 3.4em;
|
||||||
|
}
|
||||||
|
button.ui-button-icons-only {
|
||||||
|
width: 3.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button text element */
|
||||||
|
.ui-button .ui-button-text {
|
||||||
|
display: block;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.ui-button-text-only .ui-button-text {
|
||||||
|
padding: .4em 1em;
|
||||||
|
}
|
||||||
|
.ui-button-icon-only .ui-button-text,
|
||||||
|
.ui-button-icons-only .ui-button-text {
|
||||||
|
padding: .4em;
|
||||||
|
text-indent: -9999999px;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-primary .ui-button-text,
|
||||||
|
.ui-button-text-icons .ui-button-text {
|
||||||
|
padding: .4em 1em .4em 2.1em;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-secondary .ui-button-text,
|
||||||
|
.ui-button-text-icons .ui-button-text {
|
||||||
|
padding: .4em 2.1em .4em 1em;
|
||||||
|
}
|
||||||
|
.ui-button-text-icons .ui-button-text {
|
||||||
|
padding-left: 2.1em;
|
||||||
|
padding-right: 2.1em;
|
||||||
|
}
|
||||||
|
/* no icon support for input elements, provide padding by default */
|
||||||
|
input.ui-button {
|
||||||
|
padding: .4em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button icon element(s) */
|
||||||
|
.ui-button-icon-only .ui-icon,
|
||||||
|
.ui-button-text-icon-primary .ui-icon,
|
||||||
|
.ui-button-text-icon-secondary .ui-icon,
|
||||||
|
.ui-button-text-icons .ui-icon,
|
||||||
|
.ui-button-icons-only .ui-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
.ui-button-icon-only .ui-icon {
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -8px;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-primary .ui-button-icon-primary,
|
||||||
|
.ui-button-text-icons .ui-button-icon-primary,
|
||||||
|
.ui-button-icons-only .ui-button-icon-primary {
|
||||||
|
left: .5em;
|
||||||
|
}
|
||||||
|
.ui-button-text-icon-secondary .ui-button-icon-secondary,
|
||||||
|
.ui-button-text-icons .ui-button-icon-secondary,
|
||||||
|
.ui-button-icons-only .ui-button-icon-secondary {
|
||||||
|
right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button sets */
|
||||||
|
.ui-buttonset {
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
.ui-buttonset .ui-button {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: -.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* workarounds */
|
||||||
|
/* reset extra padding in Firefox, see h5bp.com/l */
|
||||||
|
input.ui-button::-moz-focus-inner,
|
||||||
|
button.ui-button::-moz-focus-inner {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.ui-dialog {
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: .2em;
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-titlebar {
|
||||||
|
padding: .4em 1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-title {
|
||||||
|
float: left;
|
||||||
|
margin: .1em 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 90%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-titlebar-close {
|
||||||
|
position: absolute;
|
||||||
|
right: .3em;
|
||||||
|
top: 50%;
|
||||||
|
width: 20px;
|
||||||
|
margin: -10px 0 0 0;
|
||||||
|
padding: 1px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-content {
|
||||||
|
position: relative;
|
||||||
|
border: 0;
|
||||||
|
padding: .5em 1em;
|
||||||
|
background: none;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-buttonpane {
|
||||||
|
text-align: left;
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
background-image: none;
|
||||||
|
margin-top: .5em;
|
||||||
|
padding: .3em 1em .5em .4em;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-dialog-buttonpane button {
|
||||||
|
margin: .5em .4em .5em 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ui-dialog .ui-resizable-se {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
right: -5px;
|
||||||
|
bottom: -5px;
|
||||||
|
background-position: 16px 16px;
|
||||||
|
}
|
||||||
|
.ui-draggable .ui-dialog-titlebar {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
.ui-progressbar {
|
||||||
|
height: 2em;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.ui-progressbar .ui-progressbar-value {
|
||||||
|
margin: -1px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-progressbar .ui-progressbar-overlay {
|
||||||
|
background: url("images/animated-overlay.gif");
|
||||||
|
height: 100%;
|
||||||
|
filter: alpha(opacity=25);
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
.ui-progressbar-indeterminate .ui-progressbar-value {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.ui-slider {
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.ui-slider .ui-slider-handle {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.ui-slider .ui-slider-range {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
font-size: .7em;
|
||||||
|
display: block;
|
||||||
|
border: 0;
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For IE8 - See #6727 */
|
||||||
|
.ui-slider.ui-state-disabled .ui-slider-handle,
|
||||||
|
.ui-slider.ui-state-disabled .ui-slider-range {
|
||||||
|
filter: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-slider-horizontal {
|
||||||
|
height: .8em;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-handle {
|
||||||
|
top: -.3em;
|
||||||
|
margin-left: -.6em;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-range {
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-range-min {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ui-slider-horizontal .ui-slider-range-max {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-slider-vertical {
|
||||||
|
width: .8em;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-handle {
|
||||||
|
left: -.3em;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-bottom: -.6em;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-range {
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-range-min {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.ui-slider-vertical .ui-slider-range-max {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.ui-tabs {
|
||||||
|
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||||
|
padding: .2em;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav {
|
||||||
|
margin: 0;
|
||||||
|
padding: .2em .2em 0;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav li {
|
||||||
|
list-style: none;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
margin: 1px .2em 0 0;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
|
||||||
|
float: left;
|
||||||
|
padding: .5em 1em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
|
||||||
|
.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.ui-tabs .ui-tabs-panel {
|
||||||
|
display: block;
|
||||||
|
border-width: 0;
|
||||||
|
padding: 1em 1.4em;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component containers
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-widget {
|
||||||
|
font-family: Verdana,Arial,sans-serif;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
.ui-widget .ui-widget {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.ui-widget input,
|
||||||
|
.ui-widget select,
|
||||||
|
.ui-widget textarea,
|
||||||
|
.ui-widget button {
|
||||||
|
font-family: Verdana,Arial,sans-serif;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
.ui-widget-content {
|
||||||
|
border: 1px solid #aaaaaa;
|
||||||
|
background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;
|
||||||
|
color: #222222;
|
||||||
|
}
|
||||||
|
.ui-widget-content a {
|
||||||
|
color: #222222;
|
||||||
|
}
|
||||||
|
.ui-widget-header {
|
||||||
|
border: 1px solid #aaaaaa;
|
||||||
|
background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;
|
||||||
|
color: #222222;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ui-widget-header a {
|
||||||
|
color: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaction states
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-default,
|
||||||
|
.ui-widget-content .ui-state-default,
|
||||||
|
.ui-widget-header .ui-state-default {
|
||||||
|
border: 1px solid #d3d3d3;
|
||||||
|
background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #555555;
|
||||||
|
}
|
||||||
|
.ui-state-default a,
|
||||||
|
.ui-state-default a:link,
|
||||||
|
.ui-state-default a:visited {
|
||||||
|
color: #555555;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-state-hover,
|
||||||
|
.ui-widget-content .ui-state-hover,
|
||||||
|
.ui-widget-header .ui-state-hover,
|
||||||
|
.ui-state-focus,
|
||||||
|
.ui-widget-content .ui-state-focus,
|
||||||
|
.ui-widget-header .ui-state-focus {
|
||||||
|
border: 1px solid #999999;
|
||||||
|
background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #212121;
|
||||||
|
}
|
||||||
|
.ui-state-hover a,
|
||||||
|
.ui-state-hover a:hover,
|
||||||
|
.ui-state-hover a:link,
|
||||||
|
.ui-state-hover a:visited,
|
||||||
|
.ui-state-focus a,
|
||||||
|
.ui-state-focus a:hover,
|
||||||
|
.ui-state-focus a:link,
|
||||||
|
.ui-state-focus a:visited {
|
||||||
|
color: #212121;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.ui-state-active,
|
||||||
|
.ui-widget-content .ui-state-active,
|
||||||
|
.ui-widget-header .ui-state-active {
|
||||||
|
border: 1px solid #aaaaaa;
|
||||||
|
background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #212121;
|
||||||
|
}
|
||||||
|
.ui-state-active a,
|
||||||
|
.ui-state-active a:link,
|
||||||
|
.ui-state-active a:visited {
|
||||||
|
color: #212121;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interaction Cues
|
||||||
|
----------------------------------*/
|
||||||
|
.ui-state-highlight,
|
||||||
|
.ui-widget-content .ui-state-highlight,
|
||||||
|
.ui-widget-header .ui-state-highlight {
|
||||||
|
border: 1px solid #fcefa1;
|
||||||
|
background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;
|
||||||
|
color: #363636;
|
||||||
|
}
|
||||||
|
.ui-state-highlight a,
|
||||||
|
.ui-widget-content .ui-state-highlight a,
|
||||||
|
.ui-widget-header .ui-state-highlight a {
|
||||||
|
color: #363636;
|
||||||
|
}
|
||||||
|
.ui-state-error,
|
||||||
|
.ui-widget-content .ui-state-error,
|
||||||
|
.ui-widget-header .ui-state-error {
|
||||||
|
border: 1px solid #cd0a0a;
|
||||||
|
background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;
|
||||||
|
color: #cd0a0a;
|
||||||
|
}
|
||||||
|
.ui-state-error a,
|
||||||
|
.ui-widget-content .ui-state-error a,
|
||||||
|
.ui-widget-header .ui-state-error a {
|
||||||
|
color: #cd0a0a;
|
||||||
|
}
|
||||||
|
.ui-state-error-text,
|
||||||
|
.ui-widget-content .ui-state-error-text,
|
||||||
|
.ui-widget-header .ui-state-error-text {
|
||||||
|
color: #cd0a0a;
|
||||||
|
}
|
||||||
|
.ui-priority-primary,
|
||||||
|
.ui-widget-content .ui-priority-primary,
|
||||||
|
.ui-widget-header .ui-priority-primary {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.ui-priority-secondary,
|
||||||
|
.ui-widget-content .ui-priority-secondary,
|
||||||
|
.ui-widget-header .ui-priority-secondary {
|
||||||
|
opacity: .7;
|
||||||
|
filter:Alpha(Opacity=70);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.ui-state-disabled,
|
||||||
|
.ui-widget-content .ui-state-disabled,
|
||||||
|
.ui-widget-header .ui-state-disabled {
|
||||||
|
opacity: .35;
|
||||||
|
filter:Alpha(Opacity=35);
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.ui-state-disabled .ui-icon {
|
||||||
|
filter:Alpha(Opacity=35); /* For IE8 - See #6059 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* states and images */
|
||||||
|
.ui-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
.ui-icon,
|
||||||
|
.ui-widget-content .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_222222_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-widget-header .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_222222_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-default .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_888888_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-hover .ui-icon,
|
||||||
|
.ui-state-focus .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_454545_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-active .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_454545_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-highlight .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_2e83ff_256x240.png);
|
||||||
|
}
|
||||||
|
.ui-state-error .ui-icon,
|
||||||
|
.ui-state-error-text .ui-icon {
|
||||||
|
background-image: url(images/ui-icons_cd0a0a_256x240.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* positioning */
|
||||||
|
.ui-icon-blank { background-position: 16px 16px; }
|
||||||
|
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||||
|
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||||
|
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||||
|
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||||
|
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||||
|
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||||
|
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||||
|
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||||
|
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||||
|
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||||
|
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||||
|
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||||
|
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||||
|
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||||
|
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||||
|
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||||
|
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||||
|
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||||
|
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||||
|
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||||
|
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||||
|
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||||
|
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||||
|
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||||
|
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||||
|
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||||
|
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||||
|
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||||
|
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||||
|
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||||
|
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||||
|
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||||
|
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||||
|
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||||
|
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||||
|
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||||
|
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||||
|
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||||
|
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||||
|
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||||
|
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||||
|
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||||
|
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||||
|
.ui-icon-extlink { background-position: -32px -80px; }
|
||||||
|
.ui-icon-newwin { background-position: -48px -80px; }
|
||||||
|
.ui-icon-refresh { background-position: -64px -80px; }
|
||||||
|
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||||
|
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||||
|
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||||
|
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||||
|
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||||
|
.ui-icon-document { background-position: -32px -96px; }
|
||||||
|
.ui-icon-document-b { background-position: -48px -96px; }
|
||||||
|
.ui-icon-note { background-position: -64px -96px; }
|
||||||
|
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||||
|
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||||
|
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||||
|
.ui-icon-comment { background-position: -128px -96px; }
|
||||||
|
.ui-icon-person { background-position: -144px -96px; }
|
||||||
|
.ui-icon-print { background-position: -160px -96px; }
|
||||||
|
.ui-icon-trash { background-position: -176px -96px; }
|
||||||
|
.ui-icon-locked { background-position: -192px -96px; }
|
||||||
|
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||||
|
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||||
|
.ui-icon-tag { background-position: -240px -96px; }
|
||||||
|
.ui-icon-home { background-position: 0 -112px; }
|
||||||
|
.ui-icon-flag { background-position: -16px -112px; }
|
||||||
|
.ui-icon-calendar { background-position: -32px -112px; }
|
||||||
|
.ui-icon-cart { background-position: -48px -112px; }
|
||||||
|
.ui-icon-pencil { background-position: -64px -112px; }
|
||||||
|
.ui-icon-clock { background-position: -80px -112px; }
|
||||||
|
.ui-icon-disk { background-position: -96px -112px; }
|
||||||
|
.ui-icon-calculator { background-position: -112px -112px; }
|
||||||
|
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||||
|
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||||
|
.ui-icon-search { background-position: -160px -112px; }
|
||||||
|
.ui-icon-wrench { background-position: -176px -112px; }
|
||||||
|
.ui-icon-gear { background-position: -192px -112px; }
|
||||||
|
.ui-icon-heart { background-position: -208px -112px; }
|
||||||
|
.ui-icon-star { background-position: -224px -112px; }
|
||||||
|
.ui-icon-link { background-position: -240px -112px; }
|
||||||
|
.ui-icon-cancel { background-position: 0 -128px; }
|
||||||
|
.ui-icon-plus { background-position: -16px -128px; }
|
||||||
|
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||||
|
.ui-icon-minus { background-position: -48px -128px; }
|
||||||
|
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||||
|
.ui-icon-close { background-position: -80px -128px; }
|
||||||
|
.ui-icon-closethick { background-position: -96px -128px; }
|
||||||
|
.ui-icon-key { background-position: -112px -128px; }
|
||||||
|
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||||
|
.ui-icon-scissors { background-position: -144px -128px; }
|
||||||
|
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||||
|
.ui-icon-copy { background-position: -176px -128px; }
|
||||||
|
.ui-icon-contact { background-position: -192px -128px; }
|
||||||
|
.ui-icon-image { background-position: -208px -128px; }
|
||||||
|
.ui-icon-video { background-position: -224px -128px; }
|
||||||
|
.ui-icon-script { background-position: -240px -128px; }
|
||||||
|
.ui-icon-alert { background-position: 0 -144px; }
|
||||||
|
.ui-icon-info { background-position: -16px -144px; }
|
||||||
|
.ui-icon-notice { background-position: -32px -144px; }
|
||||||
|
.ui-icon-help { background-position: -48px -144px; }
|
||||||
|
.ui-icon-check { background-position: -64px -144px; }
|
||||||
|
.ui-icon-bullet { background-position: -80px -144px; }
|
||||||
|
.ui-icon-radio-on { background-position: -96px -144px; }
|
||||||
|
.ui-icon-radio-off { background-position: -112px -144px; }
|
||||||
|
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||||
|
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||||
|
.ui-icon-play { background-position: 0 -160px; }
|
||||||
|
.ui-icon-pause { background-position: -16px -160px; }
|
||||||
|
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||||
|
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||||
|
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||||
|
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||||
|
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||||
|
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||||
|
.ui-icon-stop { background-position: -96px -160px; }
|
||||||
|
.ui-icon-eject { background-position: -112px -160px; }
|
||||||
|
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||||
|
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||||
|
.ui-icon-power { background-position: 0 -176px; }
|
||||||
|
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||||
|
.ui-icon-signal { background-position: -32px -176px; }
|
||||||
|
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||||
|
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||||
|
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||||
|
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||||
|
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||||
|
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||||
|
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||||
|
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||||
|
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||||
|
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||||
|
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||||
|
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||||
|
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||||
|
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||||
|
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||||
|
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||||
|
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||||
|
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||||
|
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||||
|
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||||
|
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||||
|
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||||
|
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||||
|
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||||
|
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||||
|
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||||
|
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||||
|
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||||
|
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||||
|
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc visuals
|
||||||
|
----------------------------------*/
|
||||||
|
|
||||||
|
/* Corner radius */
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-top,
|
||||||
|
.ui-corner-left,
|
||||||
|
.ui-corner-tl {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-top,
|
||||||
|
.ui-corner-right,
|
||||||
|
.ui-corner-tr {
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-bottom,
|
||||||
|
.ui-corner-left,
|
||||||
|
.ui-corner-bl {
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
.ui-corner-all,
|
||||||
|
.ui-corner-bottom,
|
||||||
|
.ui-corner-right,
|
||||||
|
.ui-corner-br {
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overlays */
|
||||||
|
.ui-widget-overlay {
|
||||||
|
background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;
|
||||||
|
opacity: .3;
|
||||||
|
filter: Alpha(Opacity=30);
|
||||||
|
}
|
||||||
|
.ui-widget-shadow {
|
||||||
|
margin: -8px 0 0 -8px;
|
||||||
|
padding: 8px;
|
||||||
|
background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;
|
||||||
|
opacity: .3;
|
||||||
|
filter: Alpha(Opacity=30);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
BIN
ajquery/img/favicon.ico
Executable file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
ajquery/img/icon1rx.png
Executable file
|
After Width: | Height: | Size: 22 KiB |
BIN
ajquery/img/loading.gif
Executable file
|
After Width: | Height: | Size: 673 B |
168
ajquery/index.html
Executable file
@@ -0,0 +1,168 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<title>foobar2000</title>
|
||||||
|
<script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
|
||||||
|
<script type="text/javascript" src="js/jquery-ui-1.10.4.custom.min.js"></script>
|
||||||
|
<script type="text/javascript" src="js/ajquery.js"></script>
|
||||||
|
<link type="text/css" href="css/smoothness/jquery-ui-1.10.4.custom.css" rel="stylesheet" />
|
||||||
|
<link rel="shortcut Icon" href="/ajquery/img/favicon.ico" type="image/x-icon" />
|
||||||
|
<style type="text/css">
|
||||||
|
body{ font-size: 0.5em; margin: 10px; background-color: #ffffff; max-width: 600px;}
|
||||||
|
ul#buttons {margin: 0; padding: 0;}
|
||||||
|
ul#buttons li {margin: 3px; position: relative; padding: 4px 0; cursor: pointer; float: left; list-style: none;}
|
||||||
|
ul#buttons span.ui-icon {float: left; margin: 0 4px;}
|
||||||
|
button { margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; }
|
||||||
|
.lindicator { padding: 8px; visibility: hidden; }
|
||||||
|
|
||||||
|
.ui-progressbar .ui-progressbar-value { background: #e8e8e8; }
|
||||||
|
|
||||||
|
#pl { display: table; width: 100%; }
|
||||||
|
.pl_row { display: table-row; cursor: default; height: 18px;}
|
||||||
|
.pl_c1 { width: 15%; display: table-cell; padding: 2px; text-align: right; vertical-align: middle; }
|
||||||
|
.pl_c2 { width: 80%; display: table-cell; padding: 2px; vertical-align: middle; }
|
||||||
|
.pl_c3 { width: 5%; display: table-cell; padding: 2px; text-align: right; vertical-align: middle; }
|
||||||
|
.pl_even{ background: #f8f8f8; }
|
||||||
|
.pl_prev{ color:DarkGray; }
|
||||||
|
.pl_selected { background: #daeaff; border: 1px solid white; }
|
||||||
|
.bbl { border-left: 1px solid gray; } /* border black left */
|
||||||
|
.bbm { border-top: 1px solid gray; border-bottom: 1px solid gray; } /* border black top and bottom */
|
||||||
|
.bbr { border-right: 1px solid gray; } /* border black right */
|
||||||
|
.bwl { border-left: 1px solid white; } /* border white left */
|
||||||
|
.bwm { border-top: 1px solid white; border-bottom: 1px solid white; } /* border white top and bottom */
|
||||||
|
.bwr { border-right: 1px solid white; } /* border white right */
|
||||||
|
.bbt { border-bottom: 1px solid white; border-top: 1px solid gray; } /* border black top */
|
||||||
|
.pl-album { color: gray;}
|
||||||
|
|
||||||
|
#playlist { margin-right: -10px; margin-left: -10px; }
|
||||||
|
|
||||||
|
.br_o { background:#f8f8f8; } /* odd file browser row */
|
||||||
|
.br_g { color:#a5a5a5; } /* inactive file browser row */
|
||||||
|
|
||||||
|
hr { border: 0; border-bottom: 1px #b0b0b0 solid; }
|
||||||
|
#progressbar { cursor: pointer; margin-bottom: 12px; }
|
||||||
|
#playingtitle { float: left; font-size: 1em; padding: 0.25em; }
|
||||||
|
#playingtime { float: right; font-size: 1em; padding: 0.25em; }
|
||||||
|
#browse_table { width: 100%; /*height: 85%;*/ overflow-y: hidden; overflow-x:hidden; }
|
||||||
|
#aa_pane { opacity: .95; width: 233px; display: none; z-index: 2; cursor: move; margin: 0px;}
|
||||||
|
|
||||||
|
#querylist { height: 300px; overflow: visible;}
|
||||||
|
#querylist #qr { cursor: pointer; }
|
||||||
|
.qr_selected { background: #daeaff; }
|
||||||
|
|
||||||
|
#tooltip { background: #ededed; padding: 2px; border: 1px solid gray; display: none; z-index: 1000; }
|
||||||
|
|
||||||
|
.dragplacer-top div { border-top: 1px double red;}
|
||||||
|
.dragplacer-bottom div { border-bottom: 1px double red;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wnd">
|
||||||
|
<ul id="buttons" class="ui-widget ui-helper-clearfix" style="float: left;">
|
||||||
|
<li class="btncmd ui-state-default ui-corner-all" style="margin-left: 0px;" title="Stop" id="Stop"><span class="ui-icon ui-icon-stop"></span></li>
|
||||||
|
<li class="btncmd ui-state-default ui-corner-all" title="Start" id="Start"><span class="ui-icon ui-icon-play"></span></li>
|
||||||
|
<li class="btncmd ui-state-default ui-corner-all" title="Play or pause (Space)" id="PlayOrPause"><span class="ui-icon ui-icon-pause"></span></li>
|
||||||
|
<li class="btncmd ui-state-default ui-corner-all" title="Previous" id="StartPrevious"><span class="ui-icon ui-icon-seek-first"></span></li>
|
||||||
|
<li class="btncmd ui-state-default ui-corner-all" title="Next" id="StartNext"><span class="ui-icon ui-icon-seek-end"></span></li>
|
||||||
|
<li class="btncmd ui-state-default ui-corner-all" title="Random" id="StartRandom"><span class="ui-icon ui-icon-help"></span></li>
|
||||||
|
<li class=""></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Browse files" id="browse_btn"><span class="ui-icon ui-icon-folder-open"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Search media library" id="search_btn"><span class="ui-icon ui-icon-search"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Album art" id="aa_btn"><span class="ui-icon ui-icon-image"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Extended controls" id="pbs_btn"><span class="ui-icon ui-icon-gear"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" id="mute"><span class="ui-icon ui-icon-volume-off"></span></li>
|
||||||
|
<li id="vol"><!--<span>--><div id="volume" style="width: 150px; margin: 0.5em"></div><!--</span>--></li>
|
||||||
|
</ul>
|
||||||
|
<div id="loading" class="lindicator"> <img src="img/loading.gif"></div>
|
||||||
|
<p><div id="progressbar"><div id="playingtitle"></div><div id="playingtime"></div></div>
|
||||||
|
|
||||||
|
<div id="tabs" class="ui-tabs ui-helper-clearfix">
|
||||||
|
<ul>
|
||||||
|
<li><a href="#t"></a></li>
|
||||||
|
</ul>
|
||||||
|
<div id="t">
|
||||||
|
<div>
|
||||||
|
<div style="float: right; width: 8em;">
|
||||||
|
<ul id="buttons" class="ui-widget" style="margin-top: -1.3em; ">
|
||||||
|
<li style="border: 1px solid transparent;" title="" id="prevpage_btn"><span class="ui-icon ui-icon-arrowthick-1-w"></span></li>
|
||||||
|
<li style="border: 1px solid transparent;" title="" id="nextpage_btn"><span class="ui-icon ui-icon-arrowthick-1-e"></span></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:0.5em; margin-right: 11em"><div id="pageslider"></div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="playlist" style="clear: both;">lol</div>
|
||||||
|
<hr style="margin-right: -1.5em; margin-left: -1.5em;">
|
||||||
|
<div id="summary" style="margin-bottom: -0.5em"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="pbs_dlg" title="Extended controls">
|
||||||
|
<p>Playlist:</p>
|
||||||
|
<ul id="buttons" class="ui-widget ui-helper-clearfix">
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Add" id="CreatePlaylist"><span class="ui-icon ui-icon-plusthick"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Remove" id="RemovePlaylist"><span class="ui-icon ui-icon-closethick"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Rename" id="RenamePlaylist"><span class="ui-icon ui-icon-pencil"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Empty" id="EmptyPlaylist"><span class="ui-icon ui-icon-clipboard"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Undo (u)" id="Undo"><span class="ui-icon ui-icon-arrowreturnthick-1-w"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Redo (r)" id="Redo"><span class="ui-icon ui-icon-arrowreturnthick-1-e"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Refresh" id="RefreshPlaylist"><span class="ui-icon ui-icon-refresh"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Focus on playing" id="FocusOnPlaying"><span class="ui-icon ui-icon-lightbulb"></span></li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<p>Playlist items:</p>
|
||||||
|
<ul id="buttons" class="ui-widget ui-helper-clearfix">
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Enqueue selected items (q)" id="QueueItems"><span class="ui-icon ui-icon-circle-plus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Dequeue selected items (w)" id="DequeueItems"><span class="ui-icon ui-icon-circle-minus"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Queue random item" id="QueueRandomItems"><span class="ui-icon ui-icon-help"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Flush queue" id="FlushQueue"><span class="ui-icon ui-icon-trash"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Delete (Del)" id="Del"><span class="ui-icon ui-icon-minusthick"></span></li>
|
||||||
|
<li class="ui-state-default ui-corner-all" title="Set cursor" id="SetFocus"><span class="ui-icon ui-icon-pin-s"></span></li>
|
||||||
|
</ul>
|
||||||
|
<hr/>
|
||||||
|
<p>Playback order <select id="PBO"><option value="0">Default</option><option value="1">Repeat (playlist)</option><option value="2">Repeat (track)</option><option value="3">Random</option><option value="4">Shuffle (tracks)</option><option value="5">Shuffle (albums)</option><option value="6">Shuffle (folders)</option></select></p>
|
||||||
|
<p><input type="checkbox" id="SAC">Stop after current</p>
|
||||||
|
<p><input type="checkbox" id="SAQ">Stop after queue</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="aa_pane">
|
||||||
|
<img id="aa_img" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="search_dlg" title="Search media library">
|
||||||
|
<div id="querylist"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="search_dlg_nav1" class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" style="border-bottom-width: 1px; border-top-width: 0px; font-size: 1em; width: 100%; white-space:nowrap;">
|
||||||
|
<p>Search: <input type="text" size="30" id="searchstr"> <a style="padding-right: 5px;" href="http://wiki.hydrogenaudio.org/index.php?title=Foobar2000:Query_syntax" title="Query syntax help">?</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="search_dlg_nav2" class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" style="border-bottom-width: 1px; border-top-width: 0px; font-size: 1em; width: 100%; white-space:nowrap;">
|
||||||
|
<button id="r_btn">Query</button> <span id="querypath"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="browse_dlg" title="File browser">
|
||||||
|
<div id="browse_table"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="browse_dlg_nav" class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" style="border-bottom-width: 1px; border-top-width: 0px; font-size: 1em; width: 100%; white-space:nowrap;">
|
||||||
|
<a id="browse_parent" href="#"></a> <span id="browse_path"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="error_dlg" title="☠ Ouch!">
|
||||||
|
<p>An AJAX error occured.</p>
|
||||||
|
<p>Possible reasons:</p>
|
||||||
|
<ul>
|
||||||
|
<li>JSON parser got stuck on invalid data; response dump might be provided below so you can analyze what went wrong using JSON validator of your choice, for example: <a href="http://jsonformatter.curiousconcept.com/">http://jsonformatter.curiousconcept.com/</a>;</li>
|
||||||
|
<li>borken connection;</li>
|
||||||
|
<li>god knows what else.</li>
|
||||||
|
</ul>
|
||||||
|
<p><a href="/ajquery/index.html">Restart</a> template or think of something else.</p>
|
||||||
|
<hr/>
|
||||||
|
<textarea id="dbg" cols="90" rows="30"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span id="tooltip" class="ui-widget"></span>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1680
ajquery/js/ajquery.js
Executable file
6
ajquery/js/browser.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"path": [PATH_JS],
|
||||||
|
"pathcurrent": "[PATH]",
|
||||||
|
"parent": "[PATH_PARENT]",
|
||||||
|
"browser": [BROWSER_JS]
|
||||||
|
}
|
||||||
4
ajquery/js/jquery-1.11.0.min.js
vendored
Executable file
6
ajquery/js/jquery-ui-1.10.4.custom.min.js
vendored
Executable file
4
ajquery/js/library.json
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"queryInfo": [QUERY_INFO_JS],
|
||||||
|
"query": [QUERY_JS]
|
||||||
|
}
|
||||||
29
ajquery/js/state.json
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
{"playlist":[PLAYLIST_JS],
|
||||||
|
"playlists":[PLAYLISTS_JS],
|
||||||
|
"playbackOrder":"[PLAYBACK_ORDER]",
|
||||||
|
"volume":"[VOLUME]",
|
||||||
|
"volumedb":"[VOLUME_DB]",
|
||||||
|
"SAC":"[SAC]",
|
||||||
|
"SAQ":"[SAQ]",
|
||||||
|
"isPlaying":"[IS_PLAYING]",
|
||||||
|
"isPaused":"[IS_PAUSED]",
|
||||||
|
"isEnqueueing":"[IS_ENQUEUEING]",
|
||||||
|
"playingItem":"[PLAYLIST_ITEM_PLAYING]",
|
||||||
|
"focusedItem":"[PLAYLIST_ITEM_FOCUSED]",
|
||||||
|
"prevplayedItem":"[PLAYLIST_ITEM_PREV_PLAYED]",
|
||||||
|
"itemPlayingPos":"[ITEM_PLAYING_POS]",
|
||||||
|
"itemPlayingLen":"[ITEM_PLAYING_LEN]",
|
||||||
|
"playlistPage":"[PLAYLIST_PAGE]",
|
||||||
|
"playlistItemsPerPage":"[PLAYLIST_ITEMS_PER_PAGE]",
|
||||||
|
"playlistItemsCount":"[PLAYLIST_ITEMS_COUNT]",
|
||||||
|
"playlistActive":"[PLAYLIST_ACTIVE]",
|
||||||
|
"playlistPlaying":"[PLAYLIST_PLAYING]",
|
||||||
|
"playlistPlayingItemsCount":"[PLAYLIST_PLAYING_ITEMS_COUNT]",
|
||||||
|
"playlistTotalTime":"[PLAYLIST_TOTAL_TIME]",
|
||||||
|
"queueTotalTime":"[QUEUE_TOTAL_TIME]",
|
||||||
|
"isUndoAvailable":"[PLAYLIST_IS_UNDO_AVAILABLE]",
|
||||||
|
"isRedoAvailable":"[PLAYLIST_IS_REDO_AVAILABLE]",
|
||||||
|
"helper1":"[HELPER1X]",
|
||||||
|
"helper2":"[HELPER2X]",
|
||||||
|
"helper3":"[HELPER3X]",
|
||||||
|
"albumArt":"[ALBUMART]"}
|
||||||
194
ajquery/readme.txt
Executable file
@@ -0,0 +1,194 @@
|
|||||||
|
Asynchronious foo_httpcontrol template
|
||||||
|
0.72 http://code.google.com/p/foo-httpcontrol/
|
||||||
|
|
||||||
|
*** Requirements
|
||||||
|
|
||||||
|
This template is developed to be used in modern desktop browsers and
|
||||||
|
is fully compatible with Opera 10, Google Chrome 4 and Firefox 3.5.
|
||||||
|
Internet Exploder 8 seems to work as well.
|
||||||
|
|
||||||
|
Some other browsers might also work, but you never know until you try.
|
||||||
|
|
||||||
|
foobar2000 1.0 and foo_httpcontrol 0.97.15 or more recent versions
|
||||||
|
are required.
|
||||||
|
|
||||||
|
*** Installation
|
||||||
|
|
||||||
|
Extract archive contents retaining directory structure
|
||||||
|
to %APPDATA%\foobar2000\foo_httpcontrol_data\
|
||||||
|
|
||||||
|
*** Usage
|
||||||
|
|
||||||
|
Open http://127.0.0.1:8888/ajquery/index.html in your browser.
|
||||||
|
(Note that IP address and port is configuration specific and may
|
||||||
|
be different in your case.)
|
||||||
|
|
||||||
|
The interface should be intuitive enough as it is by itself, except:
|
||||||
|
|
||||||
|
1. Double clicking playlist item starts playback.
|
||||||
|
|
||||||
|
2. Single clicking playlist item (maybe combined with shift or ctrl)
|
||||||
|
selects item(s).
|
||||||
|
|
||||||
|
3. Dragging playlist item or selection moves it within the current
|
||||||
|
playlist page.
|
||||||
|
|
||||||
|
4. Playlist slider is working as playlist page switcher, drag its
|
||||||
|
thumb to change page.
|
||||||
|
|
||||||
|
5. A few hotkeys are available (check command buttons tooltips for
|
||||||
|
hotkey values).
|
||||||
|
|
||||||
|
6. Use Shift+PageUp and Shift+PageDown to resize playlist.
|
||||||
|
|
||||||
|
It is recommended to enable "Cursor follows playback" option in
|
||||||
|
foobar2000 Playback menu for more convenient playlists browsing.
|
||||||
|
|
||||||
|
You are free to change template parameters by editing ajquery/config
|
||||||
|
file. For example, playlist_items_per_page variable is useful when you
|
||||||
|
want to permanently modify playlist page size.
|
||||||
|
|
||||||
|
*** Release history 2014
|
||||||
|
|
||||||
|
26 Jul 0.72
|
||||||
|
fix: broken media library search;
|
||||||
|
add: autofocus input on search window open;
|
||||||
|
|
||||||
|
02 Mar 0.71
|
||||||
|
add: Second precision seeking (instead of percent), requires
|
||||||
|
foo_httpcontrol 0.97.15;
|
||||||
|
fix: updated to latest jQuery;
|
||||||
|
|
||||||
|
02 Mar 0.70
|
||||||
|
fix: Wrong handling of parent button in file browser;
|
||||||
|
fix: Playback order drop down-box didn't reflect the actual order;
|
||||||
|
|
||||||
|
*** Release history 2012
|
||||||
|
|
||||||
|
10 Nov 0.69
|
||||||
|
fix: added a bit of sanity to file browser dialog: list scroll
|
||||||
|
position is remembered for each visited directory,
|
||||||
|
improved path navigation;
|
||||||
|
fix: added a bit of sanity to search dialog;
|
||||||
|
fix: fixed SAC & SAQ checkboxes behaviour;
|
||||||
|
fix: albumart initialisation;
|
||||||
|
fix: updated jquery & jquery-ui;
|
||||||
|
|
||||||
|
23 Aug 0.68
|
||||||
|
add: playlist page switch buttons;
|
||||||
|
fix: playlist auto width;
|
||||||
|
|
||||||
|
*** Release history 2011
|
||||||
|
|
||||||
|
09 Apr 0.67
|
||||||
|
fix: wrong now playing info when playing first track;
|
||||||
|
add: double clicking playlist switcher focuses now playing item;
|
||||||
|
add: removed search button;
|
||||||
|
|
||||||
|
16 Mar 0.66
|
||||||
|
fix: updated jquery & jquery-ui;
|
||||||
|
fix: updated cover art and favicon to match current fb2k theme;
|
||||||
|
fix: seekbar popup vertical position made constant;
|
||||||
|
|
||||||
|
27 Jan 0.65
|
||||||
|
fix: replaced Shift+[ / Shift+] hotkeys with Shift+PageUp / Shift+PageDown due to international keyboards differences;
|
||||||
|
fix: probably got rid of windows moving along with playlist resize;
|
||||||
|
fix: queue total time / selection total time;
|
||||||
|
|
||||||
|
*** Release history 2010
|
||||||
|
|
||||||
|
03 May 0.64
|
||||||
|
fix: extra formats in file browser grayed out;
|
||||||
|
fix: queue total time;
|
||||||
|
fix: weird behaviour with zero playlists;
|
||||||
|
fix: ctrl/shift+click selection behaviour;
|
||||||
|
17 Apr 0.63
|
||||||
|
add: shift+[ and shift] resizes playlist height;
|
||||||
|
fix: resize playlist width by dragging right side of seekbar;
|
||||||
|
add: show selection total time;
|
||||||
|
add: clicking album title selects whole album;
|
||||||
|
fix: prefomance improvements;
|
||||||
|
|
||||||
|
10 Apr 0.62
|
||||||
|
add: Internet Exploder 8 compatibility;
|
||||||
|
|
||||||
|
30 Mar 0.61
|
||||||
|
fix: some troubles and bugs;
|
||||||
|
|
||||||
|
27 Mar 0.60
|
||||||
|
add: improved playlist drag & drop;
|
||||||
|
add: some fixes and improvements;
|
||||||
|
add: migrated to latest jquery/jquery ui;
|
||||||
|
|
||||||
|
21 Mar 0.59
|
||||||
|
add: numerous usability improvements;
|
||||||
|
|
||||||
|
17 Mar 0.58
|
||||||
|
add: "Browse to..." in browser window;
|
||||||
|
fix: Remove playlist always removed first one;
|
||||||
|
|
||||||
|
15 Mar 0.57
|
||||||
|
add: reworked playlist items operation style (selecting and
|
||||||
|
applying some commands on selection is possible now,
|
||||||
|
along with moving selection within the current
|
||||||
|
playlist page) - vakata, thanks for the inspiration!;
|
||||||
|
add: a few hotkeys (check command buttons tooltip for
|
||||||
|
hotkey values);
|
||||||
|
fix: non-playable files disappeared in browser;
|
||||||
|
fix: excessive size of non-initialized browser window;
|
||||||
|
|
||||||
|
06 Mar 0.56a
|
||||||
|
fix: logarithmic volume control;
|
||||||
|
fix: excessive size of browser window;
|
||||||
|
|
||||||
|
22 Feb 0.56
|
||||||
|
add: logarithmic volume control;
|
||||||
|
add: mute/unmute button;
|
||||||
|
|
||||||
|
23 Jan 0.55
|
||||||
|
fix: incorrect display of xml special chars in page title;
|
||||||
|
fix: fixes and improvements;
|
||||||
|
add: ability to focus on playing item;
|
||||||
|
|
||||||
|
06 Jan 0.54b
|
||||||
|
fix: missing albumart in Firefox;
|
||||||
|
|
||||||
|
06 Jan 0.54a
|
||||||
|
fix: replaced [HELPERN] with [HELPERNX];
|
||||||
|
add: foo_httpcontrol 0.96.3 or newer is required;
|
||||||
|
|
||||||
|
05 Jan 0.54
|
||||||
|
fix: data retrieval timeouts;
|
||||||
|
add: right mouse button click brings up playlist/playlist items popup menus in Chrome/Firefox etc;
|
||||||
|
add: remembering windows position, size and state between sessions (browser cookies must be enabled);
|
||||||
|
|
||||||
|
*** Release history 2009
|
||||||
|
|
||||||
|
29 Dec 0.53
|
||||||
|
fix: various fixes and improvements;
|
||||||
|
add: proper playlist undo/redo support;
|
||||||
|
|
||||||
|
01 Nov 0.52
|
||||||
|
fix: various fixes;
|
||||||
|
|
||||||
|
14 Sep 0.51
|
||||||
|
add: queue album to playlist popup menu;
|
||||||
|
add: flush queue and queue random to playlists popup menu;
|
||||||
|
add: auto install feature;
|
||||||
|
|
||||||
|
06 Sep 0.5
|
||||||
|
fix: progressbar behaviour in paused state;
|
||||||
|
add: resizeable album art;
|
||||||
|
|
||||||
|
03 Sep 0.4
|
||||||
|
fix: couldn't perform action on 1st track;
|
||||||
|
|
||||||
|
02 Sep 0.3
|
||||||
|
add: usability improvements;
|
||||||
|
add: debug info on ajax failure;
|
||||||
|
|
||||||
|
01 Sep 0.2
|
||||||
|
add: playlist operations menu, ctrl+lmb on playlist tab name;
|
||||||
|
fix: various fixes;
|
||||||
|
|
||||||
|
30 Aug 0.1 Initial release;
|
||||||
22
default/config
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
; default template configuration file
|
||||||
|
;
|
||||||
|
[foo_httpcontrol]
|
||||||
|
url=/
|
||||||
|
; defines formatting of a playlist row using foobar2000 titleformatting.
|
||||||
|
playlist_row=<td class="p">[%album artist% ]['['%album%[ CD%discnumber%][ #%tracknumber%]']' ]%title%[ '//' %track artist%]</td><td class="t">%length%</td>[<td class="q">%queue_indexes%</td>]
|
||||||
|
; defines formatting of a helper macros using foobar2000 titleformatting.
|
||||||
|
helper1=[%album artist% ]['['%album%[ CD%discnumber%][ #%tracknumber%]']' ]%title%[ '//' %track artist%]
|
||||||
|
helper2=[%title% - ]
|
||||||
|
helper3=%codec% %bitrate%kbps %samplerate%Hz %channels%
|
||||||
|
; specifies wildcards where we should look for albumart files, separated by |. foobar2000 titleformatting is available there as well.
|
||||||
|
albumart=$directory_path(%path%)\folder.jpg|$directory_path(%path%)\*.jpg
|
||||||
|
; specifies path of a picture to show when albumart is not found.
|
||||||
|
albumart_not_found=default/icon1rx.png
|
||||||
|
; specifies path of a picture to show when albumart is requested but not currently available (no playing track).
|
||||||
|
albumart_not_available=default/icon1rx.png
|
||||||
|
; limits maximum albumart size to download, in bytes.
|
||||||
|
albumart_limit_size=0
|
||||||
|
; setting to 1 prefers embedded albumart over external.
|
||||||
|
albumart_prefer_embedded=0
|
||||||
|
; controls size of a playlist 'page'. setting to 0 completely disables playlist generation.
|
||||||
|
playlist_items_per_page=30
|
||||||
BIN
default/favicon.ico
Executable file
|
After Width: | Height: | Size: 9.4 KiB |
39
default/foo_httpcontrol_browser_tpl.html
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html><head><title>browser - foo_httpcontrol</title>
|
||||||
|
<style type="text/css">
|
||||||
|
<!--
|
||||||
|
input { height:25px; width:30px; background-color:#DEDEDE; color:#000000; margin-right:5px;}
|
||||||
|
body { background-color:#FFFFFF; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px}
|
||||||
|
.frm { margin: 0px; padding: 0px; }
|
||||||
|
.dir { font-weight: bold; }
|
||||||
|
table { width: 100%; }
|
||||||
|
table td { font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; padding: 3px; color: #999999; }
|
||||||
|
tr.odd td { background-color: #fafafa; }
|
||||||
|
tr.even td { background-color: #ffffff; }
|
||||||
|
tr.rodd td { background-color: #fafafa; color: #000000; }
|
||||||
|
tr.reven td { background-color: #ffffff; color: #000000;}
|
||||||
|
td.c1 { width: 66%; }
|
||||||
|
td.c2 { text-align: right; white-space: nowrap; width: 12%; padding-right: 5px; }
|
||||||
|
td.c3 { text-align: left; white-space: nowrap; width: 5%; padding-left: 5px; padding-right: 10px;}
|
||||||
|
td.c4 { text-align: right; white-space: nowrap; width: 10%; }
|
||||||
|
a { color: #333333; text-decoration: underline; }
|
||||||
|
a:hover { text-decoration: underline; color: #d00000; }
|
||||||
|
select { background-color: #ffffff; }
|
||||||
|
form { margin-top: 15px; }
|
||||||
|
-->
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="/default/" method="get" name="cmd_form" target="_self" class="frm">
|
||||||
|
[ <a href="/default/">Player...</a> ]
|
||||||
|
|
||||||
|
Enqueue: [ <a title="Enqueue current directory files only" href="/default/?cmd=Browse&param1=[PATH]&param2=EnqueueDir">Dir</a> <a title="Enqueue current directory including subdirectories" href="/default/?cmd=Browse&param1=[PATH]&param2=EnqueueDirSubdirs">Dir+subdirs</a> ]
|
||||||
|
<input name="cmd" type="hidden" value="Browse">
|
||||||
|
<input name="param1" type="hidden" value="">
|
||||||
|
<input name="param2" type="hidden" value="">
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
[BROWSER]
|
||||||
|
<!--[PGT] ms-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
241
default/foo_httpcontrol_controls_tpl.html
Executable file
@@ -0,0 +1,241 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html><head><title>[HELPER2X]foobar2000</title>
|
||||||
|
<link rel="shortcut Icon" href="/default/favicon.ico" type="image/x-icon" />
|
||||||
|
<script language="JavaScript" type="text/javascript">
|
||||||
|
<!--
|
||||||
|
var mouseX = 0;
|
||||||
|
var p_key = 0;
|
||||||
|
var act = 0;
|
||||||
|
|
||||||
|
function KeyPress(e) {
|
||||||
|
p_key = e;
|
||||||
|
if (p_key == 16) // shift -- focus
|
||||||
|
act = 3;
|
||||||
|
else if (p_key == 17) // ctrl -- remove
|
||||||
|
act = 4;
|
||||||
|
else if (p_key == 81) // q -- enqueue
|
||||||
|
act = 1;
|
||||||
|
else if (p_key == 87) // w -- dequeue
|
||||||
|
act = 2;
|
||||||
|
else
|
||||||
|
act = 0;
|
||||||
|
document.getElementById('Actions').selectedIndex = act;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pad(str, chr, count) {
|
||||||
|
var str_out = str.toString();
|
||||||
|
while (str_out.length < count)
|
||||||
|
str_out = chr + str_out;
|
||||||
|
return str_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pc(c, p) {
|
||||||
|
var com = c || ''; var par = p || '';
|
||||||
|
with (document.cmd_form)
|
||||||
|
{
|
||||||
|
cmd.value = com;
|
||||||
|
param1.value = par;
|
||||||
|
submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_time(time) {
|
||||||
|
mins = Math.floor(time / 60);
|
||||||
|
secs = pad(time % 60, '0', 2);
|
||||||
|
return mins+":"+secs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_t_pos(time) {
|
||||||
|
var str = format_time(time) + " / ";
|
||||||
|
document.getElementById("t_time").innerHTML = str + ( [ITEM_PLAYING_LEN] > 0 ? format_time([ITEM_PLAYING_LEN]) : '?' );
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_np_width(t_sec, t_length) {
|
||||||
|
var np_width = document.getElementById("npd").offsetWidth;
|
||||||
|
np_width = np_width < 100 ? 100: np_width;
|
||||||
|
document.getElementById('np').style.width=Math.floor(np_width * t_sec / t_length) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
function t_playback_timer(t_sec, t_length) {
|
||||||
|
if (t_sec <= t_length && t_length != 0)
|
||||||
|
{
|
||||||
|
set_t_pos(t_sec);
|
||||||
|
if (t_length != 0)
|
||||||
|
set_np_width(t_sec, t_length);
|
||||||
|
setTimeout('t_playback_timer('+(t_sec+1)+','+t_length+')',1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function a(track) { // do a(ction) on clicked entry
|
||||||
|
if (act == 0) pc('Start', track);
|
||||||
|
else if (act == 1) pc('QueueItems', track);
|
||||||
|
else if (act == 2) pc('DequeueItems', track);
|
||||||
|
else if (act == 3) pc('SetFocus', track);
|
||||||
|
else if (act == 4) pc('Del', track);
|
||||||
|
}
|
||||||
|
|
||||||
|
function np_onclick() {
|
||||||
|
with (document)
|
||||||
|
pc('Seek', Math.round((mouseX-getElementById("np").offsetLeft)*100 / (getElementById("npd").offsetWidth)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouse_capture_init() {
|
||||||
|
if (document.layers? true : false)
|
||||||
|
captureEvents(Event.MOUSEMOVE)
|
||||||
|
document.onmousemove = handleMouseMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseMove(evt) {
|
||||||
|
if (evt)
|
||||||
|
mouseX=evt.clientX;
|
||||||
|
else
|
||||||
|
if (event)
|
||||||
|
mouseX=event.x;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fit() {
|
||||||
|
with (document.getElementById('playlist'))
|
||||||
|
{
|
||||||
|
style.position = 'static'; // important for the onresize event
|
||||||
|
style.overflowY = 'auto';
|
||||||
|
style.top = offsetTop + 'px';
|
||||||
|
style.left = offsetLeft + 'px';
|
||||||
|
style.right = offsetLeft + 'px';
|
||||||
|
style.bottom = '8px'; // fit this to your taste
|
||||||
|
style.position = 'fixed';
|
||||||
|
|
||||||
|
var npelem = document.getElementById("nowplaying");
|
||||||
|
if (npelem)
|
||||||
|
{
|
||||||
|
scrolltop = npelem.offsetTop - offsetHeight/2;
|
||||||
|
|
||||||
|
if (scrolltop > 0)
|
||||||
|
scrollTop = scrolltop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onkeydown = function(evt) { KeyPress(evt?evt.keyCode:event.keyCode); }
|
||||||
|
//--></script><style type="text/css">
|
||||||
|
<!--
|
||||||
|
body { background-color:#ffffff; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; }
|
||||||
|
input { width:30px; background-color:#F0F0F0; color:#000000; margin: 0; border: 1px solid #B0B0B0; padding: 1; }
|
||||||
|
select { background-color:#F0F0F0; color:#000000; border: 1px solid #B0B0B0; padding: 1;}
|
||||||
|
.sac { background-color:#ffffff; margin-right: 0px; width:auto; height: auto;}
|
||||||
|
.frm { margin: 0px; padding: 0px; }
|
||||||
|
table td { font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; padding: 3px;}
|
||||||
|
tr.npr td { background-color: #eaeaea; border-top: 1px solid #eaeaea; }
|
||||||
|
.playlist_time { border-top: 1px solid #000000; text-align: right; }
|
||||||
|
/* playlist entries highlight */
|
||||||
|
tr.o td { background-color: #fafafa; } /* o(dd) */
|
||||||
|
tr.e td { background-color: #ffffff; } /* e(ven) */
|
||||||
|
tr.prev td { border: 1px solid #bbbbbb;} /* prev(iously played) */
|
||||||
|
tr.focus td { border: 1px solid #000000; } /* focus(ed) */
|
||||||
|
tr.queue td { background-color: #e1eaff; } /* queue(d) #ecebff */
|
||||||
|
td.t { text-align: right; } /* t(otal time) */
|
||||||
|
td.q { text-align: right; } /* q(ueue order) */
|
||||||
|
/* now playing line */
|
||||||
|
.npc { position:absolute; left:auto; width:0px; top:auto; margin-top: -5px; opacity:.50; background-color: #aaaaaa; z-index: -1; }
|
||||||
|
.track { padding: 5px; font-size: 12px;}
|
||||||
|
a, a.current, a.current:hover { color: #333333; }
|
||||||
|
a:hover { text-decoration: underline; color: #d00000; }
|
||||||
|
form { margin-top: 15px; }
|
||||||
|
-->
|
||||||
|
</style></head><body onload="mouse_capture_init(); fit();" onresize="fit();">
|
||||||
|
<form action="/default/" method="get" name="cmd_form" target="_self" class="frm">
|
||||||
|
<div>
|
||||||
|
<span style="float: right; margin-bottom: 8px;"><a href="javascript:pc();"><img src="[ALBUMART]" width="180px"></a></span>
|
||||||
|
<input name="Stop" title="Stop playback" type="button" value="#" onclick="pc(this.name);">
|
||||||
|
<input name="PlayOrPause" title="Pause/resume playback" type="button" value="||" onclick="pc(this.name);">
|
||||||
|
<input name="Start" title="Start playback" type="button" value="|>" onclick="pc(this.name);">
|
||||||
|
<input name="StartPrevious" title="Play previous track" type="button" value="||<" onclick="pc(this.name);">
|
||||||
|
<input name="StartNext" title="Play next track" type="button" value=">||" onclick="pc(this.name);">
|
||||||
|
<input name="StartRandom" title="Play random track" type="button" value="|>?" onclick="pc(this.name);">
|
||||||
|
<select title="Playback order" onchange="pc('PlaybackOrder',this.value);">[PLAYBACK_ORDER_OPTION]</select>
|
||||||
|
<select title="Volume level" onchange="pc('Volume',this.value);">[VOLUME_OPTION]</select>%
|
||||||
|
<p>
|
||||||
|
<input title="Stop after current" type="checkbox" class="sac" [SAC] onclick="pc('SAC',this.checked?'1':'0');"><span style="font-size: 12px">SAC</span>
|
||||||
|
<input title="Stop after queue" type="checkbox" class="sac" [SAQ] onclick="pc('SAQ',this.checked?'1':'0');"><span style="font-size: 12px">SAQ</span>
|
||||||
|
<input name="QueueAlbum" title="Queue album" type="button" value="QA" onclick="pc(this.name);">
|
||||||
|
<input name="QueueRandomItems" title="Queue random items" type="button" value="QR" onclick="n = prompt('How many items to queue?'); a = n != null? pc(this.name, n) : false;">
|
||||||
|
<select title="Playlist actions" id="Actions" style="background-color: #eeeeee;" onchange="act=this.selectedIndex;"><option>Start</option><option>Enqueue</option><option>Dequeue</option><option>Focus</option><option>Delete</option></select>
|
||||||
|
<input name="EmptyPlaylist" title="Empty playlist" type="button" value="—" onclick="if (confirm('Empty active playlist?')) pc(this.name); else return false;">
|
||||||
|
<select title="Playlists" onchange="pc('SwitchPlaylist',this.value);">[PLAYLISTS_OPTION]</select>
|
||||||
|
<a href="/default/?cmd=Browse">[ ... ]</a>
|
||||||
|
</p>
|
||||||
|
<p><input type="text" size="9" style="width: auto" onkeypress="document.cmd_form.cmd.value='SearchMediaLibrary'; document.cmd_form.param1.value=this.value;" value="[SEARCH_REQUEST]">
|
||||||
|
<input name="QueryRetrace" title="Retrace/init query" type="button" value=" < " onclick="pc(this.name);">
|
||||||
|
<select title="Media library query" id="QueryAdvance" onchange="pc('QueryAdvance',this.value);">[QUERY_OPTION]</select> [QUERY_INFO]</p>
|
||||||
|
<br><p id="npstr"><span id="npd" style="white-space: nowrap;" onclick="np_onclick();"><span id="np" class="npc"> </span><span id="track_title" class="track">[HELPER1X]</span> <span id="t_time" class="track"></span></span> </p>
|
||||||
|
<p><span id="status"></span> <font size="-2" color="#ababab">[HELPER3X]</font></p>
|
||||||
|
</div>
|
||||||
|
<input name="cmd" type="hidden" value=""><input name="param1" type="hidden" value="">
|
||||||
|
<script language="JavaScript" type="text/javascript">
|
||||||
|
<!--
|
||||||
|
with (document)
|
||||||
|
{
|
||||||
|
act = [LAST_ACTION];
|
||||||
|
getElementById('Actions').selectedIndex = act;
|
||||||
|
var i_p;
|
||||||
|
if ('[PLAYLIST_ITEM_PLAYING]' != '?')
|
||||||
|
i_p = parseInt('[PLAYLIST_ITEM_PLAYING]') + 1;
|
||||||
|
else
|
||||||
|
i_p = '?';
|
||||||
|
|
||||||
|
if ([IS_PLAYING]) { // start progressbar if playing
|
||||||
|
t_playback_timer([ITEM_PLAYING_POS],[ITEM_PLAYING_LEN]);
|
||||||
|
|
||||||
|
if (([ITEM_PLAYING_LEN]>0) && ([ITEM_PLAYING_POS] < [ITEM_PLAYING_LEN]) )
|
||||||
|
setTimeout('pc()',([ITEM_PLAYING_LEN]-[ITEM_PLAYING_POS])*1000 + 500);
|
||||||
|
else
|
||||||
|
if (([ITEM_PLAYING_POS] > [ITEM_PLAYING_LEN]) )
|
||||||
|
setTimeout('pc("RefreshPlayingInfo")',15000);
|
||||||
|
else
|
||||||
|
if ('[ITEM_PLAYING_LEN]' == '[ITEM_PLAYING_POS]' && '[ITEM_PLAYING_LEN]' != '?' && '[ITEM_PLAYING_LEN]' != '0')
|
||||||
|
setTimeout('pc()',500);
|
||||||
|
|
||||||
|
getElementById('status').innerHTML = '[ Playing ' + i_p + ' / [PLAYLIST_PLAYING_ITEMS_COUNT] ]';
|
||||||
|
}
|
||||||
|
else if ([IS_PAUSED]) { // adjust progressbar width if paused
|
||||||
|
set_np_width([ITEM_PLAYING_POS], [ITEM_PLAYING_LEN]);
|
||||||
|
set_t_pos([ITEM_PLAYING_POS]);
|
||||||
|
getElementById('status').innerHTML = '[ Paused ' + i_p + ' / [PLAYLIST_PLAYING_ITEMS_COUNT] ]';
|
||||||
|
} else { // hide unnecessary track info if stopped
|
||||||
|
counter = getElementById("counter");
|
||||||
|
if (counter)
|
||||||
|
counter.innerHTML = "";
|
||||||
|
getElementById("status").innerHTML = "[ Stopped ]";
|
||||||
|
getElementById("npstr").style.visibility = "hidden";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([IS_ENQUEUEING] ) {
|
||||||
|
getElementById('status').innerHTML = '[ Enqueuement in progress ] ' + getElementById('status').innerHTML;
|
||||||
|
setTimeout('pc()',5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
track = getElementById("track_title");
|
||||||
|
|
||||||
|
if (track && track.innerHTML == '' && ([IS_PLAYING] || [IS_PAUSED]) ) // if playing but track info is not loaded yet, reload page
|
||||||
|
setTimeout('pc()',500);
|
||||||
|
|
||||||
|
npp = getElementById("np"); // adjust progressbar width and height, and opacity hack for IE6
|
||||||
|
if (npp)
|
||||||
|
with (npp.style) {
|
||||||
|
if (getElementById("np").offsetHeight >= 2 )
|
||||||
|
height=getElementById("np").offsetHeight*2-2+"px";
|
||||||
|
left=getElementById("npd").offsetLeft+"px";
|
||||||
|
filter = "alpha(opacity=50)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//--></script>
|
||||||
|
<p>[PLAYLIST_PAGES]</p>
|
||||||
|
<div id="playlist" style="border-top: 1px solid #b0b0b0; clear: both; z-index: +1; ">
|
||||||
|
<table id="pl">
|
||||||
|
[PLAYLIST]
|
||||||
|
<tr><td id="totals"></td><td class="playlist_time">[PLAYLIST_TOTAL_TIME]</td><td class="playlist_time">[QUEUE_TOTAL_TIME]</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[PGT]s-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
default/icon1rx.png
Executable file
|
After Width: | Height: | Size: 27 KiB |
BIN
default/nocover.jpg
Executable file
|
After Width: | Height: | Size: 5.4 KiB |
40
default/readme.txt
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
default braindead foo_httpcontrol template
|
||||||
|
1.1 26 Jun 2011 piercemind@gmail.com http://code.google.com/p/foo-httpcontrol/
|
||||||
|
|
||||||
|
*** Requirements
|
||||||
|
|
||||||
|
This simplistic template is developed to be running on pretty much every
|
||||||
|
javascript capable browser out there.
|
||||||
|
|
||||||
|
foobar2000 1.0 and foo_httpcontrol 0.97.7 or more recent versions
|
||||||
|
are required.
|
||||||
|
|
||||||
|
*** Installation
|
||||||
|
|
||||||
|
Extract archive contents retaining directory structure
|
||||||
|
to %APPDATA%\foobar2000\foo_httpcontrol_data\default\ if foobar200 is installed
|
||||||
|
in standard mode, or to path_too_foobar2000_folder\foo_httpcontrol_data\default\
|
||||||
|
if foobar2000 is installed in portable mode.
|
||||||
|
|
||||||
|
*** Usage
|
||||||
|
|
||||||
|
Open http://127.0.0.1:8888/default/ in your browser.
|
||||||
|
(Note that IP address and port is component configuration specific
|
||||||
|
and may be different in your case).
|
||||||
|
|
||||||
|
The interface should be intuitive enough as it is by itself.
|
||||||
|
|
||||||
|
It is recommended to enable "Cursor follows playback" option in
|
||||||
|
foobar2000 Playback menu for more convenient playlists browsing.
|
||||||
|
|
||||||
|
You are free to change template parameters by editing default/config
|
||||||
|
file. For example, playlist_items_per_page variable is useful when you
|
||||||
|
want to modify playlist page size.
|
||||||
|
|
||||||
|
*** Release history 2011
|
||||||
|
|
||||||
|
26 Jun 1.1
|
||||||
|
removed obsolete "Empty Playlist" button from file browser;
|
||||||
|
|
||||||
|
07 Mar 1.0
|
||||||
|
Initial release;
|
||||||
193
foo_httpcontrol/foo_httpcontrol.sln
Executable file
@@ -0,0 +1,193 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||||
|
# Visual C++ Express 2010
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foo_httpcontrol", "foo_httpcontrol.vcxproj", "{D57DDC76-A441-4933-9820-72C32F01AF95}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E} = {622E8B19-8109-4717-BD4D-9657AA78363E}
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D} = {E8091321-D79D-4575-86EF-064EA1A4A20D}
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8} = {7020DA42-3C98-4B37-89D2-683B32EE2DB8}
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F} = {EE47764E-A202-4F85-A767-ABDAB4AFF35F}
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C} = {EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} = {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081} = {71AD2674-065B-48F5-B8B0-E1F9D3892081}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_SDK", "lib\foobar2000\SDK\foobar2000_SDK.vcxproj", "{E8091321-D79D-4575-86EF-064EA1A4A20D}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_ATL_helpers", "lib\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj", "{622E8B19-8109-4717-BD4D-9657AA78363E}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_component_client", "lib\foobar2000\foobar2000_component_client\foobar2000_component_client.vcxproj", "{71AD2674-065B-48F5-B8B0-E1F9D3892081}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "foobar2000_sdk_helpers", "lib\foobar2000\helpers\foobar2000_sdk_helpers.vcxproj", "{EE47764E-A202-4F85-A767-ABDAB4AFF35F}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pfc", "lib\pfc\pfc.vcxproj", "{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "lib\jnetlib\jnetlib.vcxproj", "{7020DA42-3C98-4B37-89D2-683B32EE2DB8}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "lib\zlib\contrib\vstudio\vc10\zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Itanium = Debug|Itanium
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Itanium = Release|Itanium
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release-speed|Itanium = Release-speed|Itanium
|
||||||
|
Release-speed|Win32 = Release-speed|Win32
|
||||||
|
Release-speed|x64 = Release-speed|x64
|
||||||
|
ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium
|
||||||
|
ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32
|
||||||
|
ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Debug|Itanium.ActiveCfg = Debug|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Debug|x64.ActiveCfg = Debug|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release|Itanium.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release|x64.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release-speed|Itanium.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release-speed|Win32.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release-speed|Win32.Build.0 = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.Release-speed|x64.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.ReleaseWithoutAsm|Win32.Build.0 = Release|Win32
|
||||||
|
{D57DDC76-A441-4933-9820-72C32F01AF95}.ReleaseWithoutAsm|x64.ActiveCfg = Release|Win32
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|Itanium.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release-speed|Itanium.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release-speed|Win32.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release-speed|x64.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.Release-speed|x64.Build.0 = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
||||||
|
{E8091321-D79D-4575-86EF-064EA1A4A20D}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|Itanium.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release|x64.Build.0 = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release-speed|Itanium.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release-speed|Win32.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release-speed|x64.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.Release-speed|x64.Build.0 = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
||||||
|
{622E8B19-8109-4717-BD4D-9657AA78363E}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|Itanium.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release|x64.Build.0 = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release-speed|Itanium.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release-speed|Win32.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release-speed|x64.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.Release-speed|x64.Build.0 = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
||||||
|
{71AD2674-065B-48F5-B8B0-E1F9D3892081}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|Itanium.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release|x64.Build.0 = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release-speed|Itanium.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release-speed|Win32.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release-speed|x64.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.Release-speed|x64.Build.0 = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
||||||
|
{EE47764E-A202-4F85-A767-ABDAB4AFF35F}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|Itanium.ActiveCfg = Debug|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|Itanium.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release|x64.Build.0 = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release-speed|Itanium.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release-speed|Win32.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release-speed|x64.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.Release-speed|x64.Build.0 = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64
|
||||||
|
{EBFFFB4E-261D-44D3-B89C-957B31A0BF9C}.ReleaseWithoutAsm|x64.Build.0 = Release|x64
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Debug|Itanium.ActiveCfg = Debug|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Debug|x64.ActiveCfg = Debug|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release|Itanium.ActiveCfg = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release|x64.ActiveCfg = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release-speed|Itanium.ActiveCfg = Release-speed|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release-speed|Win32.ActiveCfg = Release-speed|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release-speed|Win32.Build.0 = Release-speed|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.Release-speed|x64.ActiveCfg = Release-speed|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.ReleaseWithoutAsm|Win32.Build.0 = Release|Win32
|
||||||
|
{7020DA42-3C98-4B37-89D2-683B32EE2DB8}.ReleaseWithoutAsm|x64.ActiveCfg = Release|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = ReleaseWithoutAsm|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = ReleaseWithoutAsm|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release-speed|Itanium.ActiveCfg = Release|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release-speed|Win32.ActiveCfg = Release|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release-speed|x64.ActiveCfg = Release|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release-speed|x64.Build.0 = Release|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64
|
||||||
|
{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
182
foo_httpcontrol/foo_httpcontrol.vcxproj
Executable file
@@ -0,0 +1,182 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{D57DDC76-A441-4933-9820-72C32F01AF95}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>foo_httpcontrol</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<PlatformToolset>v100</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<UseOfAtl>false</UseOfAtl>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<ReferencePath>$(ReferencePath)</ReferencePath>
|
||||||
|
<IncludePath>lib/wtl/include;lib/atlmfc/include;$(IncludePath)</IncludePath>
|
||||||
|
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||||
|
<OutDir>$(SolutionDir)\build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(Configuration)\tmp\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<IncludePath>$(SolutionDir)lib/atlmfc/include;$(SolutionDir)lib/wtl/include;$(IncludePath)</IncludePath>
|
||||||
|
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(SolutionDir)build\$(Configuration)\tmp\</IntDir>
|
||||||
|
<IgnoreImportLibrary>false</IgnoreImportLibrary>
|
||||||
|
<GenerateManifest>false</GenerateManifest>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;FOO_HTTPCONTROL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<IgnoreSpecificDefaultLibraries>atlsd.lib;libcmtd.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<ShowProgress>NotSet</ShowProgress>
|
||||||
|
<AdditionalDependencies>$(SolutionDir)lib/atlmfc/lib/atlsd.lib;$(SolutionDir)lib/foobar2000/shared/shared.lib;shlwapi.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;FOO_HTTPCONTROL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<OmitFramePointers>false</OmitFramePointers>
|
||||||
|
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
|
||||||
|
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<AdditionalDependencies>$(SolutionDir)lib/foobar2000/shared/shared.lib;$(SolutionDir)lib/atlmfc/lib/atls.lib;shlwapi.lib;Ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<Version>0.97.15</Version>
|
||||||
|
<ShowProgress>NotSet</ShowProgress>
|
||||||
|
<ModuleDefinitionFile>
|
||||||
|
</ModuleDefinitionFile>
|
||||||
|
</Link>
|
||||||
|
<ProjectReference>
|
||||||
|
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
|
||||||
|
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="src\foo_httpcontrol_preferences.rc" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\browsefiles.h" />
|
||||||
|
<ClInclude Include="src\config.h" />
|
||||||
|
<ClInclude Include="src\facets.h" />
|
||||||
|
<ClInclude Include="src\httpcontrol.h" />
|
||||||
|
<ClInclude Include="src\httpserver.h" />
|
||||||
|
<ClInclude Include="src\resource.h" />
|
||||||
|
<ClInclude Include="src\state.h" />
|
||||||
|
<ClInclude Include="src\stdafx.h" />
|
||||||
|
<ClInclude Include="src\ui.h" />
|
||||||
|
<ClInclude Include="src\utils.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\browsefiles.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\callbacks.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\commands.cpp" />
|
||||||
|
<ClCompile Include="src\config.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\facets.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\httpcontrol.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\httpserver.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\state.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\stdafx.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ui.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\utils.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Use</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="lib\foobar2000\ATLHelpers\foobar2000_ATL_helpers.vcxproj">
|
||||||
|
<Project>{622e8b19-8109-4717-bd4d-9657aa78363e}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="lib\foobar2000\foobar2000_component_client\foobar2000_component_client.vcxproj">
|
||||||
|
<Project>{71ad2674-065b-48f5-b8b0-e1f9d3892081}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="lib\foobar2000\helpers\foobar2000_sdk_helpers.vcxproj">
|
||||||
|
<Project>{ee47764e-a202-4f85-a767-abdab4aff35f}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="lib\foobar2000\SDK\foobar2000_SDK.vcxproj">
|
||||||
|
<Project>{e8091321-d79d-4575-86ef-064ea1a4a20d}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="lib\jnetlib\jnetlib.vcxproj">
|
||||||
|
<Project>{7020da42-3c98-4b37-89d2-683b32ee2db8}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="lib\pfc\pfc.vcxproj">
|
||||||
|
<Project>{ebfffb4e-261d-44d3-b89c-957b31a0bf9c}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="lib\zlib\contrib\vstudio\vc10\zlibstat.vcxproj">
|
||||||
|
<Project>{745dec58-ebb3-47a9-a9b8-4c6627c01bf8}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
89
foo_httpcontrol/foo_httpcontrol.vcxproj.filters
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Source Files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Resource Files">
|
||||||
|
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||||
|
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="src\foo_httpcontrol_preferences.rc">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</ResourceCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\browsefiles.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\config.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\facets.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\httpcontrol.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\httpserver.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\state.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\stdafx.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\ui.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\utils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\resource.h">
|
||||||
|
<Filter>Resource Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\browsefiles.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\callbacks.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\config.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\facets.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\httpcontrol.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\httpserver.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\state.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\stdafx.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\ui.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\utils.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\commands.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
3
foo_httpcontrol/foo_httpcontrol.vcxproj.user
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
</Project>
|
||||||
76
foo_httpcontrol/lib/jnetlib/README.txt
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
JNetLib Readme.txt
|
||||||
|
/*
|
||||||
|
**
|
||||||
|
** Justin Frankel
|
||||||
|
** www.cockos.com
|
||||||
|
**
|
||||||
|
** Joshua Teitelbaum
|
||||||
|
** www.cryptomail.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
Table of Contents:
|
||||||
|
|
||||||
|
I) License
|
||||||
|
II) Introduction
|
||||||
|
III) Features
|
||||||
|
IV) SSL Integration
|
||||||
|
V) Postamble
|
||||||
|
|
||||||
|
I) License
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution
|
||||||
|
|
||||||
|
II) Introduction
|
||||||
|
|
||||||
|
Welcome to the JNetLib library, a C++ asynchronous network abstraction layer.
|
||||||
|
|
||||||
|
III) Features
|
||||||
|
|
||||||
|
* Works under Linux, FreeBSD, Win32, and other operating systems.
|
||||||
|
* TCP connections support
|
||||||
|
* Listening sockets support
|
||||||
|
* Asynchronous DNS support
|
||||||
|
* HTTP serving and getting support (including basic authentication, GET/POST and HTTP/1.1 support)
|
||||||
|
* Basic HTTPS serving, getting support (including basic authentication, and HTTP/1.1 support)
|
||||||
|
* Completely asynchronous love for single threaded apps.
|
||||||
|
* Coming soon: support for UDP, as well as serial i/o.
|
||||||
|
|
||||||
|
IV) SSL Integration
|
||||||
|
|
||||||
|
JNetLib now employs the OpenSSL encryption library from www.openssl.org.
|
||||||
|
However, it is not compiled in as the default.
|
||||||
|
If you would like to have SSL support compiled in you have to:
|
||||||
|
1) uncomment the #define _JNETLIB_SSL_ 1 in netinc.h
|
||||||
|
2) Obtain the openssl requisite libraries libeay32.lib and ssleay32.lib
|
||||||
|
2a) You can obtain these libraries either by building them yourself via aquring the source yourself or...
|
||||||
|
2b) Download the SSL quickpack for windows, and ensure that you have the SSL quickpack in your build environment
|
||||||
|
You will need the proper include and library paths.
|
||||||
|
If you downloaded the quickpack to C:\, then the appropriate build environment include directory would be "c:\openssl\include", and so forth.
|
||||||
|
|
||||||
|
Disclaimer:
|
||||||
|
SSL functionality is new, and not entirely feature complete.
|
||||||
|
The current certification authentication tactic is to allow all certificates through, without checking any CA signatures.
|
||||||
|
|
||||||
|
|
||||||
|
V) Postamble
|
||||||
|
Questions/Comments
|
||||||
|
joshuat@cryptomail.org
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
262
foo_httpcontrol/lib/jnetlib/asyncdns.cpp
Executable file
@@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: asyncdns.cpp - JNL portable asynchronous DNS implementation
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "asyncdns.h"
|
||||||
|
|
||||||
|
JNL_AsyncDNS::JNL_AsyncDNS(int max_cache_entries)
|
||||||
|
{
|
||||||
|
m_thread_kill=1;
|
||||||
|
m_thread=0;
|
||||||
|
m_cache_size=max_cache_entries;
|
||||||
|
m_cache=(cache_entry *)::malloc(sizeof(cache_entry)*m_cache_size);
|
||||||
|
memset(m_cache,0,sizeof(cache_entry)*m_cache_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_AsyncDNS::~JNL_AsyncDNS()
|
||||||
|
{
|
||||||
|
#ifndef NO_DNS_SUPPORT
|
||||||
|
m_thread_kill=1;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (m_thread)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(m_thread,INFINITE);
|
||||||
|
CloseHandle(m_thread);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (m_thread)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
pthread_join(m_thread,&p);
|
||||||
|
}
|
||||||
|
#endif//!_WIN32
|
||||||
|
#endif//NO_DNS_SUPPORT
|
||||||
|
free(m_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
unsigned long WINAPI JNL_AsyncDNS::_threadfunc(LPVOID _d)
|
||||||
|
#else
|
||||||
|
unsigned int JNL_AsyncDNS::_threadfunc(void *_d)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifndef NO_DNS_SUPPORT
|
||||||
|
int nowinsock=JNL::open_socketlib();
|
||||||
|
JNL_AsyncDNS *_this=(JNL_AsyncDNS*)_d;
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < _this->m_cache_size && !_this->m_thread_kill; x ++)
|
||||||
|
{
|
||||||
|
if (_this->m_cache[x].last_used && !_this->m_cache[x].resolved)
|
||||||
|
{
|
||||||
|
if (!nowinsock)
|
||||||
|
{
|
||||||
|
if (_this->m_cache[x].mode==0)
|
||||||
|
{
|
||||||
|
struct hostent *hostentry;
|
||||||
|
hostentry=::gethostbyname(_this->m_cache[x].hostname);
|
||||||
|
if (hostentry)
|
||||||
|
{
|
||||||
|
_this->m_cache[x].addr=*((int*)hostentry->h_addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_this->m_cache[x].addr=INADDR_NONE;
|
||||||
|
}
|
||||||
|
else if (_this->m_cache[x].mode==1)
|
||||||
|
{
|
||||||
|
struct hostent *ent;
|
||||||
|
ent=::gethostbyaddr((const char *)&_this->m_cache[x].addr,4,AF_INET);
|
||||||
|
if (ent)
|
||||||
|
{
|
||||||
|
strncpy(_this->m_cache[x].hostname,ent->h_name,255);
|
||||||
|
_this->m_cache[x].hostname[255]=0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_this->m_cache[x].hostname[0]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_this->m_cache[x].resolved=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_this->m_cache[x].mode==0)
|
||||||
|
{
|
||||||
|
_this->m_cache[x].addr=INADDR_NONE;
|
||||||
|
_this->m_cache[x].resolved=1;
|
||||||
|
}
|
||||||
|
else if (_this->m_cache[x].mode==1)
|
||||||
|
{
|
||||||
|
_this->m_cache[x].hostname[0]=0;
|
||||||
|
_this->m_cache[x].resolved=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!nowinsock) JNL::close_socketlib();
|
||||||
|
_this->m_thread_kill=1;
|
||||||
|
#endif // NO_DNS_SUPPORT
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_AsyncDNS::resolve(char *hostname, unsigned long *addr)
|
||||||
|
{
|
||||||
|
// return 0 on success, 1 on wait, -1 on unresolvable
|
||||||
|
int x;
|
||||||
|
unsigned long ip=inet_addr(hostname);
|
||||||
|
if (ip != INADDR_NONE)
|
||||||
|
{
|
||||||
|
*addr=ip;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifndef NO_DNS_SUPPORT
|
||||||
|
|
||||||
|
for (x = 0; x < m_cache_size; x ++)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(m_cache[x].hostname,hostname) && m_cache[x].mode==0)
|
||||||
|
{
|
||||||
|
m_cache[x].last_used=time(NULL);
|
||||||
|
if (m_cache[x].resolved)
|
||||||
|
{
|
||||||
|
if (m_cache[x].addr == INADDR_NONE)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct in_addr in;
|
||||||
|
in.s_addr=m_cache[x].addr;
|
||||||
|
*addr=m_cache[x].addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
makesurethreadisrunning();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add to resolve list
|
||||||
|
int oi=-1;
|
||||||
|
for (x = 0; x < m_cache_size; x ++)
|
||||||
|
{
|
||||||
|
if (!m_cache[x].last_used)
|
||||||
|
{
|
||||||
|
oi=x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((oi==-1 || m_cache[x].last_used < m_cache[oi].last_used) && m_cache[x].resolved)
|
||||||
|
{
|
||||||
|
oi=x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oi == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(m_cache[oi].hostname,hostname);
|
||||||
|
m_cache[oi].mode=0;
|
||||||
|
m_cache[oi].addr=INADDR_NONE;
|
||||||
|
m_cache[oi].resolved=0;
|
||||||
|
m_cache[oi].last_used=time(NULL);
|
||||||
|
|
||||||
|
makesurethreadisrunning();
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_AsyncDNS::reverse(unsigned long addr, char *hostname)
|
||||||
|
{
|
||||||
|
// return 0 on success, 1 on wait, -1 on unresolvable
|
||||||
|
int x;
|
||||||
|
if (addr == INADDR_NONE)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifndef NO_DNS_SUPPORT
|
||||||
|
for (x = 0; x < m_cache_size; x ++)
|
||||||
|
{
|
||||||
|
if (m_cache[x].addr==addr && m_cache[x].mode==1)
|
||||||
|
{
|
||||||
|
m_cache[x].last_used=time(NULL);
|
||||||
|
if (m_cache[x].resolved)
|
||||||
|
{
|
||||||
|
if (!m_cache[x].hostname[0])
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(hostname,m_cache[x].hostname,255);
|
||||||
|
hostname[255]=0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
makesurethreadisrunning();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add to resolve list
|
||||||
|
int oi=-1;
|
||||||
|
for (x = 0; x < m_cache_size; x ++)
|
||||||
|
{
|
||||||
|
if (!m_cache[x].last_used)
|
||||||
|
{
|
||||||
|
oi=x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((oi==-1 || m_cache[x].last_used < m_cache[oi].last_used) && m_cache[x].resolved)
|
||||||
|
{
|
||||||
|
oi=x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oi == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
m_cache[oi].addr=addr;
|
||||||
|
m_cache[oi].hostname[0]=0;
|
||||||
|
m_cache[oi].resolved=0;
|
||||||
|
m_cache[oi].mode=1;
|
||||||
|
m_cache[oi].last_used=time(NULL);
|
||||||
|
|
||||||
|
makesurethreadisrunning();
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JNL_AsyncDNS::makesurethreadisrunning(void)
|
||||||
|
{
|
||||||
|
#ifndef NO_DNS_SUPPORT
|
||||||
|
if (m_thread_kill)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (m_thread)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(m_thread,INFINITE);
|
||||||
|
CloseHandle(m_thread);
|
||||||
|
}
|
||||||
|
DWORD id;
|
||||||
|
m_thread_kill=0;
|
||||||
|
m_thread=CreateThread(NULL,0,_threadfunc,(LPVOID)this,0,&id);
|
||||||
|
if (!m_thread)
|
||||||
|
{
|
||||||
|
#else
|
||||||
|
if (m_thread)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
pthread_join(m_thread,&p);
|
||||||
|
}
|
||||||
|
m_thread_kill=0;
|
||||||
|
if (pthread_create(&m_thread,NULL,(void *(*) (void *))_threadfunc,(void*)this) != 0)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
m_thread_kill=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif//NO_DNS_SUPPORT
|
||||||
|
}
|
||||||
55
foo_httpcontrol/lib/jnetlib/asyncdns.h
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: asyncdns.h - JNL portable asynchronous DNS interface
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** Usage:
|
||||||
|
** 1. Create JNL_AsyncDNS object, optionally with the number of cache entries.
|
||||||
|
** 2. call resolve() to resolve a hostname into an address. The return value of
|
||||||
|
** resolve is 0 on success (host successfully resolved), 1 on wait (meaning
|
||||||
|
** try calling resolve() with the same hostname in a few hundred milliseconds
|
||||||
|
** or so), or -1 on error (i.e. the host can't resolve).
|
||||||
|
** 3. call reverse() to do reverse dns (ala resolve()).
|
||||||
|
** 4. enjoy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ASYNCDNS_H_
|
||||||
|
#define _ASYNCDNS_H_
|
||||||
|
|
||||||
|
class JNL_AsyncDNS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JNL_AsyncDNS(int max_cache_entries=64);
|
||||||
|
~JNL_AsyncDNS();
|
||||||
|
|
||||||
|
int resolve(char *hostname, unsigned long *addr); // return 0 on success, 1 on wait, -1 on unresolvable
|
||||||
|
int reverse(unsigned long addr, char *hostname); // return 0 on success, 1 on wait, -1 on unresolvable. hostname must be at least 256 bytes.
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int last_used; // timestamp.
|
||||||
|
char resolved;
|
||||||
|
char mode; // 1=reverse
|
||||||
|
char hostname[256];
|
||||||
|
unsigned long addr;
|
||||||
|
}
|
||||||
|
cache_entry;
|
||||||
|
|
||||||
|
cache_entry *m_cache;
|
||||||
|
int m_cache_size;
|
||||||
|
volatile int m_thread_kill;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE m_thread;
|
||||||
|
static unsigned long WINAPI _threadfunc(LPVOID _d);
|
||||||
|
#else
|
||||||
|
pthread_t m_thread;
|
||||||
|
static unsigned int _threadfunc(void *_d);
|
||||||
|
#endif
|
||||||
|
void makesurethreadisrunning(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_ASYNCDNS_H_
|
||||||
528
foo_httpcontrol/lib/jnetlib/connection.cpp
Executable file
@@ -0,0 +1,528 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: connection.cpp - JNL TCP connection implementation
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
|
||||||
|
JNL_Connection::JNL_Connection(JNL_AsyncDNS *dns, int sendbufsize, int recvbufsize)
|
||||||
|
{
|
||||||
|
m_errorstr="";
|
||||||
|
if (dns == JNL_CONNECTION_AUTODNS)
|
||||||
|
{
|
||||||
|
m_dns=new JNL_AsyncDNS();
|
||||||
|
m_dns_owned=1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dns=dns;
|
||||||
|
m_dns_owned=0;
|
||||||
|
}
|
||||||
|
m_recv_buffer_len=recvbufsize;
|
||||||
|
m_send_buffer_len=sendbufsize;
|
||||||
|
m_recv_buffer=(char*)malloc(m_recv_buffer_len);
|
||||||
|
m_send_buffer=(char*)malloc(m_send_buffer_len);
|
||||||
|
m_socket=INVALID_SOCKET;
|
||||||
|
memset(m_recv_buffer,0,recvbufsize);
|
||||||
|
memset(m_send_buffer,0,sendbufsize);
|
||||||
|
m_remote_port=0;
|
||||||
|
m_state=STATE_NOCONNECTION;
|
||||||
|
m_recv_len=m_recv_pos=0;
|
||||||
|
m_send_len=m_send_pos=0;
|
||||||
|
m_host[0]=0;
|
||||||
|
m_saddr = new struct sockaddr_in;
|
||||||
|
memset(m_saddr,0,sizeof(sockaddr_in));
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_Connection::connect(int s, struct sockaddr_in *loc)
|
||||||
|
{
|
||||||
|
// close(0); //IE9
|
||||||
|
|
||||||
|
m_socket=s;
|
||||||
|
m_remote_port=0;
|
||||||
|
m_dns=NULL;
|
||||||
|
|
||||||
|
if (loc)
|
||||||
|
*m_saddr=*loc;
|
||||||
|
else
|
||||||
|
memset(m_saddr,0,sizeof(sockaddr_in));
|
||||||
|
|
||||||
|
if (m_socket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
// SET_SOCK_BLOCK(m_socket,0); //IE9
|
||||||
|
m_state=STATE_CONNECTED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_errorstr="invalid socket passed to connect";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_Connection::connect(char *hostname, int port)
|
||||||
|
{
|
||||||
|
// close(0); // IE9
|
||||||
|
m_remote_port=(short)port;
|
||||||
|
m_socket=::socket(AF_INET,SOCK_STREAM,0);
|
||||||
|
if (m_socket == INVALID_SOCKET) // ==-1
|
||||||
|
{
|
||||||
|
m_errorstr="creating socket";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SET_SOCK_BLOCK(m_socket,0);
|
||||||
|
strncpy_s(m_host,hostname,sizeof(m_host)-1); // strncpy
|
||||||
|
m_host[sizeof(m_host)-1]=0;
|
||||||
|
memset(m_saddr,0,sizeof(sockaddr_in));
|
||||||
|
if (!m_host[0])
|
||||||
|
{
|
||||||
|
m_errorstr="empty hostname";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_state=STATE_RESOLVING;
|
||||||
|
m_saddr->sin_family=AF_INET;
|
||||||
|
m_saddr->sin_port=htons((unsigned short)port);
|
||||||
|
m_saddr->sin_addr.s_addr=inet_addr(hostname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** socket_shutdown
|
||||||
|
** virtualization for ssl
|
||||||
|
*/
|
||||||
|
/* Virtual */
|
||||||
|
void JNL_Connection::socket_shutdown()
|
||||||
|
{
|
||||||
|
if (m_socket != INVALID_SOCKET) // >= 0
|
||||||
|
{
|
||||||
|
::shutdown(m_socket, SHUT_RDWR);
|
||||||
|
::closesocket(m_socket);
|
||||||
|
m_socket = INVALID_SOCKET; // -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** socket_recv
|
||||||
|
** virtualization for ssl
|
||||||
|
*/
|
||||||
|
/* Virtual */
|
||||||
|
int JNL_Connection::socket_recv(char *buf, int len, int options)
|
||||||
|
{
|
||||||
|
return ::recv(m_socket,buf,len,options);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** socket_send
|
||||||
|
** virtualization for ssl
|
||||||
|
*/
|
||||||
|
/* Virtual */
|
||||||
|
int JNL_Connection::socket_send(char *buf, int len, int options)
|
||||||
|
{
|
||||||
|
return ::send(m_socket,buf,len,options);
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::socket_connect()
|
||||||
|
{
|
||||||
|
return ::connect(m_socket,(struct sockaddr *)m_saddr,16);
|
||||||
|
}
|
||||||
|
JNL_Connection::~JNL_Connection()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** virtualization for ssl, calling socket_shtudown()
|
||||||
|
*/
|
||||||
|
socket_shutdown();
|
||||||
|
|
||||||
|
free(m_recv_buffer);
|
||||||
|
free(m_send_buffer);
|
||||||
|
if (m_dns_owned)
|
||||||
|
{
|
||||||
|
delete m_dns;
|
||||||
|
}
|
||||||
|
delete m_saddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_Connection::run(int max_send_bytes, int max_recv_bytes, int *bytes_sent, int *bytes_rcvd)
|
||||||
|
{
|
||||||
|
int bytes_allowed_to_send=(max_send_bytes<0)?m_send_buffer_len:max_send_bytes;
|
||||||
|
int bytes_allowed_to_recv=(max_recv_bytes<0)?m_recv_buffer_len:max_recv_bytes;
|
||||||
|
|
||||||
|
if (bytes_sent) *bytes_sent=0;
|
||||||
|
if (bytes_rcvd) *bytes_rcvd=0;
|
||||||
|
|
||||||
|
switch (m_state)
|
||||||
|
{
|
||||||
|
case STATE_RESOLVING:
|
||||||
|
if (m_saddr->sin_addr.s_addr == INADDR_NONE)
|
||||||
|
{
|
||||||
|
int a=m_dns?m_dns->resolve(m_host,(unsigned long int *)&m_saddr->sin_addr.s_addr):-1;
|
||||||
|
if (!a) { m_state=STATE_CONNECTING; }
|
||||||
|
else if (a == 1)
|
||||||
|
{
|
||||||
|
m_state=STATE_RESOLVING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_errorstr="resolving hostname";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** virtualization for ssl
|
||||||
|
*/
|
||||||
|
if(!socket_connect())
|
||||||
|
{
|
||||||
|
m_state=STATE_CONNECTED;
|
||||||
|
on_socket_connected();
|
||||||
|
}
|
||||||
|
else if (ERRNO!=EINPROGRESS)
|
||||||
|
{
|
||||||
|
m_errorstr="connecting to host";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
}
|
||||||
|
else { m_state=STATE_CONNECTING; }
|
||||||
|
break;
|
||||||
|
case STATE_CONNECTING:
|
||||||
|
{
|
||||||
|
fd_set f[3];
|
||||||
|
FD_ZERO(&f[0]);
|
||||||
|
FD_ZERO(&f[1]);
|
||||||
|
FD_ZERO(&f[2]);
|
||||||
|
FD_SET(m_socket,&f[0]);
|
||||||
|
FD_SET(m_socket,&f[1]);
|
||||||
|
FD_SET(m_socket,&f[2]);
|
||||||
|
struct timeval tv;
|
||||||
|
memset(&tv,0,sizeof(tv));
|
||||||
|
if (select(m_socket+1,&f[0],&f[1],&f[2],&tv)==-1)
|
||||||
|
{
|
||||||
|
m_errorstr="connecting to host (calling select())";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
}
|
||||||
|
else if (FD_ISSET(m_socket,&f[1]))
|
||||||
|
{
|
||||||
|
m_state=STATE_CONNECTED;
|
||||||
|
on_socket_connected();
|
||||||
|
}
|
||||||
|
else if (FD_ISSET(m_socket,&f[2]))
|
||||||
|
{
|
||||||
|
m_errorstr="connecting to host";
|
||||||
|
m_state=STATE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STATE_CONNECTED:
|
||||||
|
case STATE_CLOSING:
|
||||||
|
if (m_send_len>0 && bytes_allowed_to_send>0)
|
||||||
|
{
|
||||||
|
int len=m_send_buffer_len-m_send_pos;
|
||||||
|
if (len > m_send_len) len=m_send_len;
|
||||||
|
if (len > bytes_allowed_to_send) len=bytes_allowed_to_send;
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
int res=socket_send(m_send_buffer+m_send_pos,len,0);
|
||||||
|
if (res==-1 && ERRNO != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
m_state=STATE_CLOSED; // **!! uncommented
|
||||||
|
return; // IE9
|
||||||
|
}
|
||||||
|
if (res>0)
|
||||||
|
{
|
||||||
|
bytes_allowed_to_send-=res;
|
||||||
|
if (bytes_sent) *bytes_sent+=res;
|
||||||
|
m_send_pos+=res;
|
||||||
|
m_send_len-=res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_send_pos>=m_send_buffer_len)
|
||||||
|
{
|
||||||
|
m_send_pos=0;
|
||||||
|
if (m_send_len>0)
|
||||||
|
{
|
||||||
|
len=m_send_buffer_len-m_send_pos;
|
||||||
|
if (len > m_send_len) len=m_send_len;
|
||||||
|
if (len > bytes_allowed_to_send) len=bytes_allowed_to_send;
|
||||||
|
int res=socket_send(m_send_buffer+m_send_pos,len,0);
|
||||||
|
if (res==-1 && ERRNO != EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
m_state=STATE_CLOSED; // **!! uncommented
|
||||||
|
return; // **!! added IE9
|
||||||
|
}
|
||||||
|
if (res>0)
|
||||||
|
{
|
||||||
|
bytes_allowed_to_send-=res;
|
||||||
|
if (bytes_sent) *bytes_sent+=res;
|
||||||
|
m_send_pos+=res;
|
||||||
|
m_send_len-=res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_recv_len<m_recv_buffer_len)
|
||||||
|
{
|
||||||
|
int len=m_recv_buffer_len-m_recv_pos;
|
||||||
|
if (len > m_recv_buffer_len-m_recv_len) len=m_recv_buffer_len-m_recv_len;
|
||||||
|
if (len > bytes_allowed_to_recv) len=bytes_allowed_to_recv;
|
||||||
|
if (len>0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** virtualization for SSL
|
||||||
|
*/
|
||||||
|
int res = socket_recv(m_recv_buffer+m_recv_pos,len,0);
|
||||||
|
|
||||||
|
if (res == 0 || ((res < 0) && (ERRNO != EWOULDBLOCK) ))
|
||||||
|
{
|
||||||
|
m_state=STATE_CLOSED;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res > 0)
|
||||||
|
{
|
||||||
|
bytes_allowed_to_recv-=res;
|
||||||
|
if (bytes_rcvd) *bytes_rcvd+=res;
|
||||||
|
m_recv_pos+=res;
|
||||||
|
m_recv_len+=res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_recv_pos >= m_recv_buffer_len)
|
||||||
|
{
|
||||||
|
m_recv_pos=0;
|
||||||
|
if (m_recv_len < m_recv_buffer_len)
|
||||||
|
{
|
||||||
|
len=m_recv_buffer_len-m_recv_len;
|
||||||
|
if (len > bytes_allowed_to_recv) len=bytes_allowed_to_recv;
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
int res=socket_recv(m_recv_buffer+m_recv_pos,len,0);
|
||||||
|
if (res == 0 || (res < 0 && ERRNO != EWOULDBLOCK))
|
||||||
|
{
|
||||||
|
m_state=STATE_CLOSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res > 0)
|
||||||
|
{
|
||||||
|
bytes_allowed_to_recv-=res;
|
||||||
|
if (bytes_rcvd) *bytes_rcvd+=res;
|
||||||
|
m_recv_pos+=res;
|
||||||
|
m_recv_len+=res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_state == STATE_CLOSING)
|
||||||
|
{
|
||||||
|
if (m_send_len < 1) m_state = STATE_CLOSED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_Connection::on_socket_connected(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void JNL_Connection::close(int quick)
|
||||||
|
{
|
||||||
|
if (quick || m_state == STATE_RESOLVING || m_state == STATE_CONNECTING)
|
||||||
|
{
|
||||||
|
m_state=STATE_CLOSED;
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** virualization for ssl
|
||||||
|
*/
|
||||||
|
socket_shutdown();
|
||||||
|
|
||||||
|
m_socket = INVALID_SOCKET; // -1
|
||||||
|
memset(m_recv_buffer,0,m_recv_buffer_len);
|
||||||
|
memset(m_send_buffer,0,m_send_buffer_len);
|
||||||
|
m_remote_port=0;
|
||||||
|
m_recv_len=m_recv_pos=0;
|
||||||
|
m_send_len=m_send_pos=0;
|
||||||
|
m_host[0]=0;
|
||||||
|
memset(m_saddr,0,sizeof(sockaddr_in));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_state == STATE_CONNECTED) m_state=STATE_CLOSING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::send_bytes_in_queue(void)
|
||||||
|
{
|
||||||
|
return m_send_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::send_bytes_available(void)
|
||||||
|
{
|
||||||
|
return m_send_buffer_len-m_send_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::send(const void *_data, int length)
|
||||||
|
{
|
||||||
|
const char *data = static_cast<const char *>(_data);
|
||||||
|
if (length > send_bytes_available())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_pos=m_send_pos+m_send_len;
|
||||||
|
if (write_pos >= m_send_buffer_len)
|
||||||
|
{
|
||||||
|
write_pos-=m_send_buffer_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len=m_send_buffer_len-write_pos;
|
||||||
|
if (len > length)
|
||||||
|
{
|
||||||
|
len=length;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(m_send_buffer+write_pos,data,len);
|
||||||
|
if (length > len)
|
||||||
|
{
|
||||||
|
memcpy(m_send_buffer,data+len,length-len);
|
||||||
|
}
|
||||||
|
m_send_len+=length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::send_string(const char *line)
|
||||||
|
{
|
||||||
|
return send(line,strlen(line));
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::recv_bytes_available(void)
|
||||||
|
{
|
||||||
|
return m_recv_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::peek_bytes(void *_data, int maxlength)
|
||||||
|
{
|
||||||
|
char *data = static_cast<char *>(_data);
|
||||||
|
if (maxlength > m_recv_len)
|
||||||
|
{
|
||||||
|
maxlength=m_recv_len;
|
||||||
|
}
|
||||||
|
int read_pos=m_recv_pos-m_recv_len;
|
||||||
|
if (read_pos < 0)
|
||||||
|
{
|
||||||
|
read_pos += m_recv_buffer_len;
|
||||||
|
}
|
||||||
|
int len=m_recv_buffer_len-read_pos;
|
||||||
|
if (len > maxlength)
|
||||||
|
{
|
||||||
|
len=maxlength;
|
||||||
|
}
|
||||||
|
if (data != NULL) {
|
||||||
|
memcpy(data,m_recv_buffer+read_pos,len);
|
||||||
|
if (len < maxlength)
|
||||||
|
{
|
||||||
|
memcpy(data+len,m_recv_buffer,maxlength-len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxlength;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::recv_bytes(void *_data, int maxlength)
|
||||||
|
{
|
||||||
|
char *data = static_cast<char *>(_data);
|
||||||
|
|
||||||
|
int ml=peek_bytes(data,maxlength);
|
||||||
|
m_recv_len-=ml;
|
||||||
|
return ml;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::getbfromrecv(int pos, int remove)
|
||||||
|
{
|
||||||
|
int read_pos=m_recv_pos-m_recv_len + pos;
|
||||||
|
if (pos < 0 || pos > m_recv_len) return -1;
|
||||||
|
if (read_pos < 0)
|
||||||
|
{
|
||||||
|
read_pos += m_recv_buffer_len;
|
||||||
|
}
|
||||||
|
if (read_pos >= m_recv_buffer_len)
|
||||||
|
{
|
||||||
|
read_pos-=m_recv_buffer_len;
|
||||||
|
}
|
||||||
|
if (remove) m_recv_len--;
|
||||||
|
return m_recv_buffer[read_pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::recv_lines_available(void)
|
||||||
|
{
|
||||||
|
int l=recv_bytes_available();
|
||||||
|
int lcount=0;
|
||||||
|
int lastch=0;
|
||||||
|
int pos;
|
||||||
|
for (pos=0; pos < l; pos ++)
|
||||||
|
{
|
||||||
|
int t=getbfromrecv(pos,0);
|
||||||
|
if (t == -1) return lcount;
|
||||||
|
if ((t=='\r' || t=='\n') &&(
|
||||||
|
(lastch != '\r' && lastch != '\n') || lastch==t
|
||||||
|
)) lcount++;
|
||||||
|
lastch=t;
|
||||||
|
}
|
||||||
|
return lcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_Connection::recv_line(char *line, int maxlength)
|
||||||
|
{
|
||||||
|
if (maxlength > m_recv_len) maxlength=m_recv_len;
|
||||||
|
while (maxlength--)
|
||||||
|
{
|
||||||
|
int t=getbfromrecv(0,1);
|
||||||
|
if (t == -1)
|
||||||
|
{
|
||||||
|
*line=0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (t == '\r' || t == '\n')
|
||||||
|
{
|
||||||
|
int r=getbfromrecv(0,0);
|
||||||
|
if ((r == '\r' || r == '\n') && r != t) getbfromrecv(0,1);
|
||||||
|
*line=0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*line++=(char)t;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long JNL_Connection::get_interface(void)
|
||||||
|
{
|
||||||
|
if (m_socket == INVALID_SOCKET) return 0; // -1
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
memset(&sin,0,sizeof(sin));
|
||||||
|
socklen_t len=16;
|
||||||
|
if (::getsockname(m_socket,(struct sockaddr *)&sin,&len)) return 0;
|
||||||
|
return (unsigned long) sin.sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long JNL_Connection::get_remote()
|
||||||
|
{
|
||||||
|
return m_saddr->sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
short JNL_Connection::get_remote_port()
|
||||||
|
{
|
||||||
|
return m_remote_port;
|
||||||
|
}
|
||||||
153
foo_httpcontrol/lib/jnetlib/connection.h
Executable file
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: connection.h - JNL TCP connection interface
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** Usage:
|
||||||
|
** 1. Create a JNL_Connection object, optionally specifying a JNL_AsyncDNS
|
||||||
|
** object to use (or NULL for none, or JNL_CONNECTION_AUTODNS for auto),
|
||||||
|
** and the send and receive buffer sizes.
|
||||||
|
** 2. Call connect() to have it connect to a host/port (the hostname will be
|
||||||
|
** resolved if possible).
|
||||||
|
** 3. call run() with the maximum send/recv amounts, and optionally parameters
|
||||||
|
** so you can tell how much has been send/received. You want to do this a lot, while:
|
||||||
|
** 4. check get_state() to check the state of the connection. The states are:
|
||||||
|
** JNL_Connection::STATE_ERROR
|
||||||
|
** - an error has occured on the connection. the connection has closed,
|
||||||
|
** and you can no longer write to the socket (there still might be
|
||||||
|
** data in the receive buffer - use recv_bytes_available()).
|
||||||
|
** JNL_Connection::STATE_NOCONNECTION
|
||||||
|
** - no connection has been made yet. call connect() already! :)
|
||||||
|
** JNL_Connection::STATE_RESOLVING
|
||||||
|
** - the connection is still waiting for a JNL_AsycnDNS to resolve the
|
||||||
|
** host.
|
||||||
|
** JNL_Connection::STATE_CONNECTING
|
||||||
|
** - the asynchronous call to connect() is still running.
|
||||||
|
** JNL_Connection::STATE_CONNECTED
|
||||||
|
** - the connection has connected, all is well.
|
||||||
|
** JNL_Connection::STATE_CLOSING
|
||||||
|
** - the connection is closing. This happens after a call to close,
|
||||||
|
** without the quick parameter set. This means that the connection
|
||||||
|
** will close once the data in the send buffer is sent (data could
|
||||||
|
** still be being received when it would be closed). After it is
|
||||||
|
** closed, the state will transition to:
|
||||||
|
** JNL_Connection::STATE_CLOSED
|
||||||
|
** - the connection has closed, generally without error. There still
|
||||||
|
** might be data in the receieve buffer, use recv_bytes_available().
|
||||||
|
** 5. Use send() and send_string() to send data. You can use
|
||||||
|
** send_bytes_in_queue() to see how much has yet to go out, or
|
||||||
|
** send_bytes_available() to see how much you can write. If you use send()
|
||||||
|
** or send_string() and not enough room is available, both functions will
|
||||||
|
** return error ( < 0)
|
||||||
|
** 6. Use recv() and recv_line() to get data. If you want to see how much data
|
||||||
|
** there is, use recv_bytes_available() and recv_lines_available(). If you
|
||||||
|
** call recv() and not enough data is available, recv() will return how much
|
||||||
|
** data was actually read. See comments at the function defs.
|
||||||
|
**
|
||||||
|
** 7. To close, call close(1) for a quick close, or close() for a close that will
|
||||||
|
** make the socket close after sending all the data sent.
|
||||||
|
**
|
||||||
|
** 8. delete ye' ol' object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CONNECTION_H_
|
||||||
|
#define _CONNECTION_H_
|
||||||
|
|
||||||
|
#include "asyncdns.h"
|
||||||
|
|
||||||
|
#define JNL_CONNECTION_AUTODNS ((JNL_AsyncDNS*)-1)
|
||||||
|
|
||||||
|
struct sockaddr_in;
|
||||||
|
|
||||||
|
class JNL_Connection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_ERROR,
|
||||||
|
STATE_NOCONNECTION,
|
||||||
|
STATE_RESOLVING,
|
||||||
|
STATE_CONNECTING,
|
||||||
|
STATE_CONNECTED,
|
||||||
|
STATE_CLOSING,
|
||||||
|
STATE_CLOSED
|
||||||
|
} state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum, 1/27/2006 adding virtual
|
||||||
|
*/
|
||||||
|
JNL_Connection(JNL_AsyncDNS *dns=JNL_CONNECTION_AUTODNS, int sendbufsize=8192, int recvbufsize=8192);
|
||||||
|
virtual ~JNL_Connection();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void connect(char *hostname, int port);
|
||||||
|
virtual void connect(int sock, struct sockaddr_in *loc=NULL); // used by the listen object, usually not needed by users.
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 2/2/2006
|
||||||
|
** Need to make this virtual to ensure SSL can init properly
|
||||||
|
*/
|
||||||
|
virtual void run(int max_send_bytes=-1, int max_recv_bytes=-1, int *bytes_sent=NULL, int *bytes_rcvd=NULL);
|
||||||
|
int get_state() { return m_state; }
|
||||||
|
char *get_errstr() { return m_errorstr; }
|
||||||
|
|
||||||
|
void close(int quick=0);
|
||||||
|
void flush_send(void) { m_send_len=m_send_pos=0; }
|
||||||
|
|
||||||
|
int send_bytes_in_queue(void);
|
||||||
|
int send_bytes_available(void);
|
||||||
|
int send(const void *data, int length); // returns -1 if not enough room
|
||||||
|
inline int send_bytes(const void *data, int length) { return send(data, length); }
|
||||||
|
int send_string(const char *line); // returns -1 if not enough room
|
||||||
|
|
||||||
|
|
||||||
|
int recv_bytes_available(void);
|
||||||
|
int recv_bytes(void *data, int maxlength); // returns actual bytes read
|
||||||
|
unsigned int recv_int(void);
|
||||||
|
int recv_lines_available(void);
|
||||||
|
int recv_line(char *line, int maxlength); // returns 0 if the line was terminated with a \r or \n, 1 if not.
|
||||||
|
// (i.e. if you specify maxlength=10, and the line is 12 bytes long
|
||||||
|
// it will return 1. or if there is no \r or \n and that's all the data
|
||||||
|
// the connection has.)
|
||||||
|
int peek_bytes(void *data, int maxlength); // returns bytes peeked
|
||||||
|
|
||||||
|
unsigned long get_interface(void); // this returns the interface the connection is on
|
||||||
|
unsigned long get_remote(void); // remote host ip.
|
||||||
|
short get_remote_port(void); // this returns the remote port of connection
|
||||||
|
|
||||||
|
int m_socket;
|
||||||
|
state m_state;
|
||||||
|
protected:
|
||||||
|
short m_remote_port;
|
||||||
|
char *m_recv_buffer;
|
||||||
|
char *m_send_buffer;
|
||||||
|
int m_recv_buffer_len;
|
||||||
|
int m_send_buffer_len;
|
||||||
|
|
||||||
|
int m_recv_pos;
|
||||||
|
int m_recv_len;
|
||||||
|
int m_send_pos;
|
||||||
|
int m_send_len;
|
||||||
|
|
||||||
|
struct sockaddr_in *m_saddr;
|
||||||
|
char m_host[256];
|
||||||
|
|
||||||
|
JNL_AsyncDNS *m_dns;
|
||||||
|
int m_dns_owned;
|
||||||
|
|
||||||
|
char *m_errorstr;
|
||||||
|
|
||||||
|
int getbfromrecv(int pos, int remove); // used by recv_line*
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006 Adding new BSD socket analogues for SSL compatibility
|
||||||
|
*/
|
||||||
|
virtual void socket_shutdown();
|
||||||
|
virtual int socket_recv(char *buf, int len, int options);
|
||||||
|
virtual int socket_send(char *buf, int len, int options);
|
||||||
|
virtual int socket_connect();
|
||||||
|
virtual void on_socket_connected();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _Connection_H_
|
||||||
492
foo_httpcontrol/lib/jnetlib/httpget.cpp
Executable file
@@ -0,0 +1,492 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: httpget.cpp - JNL HTTP GET implementation
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Undefine this if you don't want SSL compiled in
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "httpget.h"
|
||||||
|
#include "sslconnection.h"
|
||||||
|
|
||||||
|
|
||||||
|
JNL_HTTPGet::JNL_HTTPGet(JNL_AsyncDNS *dns, int recvbufsize, char *proxy)
|
||||||
|
{
|
||||||
|
m_recvbufsize=recvbufsize;
|
||||||
|
m_dns=dns;
|
||||||
|
m_con=NULL;
|
||||||
|
m_http_proxylpinfo=0;
|
||||||
|
m_http_proxyhost=0;
|
||||||
|
m_http_proxyport=0;
|
||||||
|
if (proxy && *proxy)
|
||||||
|
{
|
||||||
|
char *p=(char*)malloc(strlen(proxy)+1);
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
char *r=NULL;
|
||||||
|
strcpy(p,proxy);
|
||||||
|
do_parse_url(p,&m_http_proxyhost,&m_http_proxyport,&r,&m_http_proxylpinfo);
|
||||||
|
free(r);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_sendheaders=NULL;
|
||||||
|
m_http_redir_url=0;
|
||||||
|
reinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_HTTPGet::reinit()
|
||||||
|
{
|
||||||
|
m_errstr=0;
|
||||||
|
m_recvheaders=NULL;
|
||||||
|
m_recvheaders_size=0;
|
||||||
|
m_http_state=0;
|
||||||
|
m_http_port=0;
|
||||||
|
m_http_url=0;
|
||||||
|
m_reply=0;
|
||||||
|
m_http_host=m_http_lpinfo=m_http_request=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_HTTPGet::deinit()
|
||||||
|
{
|
||||||
|
delete m_con; m_con = NULL;
|
||||||
|
free(m_recvheaders);
|
||||||
|
|
||||||
|
free(m_http_url);
|
||||||
|
free(m_http_host);
|
||||||
|
free(m_http_lpinfo);
|
||||||
|
free(m_http_request);
|
||||||
|
free(m_errstr);
|
||||||
|
free(m_reply);
|
||||||
|
reinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_HTTPGet::~JNL_HTTPGet()
|
||||||
|
{
|
||||||
|
deinit();
|
||||||
|
free(m_sendheaders);
|
||||||
|
free(m_http_proxylpinfo);
|
||||||
|
free(m_http_proxyhost);
|
||||||
|
free(m_http_redir_url);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JNL_HTTPGet::addheader(const char *header)
|
||||||
|
{
|
||||||
|
if (strstr(header,"\r") || strstr(header,"\n")) return;
|
||||||
|
if (!m_sendheaders)
|
||||||
|
{
|
||||||
|
m_sendheaders=(char*)malloc(strlen(header)+3);
|
||||||
|
if (m_sendheaders)
|
||||||
|
{
|
||||||
|
strcpy(m_sendheaders,header);
|
||||||
|
strcat(m_sendheaders,"\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *t=(char*)malloc(strlen(header)+strlen(m_sendheaders)+1+2);
|
||||||
|
if (t)
|
||||||
|
{
|
||||||
|
strcpy(t,m_sendheaders);
|
||||||
|
strcat(t,header);
|
||||||
|
strcat(t,"\r\n");
|
||||||
|
free(m_sendheaders);
|
||||||
|
m_sendheaders=t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_HTTPGet::do_encode_mimestr(char *in, char *out)
|
||||||
|
{
|
||||||
|
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
int shift = 0;
|
||||||
|
int accum = 0;
|
||||||
|
|
||||||
|
while (*in)
|
||||||
|
{
|
||||||
|
if (*in)
|
||||||
|
{
|
||||||
|
accum <<= 8;
|
||||||
|
shift += 8;
|
||||||
|
accum |= *in++;
|
||||||
|
}
|
||||||
|
while ( shift >= 6 )
|
||||||
|
{
|
||||||
|
shift -= 6;
|
||||||
|
*out++ = alphabet[(accum >> shift) & 0x3F];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shift == 4)
|
||||||
|
{
|
||||||
|
*out++ = alphabet[(accum & 0xF)<<2];
|
||||||
|
*out++='=';
|
||||||
|
}
|
||||||
|
else if (shift == 2)
|
||||||
|
{
|
||||||
|
*out++ = alphabet[(accum & 0x3)<<4];
|
||||||
|
*out++='=';
|
||||||
|
*out++='=';
|
||||||
|
}
|
||||||
|
|
||||||
|
*out++=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JNL_HTTPGet::connect(const char *url, int ver, char *requestmethod)
|
||||||
|
{
|
||||||
|
deinit();
|
||||||
|
m_http_url=(char*)malloc(strlen(url)+1);
|
||||||
|
strcpy(m_http_url,url);
|
||||||
|
do_parse_url(m_http_url,&m_http_host,&m_http_port,&m_http_request, &m_http_lpinfo);
|
||||||
|
strcpy(m_http_url,url);
|
||||||
|
if (!m_http_host || !m_http_host[0] || !m_http_port)
|
||||||
|
{
|
||||||
|
m_http_state=-1;
|
||||||
|
seterrstr("invalid URL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sendbufferlen=0;
|
||||||
|
|
||||||
|
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
||||||
|
{
|
||||||
|
sendbufferlen += strlen(requestmethod)+1 /* GET */ + strlen(m_http_request) + 9 /* HTTP/1.0 */ + 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sendbufferlen += strlen(requestmethod)+1 /* GET */ + strlen(m_http_url) + 9 /* HTTP/1.0 */ + 2;
|
||||||
|
if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
|
||||||
|
{
|
||||||
|
sendbufferlen+=58+strlen(m_http_proxylpinfo)*2; // being safe here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendbufferlen += 5 /* Host: */ + strlen(m_http_host) + 2;
|
||||||
|
|
||||||
|
if (m_http_lpinfo&&m_http_lpinfo[0])
|
||||||
|
{
|
||||||
|
sendbufferlen+=46+strlen(m_http_lpinfo)*2; // being safe here
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_sendheaders) sendbufferlen+=strlen(m_sendheaders);
|
||||||
|
|
||||||
|
char *str=(char*)malloc(sendbufferlen+1024);
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
seterrstr("error allocating memory");
|
||||||
|
m_http_state=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
||||||
|
{
|
||||||
|
wsprintf(str,"%s %s HTTP/1.%d\r\n",requestmethod,m_http_request,ver%10);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wsprintf(str,"%s %s HTTP/1.%d\r\n",requestmethod, m_http_url,ver%10);
|
||||||
|
}
|
||||||
|
|
||||||
|
wsprintf(str+strlen(str),"Host:%s\r\n",m_http_host);
|
||||||
|
|
||||||
|
if (m_http_lpinfo&&m_http_lpinfo[0])
|
||||||
|
{
|
||||||
|
strcat(str,"Authorization: Basic ");
|
||||||
|
do_encode_mimestr(m_http_lpinfo,str+strlen(str));
|
||||||
|
strcat(str,"\r\n");
|
||||||
|
}
|
||||||
|
if (m_http_proxylpinfo&&m_http_proxylpinfo[0])
|
||||||
|
{
|
||||||
|
strcat(str,"Proxy-Authorization: Basic ");
|
||||||
|
do_encode_mimestr(m_http_proxylpinfo,str+strlen(str));
|
||||||
|
strcat(str,"\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_sendheaders) strcat(str,m_sendheaders);
|
||||||
|
strcat(str,"\r\n");
|
||||||
|
|
||||||
|
int a=m_recvbufsize;
|
||||||
|
if (a < 4096) a=4096;
|
||||||
|
//m_con=new JNL_Connection(m_dns,strlen(str)+4,a);
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum delta 1/15/2006
|
||||||
|
*/
|
||||||
|
#ifdef _JNETLIB_SSL_
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** Check for secure
|
||||||
|
*/
|
||||||
|
if(!strnicmp(m_http_url,"https:",strlen("https:")))
|
||||||
|
{
|
||||||
|
m_con=new JNL_SSL_Connection(NULL,m_dns,8192,a);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_con=new JNL_Connection(m_dns,8192,a);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
m_con=new JNL_Connection(m_dns,8192,a);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_con)
|
||||||
|
{
|
||||||
|
if (!m_http_proxyhost || !m_http_proxyhost[0])
|
||||||
|
{
|
||||||
|
m_con->connect(m_http_host,m_http_port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_con->connect(m_http_proxyhost,m_http_proxyport);
|
||||||
|
}
|
||||||
|
m_con->send_string(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_http_state=-1;
|
||||||
|
seterrstr("could not create connection object");
|
||||||
|
}
|
||||||
|
free(str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_HTTPGet::do_parse_url(char *url, char **host, int *port, char **req, char **lp)
|
||||||
|
{
|
||||||
|
char *p,*np;
|
||||||
|
free(*host); *host=0;
|
||||||
|
free(*req); *req=0;
|
||||||
|
free(*lp); *lp=0;
|
||||||
|
|
||||||
|
if (strstr(url,"://")) np=p=strstr(url,"://")+3;
|
||||||
|
else np=p=url;
|
||||||
|
while (*np != '/' && *np) np++;
|
||||||
|
if (*np)
|
||||||
|
{
|
||||||
|
*req=(char*)malloc(strlen(np)+1);
|
||||||
|
if (*req) strcpy(*req,np);
|
||||||
|
*np++=0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*req=(char*)malloc(2);
|
||||||
|
if (*req) strcpy(*req,"/");
|
||||||
|
}
|
||||||
|
|
||||||
|
np=p;
|
||||||
|
while (*np != '@' && *np) np++;
|
||||||
|
if (*np)
|
||||||
|
{
|
||||||
|
*np++=0;
|
||||||
|
*lp=(char*)malloc(strlen(p)+1);
|
||||||
|
if (*lp) strcpy(*lp,p);
|
||||||
|
p=np;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*lp=(char*)malloc(1);
|
||||||
|
if (*lp) strcpy(*lp,"");
|
||||||
|
}
|
||||||
|
np=p;
|
||||||
|
while (*np != ':' && *np) np++;
|
||||||
|
if (*np)
|
||||||
|
{
|
||||||
|
*np++=0;
|
||||||
|
*port=atoi(np);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006
|
||||||
|
** HTTPS enhancements
|
||||||
|
*/
|
||||||
|
if(!strnicmp(url,"https:",strlen("https:")))
|
||||||
|
{
|
||||||
|
*port = 443;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*port=80;
|
||||||
|
}
|
||||||
|
*host=(char*)malloc(strlen(p)+1);
|
||||||
|
if (*host) strcpy(*host,p);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *JNL_HTTPGet::getallheaders()
|
||||||
|
{ // double null terminated, null delimited list
|
||||||
|
if (m_recvheaders) return m_recvheaders;
|
||||||
|
else return "\0\0";
|
||||||
|
}
|
||||||
|
|
||||||
|
char *JNL_HTTPGet::getheader(char *headername)
|
||||||
|
{
|
||||||
|
char *ret=NULL;
|
||||||
|
if (strlen(headername)<1||!m_recvheaders) return NULL;
|
||||||
|
char *buf=(char*)malloc(strlen(headername)+2);
|
||||||
|
strcpy(buf,headername);
|
||||||
|
if (buf[strlen(buf)-1]!=':') strcat(buf,":");
|
||||||
|
char *p=m_recvheaders;
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
if (!strnicmp(buf,p,strlen(buf)))
|
||||||
|
{
|
||||||
|
ret=p+strlen(buf);
|
||||||
|
ret=strdup(p+strlen(buf));
|
||||||
|
while (*ret == ' ') ret++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p+=strlen(p)+1;
|
||||||
|
}
|
||||||
|
ret = strdup(ret);
|
||||||
|
free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_HTTPGet::run()
|
||||||
|
{
|
||||||
|
int cnt=0;
|
||||||
|
if (m_http_state==-1||!m_con) return -1; // error
|
||||||
|
|
||||||
|
|
||||||
|
run_again:
|
||||||
|
m_con->run();
|
||||||
|
|
||||||
|
if (m_con->get_state()==JNL_Connection::STATE_ERROR)
|
||||||
|
{
|
||||||
|
seterrstr(m_con->get_errstr());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (m_con->get_state()==JNL_Connection::STATE_CLOSED) return 1;
|
||||||
|
|
||||||
|
if (m_http_state==0) // connected, waiting for reply
|
||||||
|
{
|
||||||
|
if (m_con->recv_lines_available()>0)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
m_con->recv_line(buf,4095);
|
||||||
|
buf[4095]=0;
|
||||||
|
m_reply=(char*)malloc(strlen(buf)+1);
|
||||||
|
strcpy(m_reply,buf);
|
||||||
|
|
||||||
|
int code=getreplycode();
|
||||||
|
if (code == 200 || code==206) m_http_state=2; // proceed to read headers normally
|
||||||
|
else if (code == 301 || code==302)
|
||||||
|
{
|
||||||
|
m_http_state=1; // redirect city
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seterrstr(buf);
|
||||||
|
m_http_state=-1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cnt=0;
|
||||||
|
}
|
||||||
|
else if (!cnt++) goto run_again;
|
||||||
|
}
|
||||||
|
if (m_http_state == 1) // redirect
|
||||||
|
{
|
||||||
|
while (m_con->recv_lines_available() > 0)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
m_con->recv_line(buf,4096);
|
||||||
|
if (!buf[0])
|
||||||
|
{
|
||||||
|
m_http_state=-1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!strnicmp(buf,"Location:",9))
|
||||||
|
{
|
||||||
|
char *p=buf+9; while (*p== ' ') p++;
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
free(m_http_redir_url);
|
||||||
|
m_http_redir_url = strdup(p);
|
||||||
|
connect(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_http_state==2)
|
||||||
|
{
|
||||||
|
if (!cnt++ && m_con->recv_lines_available() < 1) goto run_again;
|
||||||
|
while (m_con->recv_lines_available() > 0)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
m_con->recv_line(buf,4096);
|
||||||
|
if (!buf[0]) { m_http_state=3; break; }
|
||||||
|
if (!m_recvheaders)
|
||||||
|
{
|
||||||
|
m_recvheaders_size=strlen(buf)+1;
|
||||||
|
m_recvheaders=(char*)malloc(m_recvheaders_size+1);
|
||||||
|
if (m_recvheaders)
|
||||||
|
{
|
||||||
|
strcpy(m_recvheaders,buf);
|
||||||
|
m_recvheaders[m_recvheaders_size]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int oldsize=m_recvheaders_size;
|
||||||
|
m_recvheaders_size+=strlen(buf)+1;
|
||||||
|
char *n=(char*)malloc(m_recvheaders_size+1);
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
memcpy(n,m_recvheaders,oldsize);
|
||||||
|
strcpy(n+oldsize,buf);
|
||||||
|
n[m_recvheaders_size]=0;
|
||||||
|
free(m_recvheaders);
|
||||||
|
m_recvheaders=n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_http_state==3)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_HTTPGet::get_status() // returns 0 if connecting, 1 if reading headers,
|
||||||
|
// 2 if reading content, -1 if error.
|
||||||
|
{
|
||||||
|
if (m_http_state < 0) return -1;
|
||||||
|
if (m_http_state < 2) return 0;
|
||||||
|
if (m_http_state == 2) return 1;
|
||||||
|
if (m_http_state == 3) return 2;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_HTTPGet::getreplycode()// returns 0 if none yet, otherwise returns http reply code.
|
||||||
|
{
|
||||||
|
if (!m_reply) return 0;
|
||||||
|
char *p=m_reply;
|
||||||
|
while (*p && *p != ' ') p++; // skip over HTTP/x.x
|
||||||
|
if (!*p) return 0;
|
||||||
|
return atoi(++p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_HTTPGet::bytes_available()
|
||||||
|
{
|
||||||
|
if (m_con && m_http_state==3) return m_con->recv_bytes_available();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char *JNL_HTTPGet::getredirurl() { return m_http_redir_url; }
|
||||||
|
|
||||||
|
int JNL_HTTPGet::get_bytes(char *buf, int len)
|
||||||
|
{
|
||||||
|
if (m_con && m_http_state==3) return m_con->recv_bytes(buf,len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int JNL_HTTPGet::peek_bytes(char *buf, int len)
|
||||||
|
{
|
||||||
|
if (m_con && m_http_state==3) return m_con->peek_bytes(buf,len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
112
foo_httpcontrol/lib/jnetlib/httpget.h
Executable file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: httpget.h - JNL interface for doing HTTP GETs.
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** Usage:
|
||||||
|
** 1. Create a JNL_HTTPGet object, optionally specifying a JNL_AsyncDNS
|
||||||
|
** object to use (or NULL for none, or JNL_CONNECTION_AUTODNS for auto),
|
||||||
|
** and the receive buffer size, and a string specifying proxy (or NULL
|
||||||
|
** for none). See note on proxy string below.
|
||||||
|
** 2. call addheader() to add whatever headers you want. It is recommended to
|
||||||
|
** add at least the following two:
|
||||||
|
** addheader("User-Agent:MyApp (Mozilla)");
|
||||||
|
*/// addheader("Accept:*/*");
|
||||||
|
/* ( the comment weirdness is there so I Can do the star-slash :)
|
||||||
|
** 3. Call connect() with the URL you wish to GET (see URL string note below)
|
||||||
|
** 4. Call run() once in a while, checking to see if it returns -1
|
||||||
|
** (if it does return -1, call geterrorstr() to see what the error is).
|
||||||
|
** (if it returns 1, no big deal, the connection has closed).
|
||||||
|
** 5. While you're at it, you can call bytes_available() to see if any data
|
||||||
|
** from the http stream is available, or getheader() to see if any headers
|
||||||
|
** are available, or getreply() to see the HTTP reply, or getallheaders()
|
||||||
|
** to get a double null terminated, null delimited list of headers returned.
|
||||||
|
** 6. If you want to read from the stream, call get_bytes (which returns how much
|
||||||
|
** was actually read).
|
||||||
|
** 7. content_length() is a helper function that uses getheader() to check the
|
||||||
|
** content-length header.
|
||||||
|
** 8. Delete ye' ol' object when done.
|
||||||
|
**
|
||||||
|
** Proxy String:
|
||||||
|
** should be in the format of host:port, or user@host:port, or
|
||||||
|
** user:password@host:port. if port is not specified, 80 is assumed.
|
||||||
|
** URL String:
|
||||||
|
** should be in the format of http://user:pass@host:port/requestwhatever
|
||||||
|
** note that user, pass, port, and /requestwhatever are all optional :)
|
||||||
|
** note that also, http:// is really not important. if you do poo://
|
||||||
|
** or even leave out the http:// altogether, it will still work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HTTPGET_H_
|
||||||
|
#define _HTTPGET_H_
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
class JNL_HTTPGet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JNL_HTTPGet(JNL_AsyncDNS *dns=JNL_CONNECTION_AUTODNS, int recvbufsize=16384, char *proxy=NULL);
|
||||||
|
~JNL_HTTPGet();
|
||||||
|
|
||||||
|
void addheader(const char *header);
|
||||||
|
|
||||||
|
void connect(const char *url, int ver=0, char *requestmethod="GET");
|
||||||
|
|
||||||
|
int run(); // returns: 0 if all is OK. -1 if error (call geterrorstr()). 1 if connection closed.
|
||||||
|
|
||||||
|
int get_status(); // returns 0 if connecting, 1 if reading headers,
|
||||||
|
// 2 if reading content, -1 if error.
|
||||||
|
|
||||||
|
char *getallheaders(); // double null terminated, null delimited list
|
||||||
|
char *getheader(char *headername);
|
||||||
|
char *getreply() { return m_reply; }
|
||||||
|
int getreplycode(); // returns 0 if none yet, otherwise returns http reply code.
|
||||||
|
|
||||||
|
char *geterrorstr() { return m_errstr;}
|
||||||
|
|
||||||
|
char *getredirurl();
|
||||||
|
|
||||||
|
int bytes_available();
|
||||||
|
int get_bytes(char *buf, int len);
|
||||||
|
int peek_bytes(char *buf, int len);
|
||||||
|
|
||||||
|
int content_length() { char *p=getheader("content-length"); if (p) return atoi(p); return 0; }
|
||||||
|
|
||||||
|
JNL_Connection *get_con() { return m_con; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void reinit();
|
||||||
|
void deinit();
|
||||||
|
void seterrstr(char *str) { if (m_errstr) free(m_errstr); m_errstr=(char*)malloc(strlen(str)+1); strcpy(m_errstr,str); }
|
||||||
|
|
||||||
|
void do_parse_url(char *url, char **host, int *port, char **req, char **lp);
|
||||||
|
void do_encode_mimestr(char *in, char *out);
|
||||||
|
|
||||||
|
JNL_AsyncDNS *m_dns;
|
||||||
|
JNL_Connection *m_con;
|
||||||
|
int m_recvbufsize;
|
||||||
|
|
||||||
|
int m_http_state;
|
||||||
|
|
||||||
|
int m_http_port;
|
||||||
|
char *m_http_url;
|
||||||
|
char *m_http_redir_url;
|
||||||
|
char *m_http_host;
|
||||||
|
char *m_http_lpinfo;
|
||||||
|
char *m_http_request;
|
||||||
|
|
||||||
|
char *m_http_proxylpinfo;
|
||||||
|
char *m_http_proxyhost;
|
||||||
|
int m_http_proxyport;
|
||||||
|
|
||||||
|
char *m_sendheaders;
|
||||||
|
char *m_recvheaders;
|
||||||
|
int m_recvheaders_size;
|
||||||
|
char *m_reply;
|
||||||
|
|
||||||
|
char *m_errstr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _HTTPGET_H_
|
||||||
412
foo_httpcontrol/lib/jnetlib/httppost.cpp
Executable file
@@ -0,0 +1,412 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) Joshua Teitelbaum, sergent first class, 1014 army.
|
||||||
|
** Author: Joshua Teitelbaum
|
||||||
|
** File: httppost.cpp
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "httppost.h"
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
static char *PREFIX = "--";
|
||||||
|
static char *NEWLINE = "\r\n";
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/15/2006
|
||||||
|
** 1014 Army, Sergent First Class
|
||||||
|
** HTTP Post implementation employing HTTPGet as base class.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
** _endstack
|
||||||
|
** when building the POST stack for a FORM, need a postamble
|
||||||
|
*/
|
||||||
|
void JNL_HTTPPost::_endstack()
|
||||||
|
{
|
||||||
|
std::string cd;
|
||||||
|
cd = PREFIX;
|
||||||
|
cd += m_boundary;
|
||||||
|
cd += PREFIX;
|
||||||
|
cd += NEWLINE;
|
||||||
|
|
||||||
|
FILEStackObject fso;
|
||||||
|
fso.m_otype = 2;
|
||||||
|
fso.m_str = cd;
|
||||||
|
m_filestack.push_back(fso);
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** prepares one field and puts it on the stack
|
||||||
|
*/
|
||||||
|
void JNL_HTTPPost::_preparefield(std::string &name)
|
||||||
|
{
|
||||||
|
std::string cd;
|
||||||
|
|
||||||
|
cd = PREFIX;
|
||||||
|
cd += m_boundary;
|
||||||
|
cd += NEWLINE;
|
||||||
|
cd += "content-disposition: form-data; name=\"";
|
||||||
|
cd += name;
|
||||||
|
cd += "\"";
|
||||||
|
cd += NEWLINE;
|
||||||
|
cd += NEWLINE;
|
||||||
|
cd += m_fields[name];
|
||||||
|
cd += "\r\n";
|
||||||
|
|
||||||
|
FILEStackObject fso;
|
||||||
|
|
||||||
|
fso.m_otype = 3;
|
||||||
|
fso.m_str = cd;
|
||||||
|
m_filestack.push_back(fso);
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** prepare all the fields, and push them on the stack
|
||||||
|
*/
|
||||||
|
void JNL_HTTPPost::_preparefieldstack()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string>::iterator it;
|
||||||
|
|
||||||
|
for(it = m_fields.begin(); it != m_fields.end(); it++)
|
||||||
|
{
|
||||||
|
std::string str = (*it).first;
|
||||||
|
_preparefield(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** prepare files and put them on the stack
|
||||||
|
*/
|
||||||
|
void JNL_HTTPPost::_preparefilestack()
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string>::iterator it;
|
||||||
|
|
||||||
|
for(it = m_paths.begin(); it != m_paths.end(); it++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
--boundary\r\n
|
||||||
|
Content-Disposition: form-data; name="<fieldName>"; filename="<filename>"\r\n
|
||||||
|
Content-Type: <mime-type>\r\n
|
||||||
|
\r\n
|
||||||
|
<file-data>\r\n
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::string cd ;
|
||||||
|
|
||||||
|
cd = PREFIX;
|
||||||
|
cd += m_boundary;
|
||||||
|
cd += NEWLINE;
|
||||||
|
cd += "content-disposition: form-data; name=\"";
|
||||||
|
cd += (*it).first;
|
||||||
|
cd += "\"; filename=\"";
|
||||||
|
cd += m_filenames[(*it).first];
|
||||||
|
cd += "\"";
|
||||||
|
cd += NEWLINE;
|
||||||
|
cd += "content-type: ";
|
||||||
|
cd += m_content_type[(*it).first];
|
||||||
|
cd += NEWLINE;
|
||||||
|
cd += NEWLINE;
|
||||||
|
|
||||||
|
|
||||||
|
FILEStackObject fso;
|
||||||
|
|
||||||
|
fso.m_otype = 0;
|
||||||
|
fso.m_str = cd;
|
||||||
|
m_filestack.push_back(fso);
|
||||||
|
|
||||||
|
fso.m_otype = 1;
|
||||||
|
fso.m_str = (*it).first;
|
||||||
|
m_filestack.push_back(fso);
|
||||||
|
|
||||||
|
cd = NEWLINE;
|
||||||
|
|
||||||
|
fso.m_otype = 2;
|
||||||
|
fso.m_str = cd;
|
||||||
|
m_filestack.push_back(fso);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** payload function, run.
|
||||||
|
** the tactic is this:
|
||||||
|
** if we can't write, do normal run.
|
||||||
|
**
|
||||||
|
** while there is stuff on the POST stack
|
||||||
|
** pop and item
|
||||||
|
** write to the buffers as much as we can
|
||||||
|
** if we can't write more, stop
|
||||||
|
** end while
|
||||||
|
** do normal run
|
||||||
|
*/
|
||||||
|
int JNL_HTTPPost::run()
|
||||||
|
{
|
||||||
|
bool stop = 0;
|
||||||
|
std::map<std::string, std::string>::iterator it;
|
||||||
|
int ntowrite;
|
||||||
|
int retval;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if(m_con->send_bytes_available() <= 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** rut roh, no buffa
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_filestack.size() <= 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Nothing to do
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** Get the current object off the stack
|
||||||
|
*/
|
||||||
|
switch(m_filestack.front().m_otype)
|
||||||
|
{
|
||||||
|
case 0: /*preamble*/
|
||||||
|
case 2: /*postamble*/
|
||||||
|
case 3: /*plain jane field*/
|
||||||
|
{
|
||||||
|
ntowrite = m_filestack.front().m_str.length() - m_filestack.front().nwritten;
|
||||||
|
|
||||||
|
if(m_con->send_bytes_available() < ntowrite)
|
||||||
|
{
|
||||||
|
ntowrite = m_con->send_bytes_available();
|
||||||
|
}
|
||||||
|
if(ntowrite>0)
|
||||||
|
{
|
||||||
|
retval = m_con->send(m_filestack.front().m_str.c_str() + m_filestack.front().nwritten,ntowrite);
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filestack.front().nwritten += ntowrite;
|
||||||
|
m_nwritten += ntowrite;
|
||||||
|
|
||||||
|
if( m_filestack.front().nwritten == m_filestack.front().m_str.length())
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** all done with this object
|
||||||
|
*/
|
||||||
|
m_filestack.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retval = 0;
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: /*MEAT*/
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int sresult;
|
||||||
|
fp = fopen(m_paths[m_filestack.front().m_str].c_str(),"rb");
|
||||||
|
|
||||||
|
if(fp == NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** someone gave this process a hot foot?
|
||||||
|
*/
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sresult = fseek(fp,m_filestack.front().nwritten,SEEK_SET);
|
||||||
|
|
||||||
|
if(sresult < 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** someone gave this process a hot foot?
|
||||||
|
*/
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(((m_content_length[m_filestack.front().m_str] - m_filestack.front().nwritten)) > (unsigned long)m_con->send_bytes_available())
|
||||||
|
{
|
||||||
|
ntowrite = m_con->send_bytes_available();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ntowrite = (m_content_length[m_filestack.front().m_str] - m_filestack.front().nwritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *b=NULL;
|
||||||
|
|
||||||
|
b = (char *)malloc(ntowrite);
|
||||||
|
|
||||||
|
if(b == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
/*
|
||||||
|
** whiskey tango foxtrot
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** read from where we left off
|
||||||
|
*/
|
||||||
|
sresult = fread(b,1,ntowrite,fp);
|
||||||
|
|
||||||
|
if(sresult != ntowrite)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** hot foot with matches again
|
||||||
|
*/
|
||||||
|
if(b)
|
||||||
|
{
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
retval = m_con->send(b,ntowrite);
|
||||||
|
|
||||||
|
free(b);
|
||||||
|
|
||||||
|
if(retval < 0)
|
||||||
|
{
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filestack.front().nwritten += ntowrite;
|
||||||
|
|
||||||
|
m_nwritten += ntowrite;
|
||||||
|
|
||||||
|
if(m_filestack.front().nwritten == m_content_length[m_filestack.front().m_str])
|
||||||
|
{
|
||||||
|
m_filestack.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(!stop);
|
||||||
|
|
||||||
|
return JNL_HTTPGet::run();
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** addfield, adds field
|
||||||
|
*/
|
||||||
|
int JNL_HTTPPost::addfield(char *name, char *val)
|
||||||
|
{
|
||||||
|
if(name == NULL || val == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
m_fields[name]=val;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** addfile, adds file
|
||||||
|
*/
|
||||||
|
int JNL_HTTPPost::addfile(char *name, char *mimetype, char *filename, char *filepath)
|
||||||
|
{
|
||||||
|
struct stat buffer;
|
||||||
|
|
||||||
|
FILE *fp=NULL;
|
||||||
|
if(name==NULL || filepath == NULL || mimetype == NULL || filename == NULL || (!(fp=fopen(filepath,"rb"))))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_content_type[name] = mimetype;
|
||||||
|
m_paths[name] = filepath;
|
||||||
|
m_filenames[name] = filename;
|
||||||
|
|
||||||
|
fstat(fileno(fp),&buffer);
|
||||||
|
fclose(fp);
|
||||||
|
m_content_length[name] = buffer.st_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
** After adding fields and files, get the content length
|
||||||
|
*/
|
||||||
|
int JNL_HTTPPost::contentlength()
|
||||||
|
{
|
||||||
|
std::map<std::string,std::string>::iterator it;
|
||||||
|
std::string tmp;
|
||||||
|
int length = 0;
|
||||||
|
// fields
|
||||||
|
{
|
||||||
|
for (it = m_fields.begin(); it != m_fields.end(); it++)
|
||||||
|
{
|
||||||
|
std::string name = (*it).first;
|
||||||
|
std::string value = (*it).second;
|
||||||
|
|
||||||
|
tmp = "--" + m_boundary + "\r\n"
|
||||||
|
"content-disposition: form-data; name=\"" + name + "\"\r\n"
|
||||||
|
"\r\n";
|
||||||
|
tmp += value + "\r\n";
|
||||||
|
|
||||||
|
length += tmp.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// files
|
||||||
|
{
|
||||||
|
for (it = m_filenames.begin(); it != m_filenames.end(); it++)
|
||||||
|
{
|
||||||
|
std::string name = (*it).first;
|
||||||
|
std::string filename = (*it).second;
|
||||||
|
long content_length = m_content_length[name];
|
||||||
|
std::string content_type = m_content_type[name];
|
||||||
|
tmp = "--" + m_boundary + "\r\n"
|
||||||
|
"content-disposition: form-data; name=\"" + name + "\"; filename=\"" + filename + "\"\r\n"
|
||||||
|
"content-type: " + content_type + "\r\n"
|
||||||
|
"\r\n";
|
||||||
|
length += tmp.size();
|
||||||
|
length += content_length;
|
||||||
|
length += 2; // crlf after file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end
|
||||||
|
tmp = "--" + m_boundary + "--\r\n";
|
||||||
|
length += tmp.size();
|
||||||
|
|
||||||
|
return length;
|
||||||
|
|
||||||
|
}
|
||||||
|
void JNL_HTTPPost::_addformheader()
|
||||||
|
{
|
||||||
|
char *h;
|
||||||
|
#ifdef _WIN32
|
||||||
|
srand(GetTickCount());
|
||||||
|
#else
|
||||||
|
srand(time(NULL));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int x;
|
||||||
|
char *preamble = "content-type:multipart/form-data; boundary=";
|
||||||
|
char *dashes = "----";
|
||||||
|
|
||||||
|
char *post_boundary = (char*)alloca(10+strlen(dashes));
|
||||||
|
memcpy(post_boundary,dashes,strlen(dashes));
|
||||||
|
|
||||||
|
for(x=strlen(dashes); x < (int)strlen(dashes)+9; x++)
|
||||||
|
{
|
||||||
|
post_boundary[x] = (char)(rand() % 9) + '0';
|
||||||
|
}
|
||||||
|
post_boundary[x] = 0;
|
||||||
|
|
||||||
|
h = (char *)alloca(strlen(preamble) + strlen(post_boundary) + 1);
|
||||||
|
sprintf(h,"%s%s",preamble,post_boundary);
|
||||||
|
addheader(h);
|
||||||
|
m_boundary = post_boundary;
|
||||||
|
}
|
||||||
129
foo_httpcontrol/lib/jnetlib/httppost.h
Executable file
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) Joshua Teitelbaum, sergent first class, 1014 army.
|
||||||
|
** Author: Joshua Teitelbaum
|
||||||
|
** File: httppost.cpp/h
|
||||||
|
** License: see jnetlib.h
|
||||||
|
** Usage:
|
||||||
|
** 1. Create a JNL_HTTPPost object, optionally specifying a JNL_AsyncDNS
|
||||||
|
** object to use (or NULL for none, or JNL_CONNECTION_AUTODNS for auto),
|
||||||
|
** and the receive buffer size, and a string specifying proxy (or NULL
|
||||||
|
** for none). See note on proxy string below.
|
||||||
|
** 2. call addheader() to add whatever headers you want. It is recommended to
|
||||||
|
** add at least the following two:
|
||||||
|
** addheader("User-Agent:MyApp (Mozilla)");
|
||||||
|
*/// addheader("Accept:*/*");
|
||||||
|
/* Joshua Teitelbaum 1/15/2006
|
||||||
|
** 2.5 call addfield to add field items to your POST
|
||||||
|
** 2.9 call addfile to add file items to your POST
|
||||||
|
*/
|
||||||
|
/* ( the comment weirdness is there so I Can do the star-slash :)
|
||||||
|
** 3. Call connect() with the URL you wish to Post (see URL string note below)
|
||||||
|
** 4. Call run() once in a while, checking to see if it returns -1
|
||||||
|
** (if it does return -1, call geterrorstr() to see what the error is).
|
||||||
|
** (if it returns 1, no big deal, the connection has closed).
|
||||||
|
** 5. While you're at it, you can call bytes_available() to see if any data
|
||||||
|
** from the http stream is available, or getheader() to see if any headers
|
||||||
|
** are available, or getreply() to see the HTTP reply, or getallheaders()
|
||||||
|
** to get a double null terminated, null delimited list of headers returned.
|
||||||
|
** 6. If you want to read from the stream, call get_bytes (which returns how much
|
||||||
|
** was actually read).
|
||||||
|
** 7. content_length() is a helper function that uses getheader() to check the
|
||||||
|
** content-length header.
|
||||||
|
** 8. Delete ye' ol' object when done.
|
||||||
|
**
|
||||||
|
** Proxy String:
|
||||||
|
** should be in the format of host:port, or user@host:port, or
|
||||||
|
** user:password@host:port. if port is not specified, 80 is assumed.
|
||||||
|
** URL String:
|
||||||
|
** should be in the format of http://user:pass@host:port/requestwhatever
|
||||||
|
** note that user, pass, port, and /requestwhatever are all optional :)
|
||||||
|
** note that also, http:// is really not important. if you do poo://
|
||||||
|
** or even leave out the http:// altogether, it will still work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HTTPPOST_H_
|
||||||
|
#define _HTTPPOST_H_
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
#include "httpget.h"
|
||||||
|
/*
|
||||||
|
** VC6 SPEW
|
||||||
|
*/
|
||||||
|
#pragma warning(disable:4786)
|
||||||
|
/*
|
||||||
|
** END VC6 SPEW
|
||||||
|
*/
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class FILEStackObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int m_otype; /* 0 = PREAMBLE, 1 = DO THE FILE , 2 = POSTAMBLE, 3 = FIELD */
|
||||||
|
std::string m_str;
|
||||||
|
unsigned long nwritten;
|
||||||
|
public:
|
||||||
|
FILEStackObject()
|
||||||
|
{
|
||||||
|
m_otype = 0;
|
||||||
|
m_str = "";
|
||||||
|
nwritten = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
class JNL_HTTPPost : public JNL_HTTPGet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int run(void);
|
||||||
|
void connect(const char *url, int ver=1, char *requestmethod="POST")
|
||||||
|
{
|
||||||
|
m_nwritten = 0;
|
||||||
|
|
||||||
|
_addformheader();
|
||||||
|
|
||||||
|
_preparefieldstack();
|
||||||
|
_preparefilestack();
|
||||||
|
|
||||||
|
_addcontentlength();
|
||||||
|
|
||||||
|
_endstack();
|
||||||
|
|
||||||
|
JNL_HTTPGet::connect(url,ver,requestmethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
int addfield(char *name, char *val);
|
||||||
|
int addfile(char *name, char *mimetype, char *filename, char *filepath);
|
||||||
|
int contentlength();
|
||||||
|
unsigned long written(){return m_nwritten;};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void _preparefield(std::string &str);
|
||||||
|
void _preparefieldstack();
|
||||||
|
void _preparefilestack();
|
||||||
|
void _endstack();
|
||||||
|
void _addformheader();
|
||||||
|
void _addcontentlength()
|
||||||
|
{
|
||||||
|
char sz[1024];
|
||||||
|
sprintf(sz,"Content-length:%d",contentlength());
|
||||||
|
addheader(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long m_nwritten;
|
||||||
|
std::string m_boundary;
|
||||||
|
std::string m_strcurrentfileformname;
|
||||||
|
|
||||||
|
std::map<std::string /*name*/ ,std::string /*value*/> m_fields;
|
||||||
|
std::map<std::string /*name*/ ,std::string /*content type*/> m_content_type;
|
||||||
|
std::map<std::string /*name*/ ,std::string /*path*/> m_paths;
|
||||||
|
std::map<std::string /*name*/ ,std::string /*filename*/> m_filenames;
|
||||||
|
std::map<std::string /*name */,unsigned long /*size*/> m_content_length;
|
||||||
|
|
||||||
|
std::list<FILEStackObject> m_filestack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _HTTPPOST_H_
|
||||||
257
foo_httpcontrol/lib/jnetlib/httpserv.cpp
Executable file
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: httpserv.cpp - JNL HTTP GET/POST serving implementation
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** This class just manages the http reply/sending, not where the data
|
||||||
|
** comes from, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "httpserv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
States for m_state:
|
||||||
|
-1 error (connection closed, etc)
|
||||||
|
0 not read request yet.
|
||||||
|
1 reading headers
|
||||||
|
2 headers read, have not sent reply
|
||||||
|
3 sent reply
|
||||||
|
4 closed
|
||||||
|
*/
|
||||||
|
|
||||||
|
JNL_HTTPServ::JNL_HTTPServ(JNL_Connection *con)
|
||||||
|
{
|
||||||
|
m_con=con;
|
||||||
|
m_state=0;
|
||||||
|
m_reply_headers=0;
|
||||||
|
m_reply_string=0;
|
||||||
|
m_recvheaders=0;
|
||||||
|
m_recv_request=0;
|
||||||
|
m_recvheaders_size=0;
|
||||||
|
m_errstr=0;
|
||||||
|
m_reply_ready=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_HTTPServ::~JNL_HTTPServ()
|
||||||
|
{
|
||||||
|
free(m_recv_request);
|
||||||
|
free(m_recvheaders);
|
||||||
|
free(m_reply_string);
|
||||||
|
free(m_reply_headers);
|
||||||
|
free(m_errstr);
|
||||||
|
delete m_con;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_HTTPServ::run()
|
||||||
|
{ // returns: < 0 on error, 0 on connection close, 1 if reading request, 2 if reply not sent, 3 if reply sent, sending data.
|
||||||
|
int cnt=0;
|
||||||
|
run_again:
|
||||||
|
m_con->run();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (m_con->get_state()==JNL_Connection::STATE_ERROR)
|
||||||
|
{
|
||||||
|
seterrstr(m_con->get_errstr());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_con->get_state()==JNL_Connection::STATE_CLOSED || m_con->get_state()==JNL_Connection::STATE_CLOSING)
|
||||||
|
return 4; // IE9
|
||||||
|
|
||||||
|
if (m_state == 0)
|
||||||
|
{
|
||||||
|
if (m_con->recv_lines_available()>0)
|
||||||
|
{
|
||||||
|
char *buf=(char*)malloc(m_con->recv_bytes_available()-1);
|
||||||
|
m_con->recv_line(buf,m_con->recv_bytes_available()-1);
|
||||||
|
free(m_recv_request);
|
||||||
|
m_recv_request=(char*)malloc(strlen(buf)+2);
|
||||||
|
strcpy(m_recv_request,buf);
|
||||||
|
m_recv_request[strlen(m_recv_request)+1]=0;
|
||||||
|
free(buf);
|
||||||
|
buf=m_recv_request;
|
||||||
|
|
||||||
|
while (*buf) buf++;
|
||||||
|
while (buf >= m_recv_request && *buf != ' ') buf--;
|
||||||
|
if (strncmp(buf+1,"HTTP",4) || strncmp(m_recv_request,"GET ",3))
|
||||||
|
{
|
||||||
|
seterrstr("malformed HTTP request");
|
||||||
|
m_state=-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_state=1;
|
||||||
|
cnt=0;
|
||||||
|
if (buf >= m_recv_request) buf[0]=buf[1]=0;
|
||||||
|
|
||||||
|
buf=strstr(m_recv_request,"?");
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
*buf++=0; // change &'s into 0s now.
|
||||||
|
char *t=buf;
|
||||||
|
int stat=1;
|
||||||
|
|
||||||
|
while (*t)
|
||||||
|
{
|
||||||
|
if (*t == '&' && !stat)
|
||||||
|
{
|
||||||
|
stat=1;
|
||||||
|
*t=0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stat=0;
|
||||||
|
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!cnt++)
|
||||||
|
goto run_again;
|
||||||
|
}
|
||||||
|
if (m_state == 1)
|
||||||
|
{
|
||||||
|
if (!cnt++ && m_con->recv_lines_available()<1)
|
||||||
|
goto run_again;
|
||||||
|
|
||||||
|
while (m_con->recv_lines_available()>0)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
buf[0]=0;
|
||||||
|
m_con->recv_line(buf,4096);
|
||||||
|
if (!buf[0]) { m_state=2; break; }
|
||||||
|
if (!m_recvheaders)
|
||||||
|
{
|
||||||
|
m_recvheaders_size=strlen(buf)+1;
|
||||||
|
m_recvheaders=(char*)malloc(m_recvheaders_size+1);
|
||||||
|
if (m_recvheaders)
|
||||||
|
{
|
||||||
|
strcpy(m_recvheaders,buf);
|
||||||
|
m_recvheaders[m_recvheaders_size]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int oldsize=m_recvheaders_size;
|
||||||
|
m_recvheaders_size+=strlen(buf)+1;
|
||||||
|
char *n=(char*)malloc(m_recvheaders_size+1);
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
memcpy(n,m_recvheaders,oldsize);
|
||||||
|
strcpy(n+oldsize,buf);
|
||||||
|
n[m_recvheaders_size]=0;
|
||||||
|
free(m_recvheaders);
|
||||||
|
m_recvheaders=n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_state == 2)
|
||||||
|
{
|
||||||
|
if (m_reply_ready)
|
||||||
|
{
|
||||||
|
// send reply
|
||||||
|
m_con->send_string((char*)(m_reply_string?m_reply_string:"HTTP/1.0 200 OK")); // IE9 HTTP/1.1
|
||||||
|
m_con->send_string("\r\n");
|
||||||
|
if (m_reply_headers) m_con->send_string(m_reply_headers);
|
||||||
|
m_con->send_string("\r\n");
|
||||||
|
m_state=3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_state == 3)
|
||||||
|
{
|
||||||
|
// nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *JNL_HTTPServ::get_request_file()
|
||||||
|
{
|
||||||
|
// file portion of http request
|
||||||
|
if (!m_recv_request) return NULL;
|
||||||
|
char *t=m_recv_request;
|
||||||
|
while (*t != ' ' && *t) t++;
|
||||||
|
if (!*t) return NULL;
|
||||||
|
while (*t == ' ') t++;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *JNL_HTTPServ::get_request_parm(char *parmname) // parameter portion (after ?)
|
||||||
|
{
|
||||||
|
char *t=m_recv_request;
|
||||||
|
while (*t) t++;
|
||||||
|
t++;
|
||||||
|
while (*t)
|
||||||
|
{
|
||||||
|
while (*t == '&') t++;
|
||||||
|
if (!strnicmp(t,parmname,strlen(parmname)) && t[strlen(parmname)] == '=')
|
||||||
|
{
|
||||||
|
return t+strlen(parmname)+1;
|
||||||
|
}
|
||||||
|
t+=strlen(t)+1;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *JNL_HTTPServ::getheader(char *headername)
|
||||||
|
{
|
||||||
|
char *ret=NULL;
|
||||||
|
if (strlen(headername)<1||!m_recvheaders) return NULL;
|
||||||
|
|
||||||
|
// char *buf=(char*)malloc(strlen(headername)+2);
|
||||||
|
|
||||||
|
// ret = (char*)malloc(strlen(headername)+2);
|
||||||
|
// strcpy(buf,headername);
|
||||||
|
// if (buf[strlen(buf)-1]!=':') strcat(buf,":");
|
||||||
|
char *p=m_recvheaders;
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
if (!strnicmp(headername,p,strlen(headername)))
|
||||||
|
{
|
||||||
|
ret=p+strlen(headername);
|
||||||
|
while (*ret == ' ') ret++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p+=strlen(p)+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
ret = strdup(ret);
|
||||||
|
|
||||||
|
// free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_HTTPServ::set_reply_string(char *reply_string) // should be HTTP/1.1 OK or the like
|
||||||
|
{
|
||||||
|
free(m_reply_string);
|
||||||
|
m_reply_string=(char*)malloc(strlen(reply_string)+1);
|
||||||
|
strcpy(m_reply_string,reply_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_HTTPServ::set_reply_header(char *header) // "Connection: close" for example
|
||||||
|
{
|
||||||
|
if (m_reply_headers)
|
||||||
|
{
|
||||||
|
char *tmp=(char*)malloc(strlen(m_reply_headers)+strlen(header)+3);
|
||||||
|
strcpy(tmp,m_reply_headers);
|
||||||
|
strcat(tmp,header);
|
||||||
|
strcat(tmp,"\r\n");
|
||||||
|
free(m_reply_headers);
|
||||||
|
m_reply_headers=tmp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_reply_headers=(char*)malloc(strlen(header)+3);
|
||||||
|
strcpy(m_reply_headers,header);
|
||||||
|
strcat(m_reply_headers,"\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
62
foo_httpcontrol/lib/jnetlib/httpserv.h
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: httpserv.h - JNL interface for doing HTTP GET/POST serving.
|
||||||
|
** License: see jnetlib.h
|
||||||
|
** This class just manages the http reply/sending, not where the data
|
||||||
|
** comes from, etc.
|
||||||
|
** for a mini-web server see webserver.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HTTPSERV_H_
|
||||||
|
#define _HTTPSERV_H_
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
class JNL_HTTPServ
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JNL_HTTPServ(JNL_Connection *con);
|
||||||
|
~JNL_HTTPServ();
|
||||||
|
|
||||||
|
int run(); // returns: < 0 on error, 0 on request not read yet, 1 if reading headers, 2 if reply not sent, 3 if reply sent, sending data. 4 on connection closed.
|
||||||
|
|
||||||
|
char *geterrorstr() { return m_errstr;}
|
||||||
|
|
||||||
|
// use these when state returned by run() is 2
|
||||||
|
char *get_request_file(); // file portion of http request
|
||||||
|
char *get_request_parm(char *parmname); // parameter portion (after ?)
|
||||||
|
char *getallheaders() { return m_recvheaders; } // double null terminated, null delimited list
|
||||||
|
char *getheader(char *headername);
|
||||||
|
|
||||||
|
void set_reply_string(char *reply_string); // should be HTTP/1.1 OK or the like
|
||||||
|
void set_reply_header(char *header); // i.e. "content-size: 12345"
|
||||||
|
|
||||||
|
void send_reply() { m_reply_ready=1; } // send reply, state will advance to 3.
|
||||||
|
|
||||||
|
////////// sending data ///////////////
|
||||||
|
int bytes_inqueue() { if (m_state == 3 || m_state == -1 || m_state ==4) return m_con->send_bytes_in_queue(); else return 0; }
|
||||||
|
int bytes_cansend() { if (m_state == 3) return m_con->send_bytes_available(); else return 0; }
|
||||||
|
void write_bytes(char *bytes, int length) { m_con->send(bytes,length); }
|
||||||
|
|
||||||
|
void close(int quick) { m_con->close(quick); m_state=4; }
|
||||||
|
|
||||||
|
JNL_Connection *get_con() { return m_con; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void seterrstr(char *str) { if (m_errstr) free(m_errstr); m_errstr=(char*)malloc(strlen(str)+1); strcpy(m_errstr,str); }
|
||||||
|
|
||||||
|
int m_reply_ready;
|
||||||
|
int m_state;
|
||||||
|
|
||||||
|
char *m_errstr;
|
||||||
|
char *m_reply_headers;
|
||||||
|
char *m_reply_string;
|
||||||
|
char *m_recvheaders;
|
||||||
|
int m_recvheaders_size;
|
||||||
|
char *m_recv_request; // either double-null terminated, or may contain parameters after first null.
|
||||||
|
JNL_Connection *m_con;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _HTTPSERV_H_
|
||||||
1373
foo_httpcontrol/lib/jnetlib/ircclient.cpp
Executable file
472
foo_httpcontrol/lib/jnetlib/ircclient.h
Executable file
@@ -0,0 +1,472 @@
|
|||||||
|
#ifndef _JNL_IRCCLIENT_H_
|
||||||
|
#define _JNL_IRCCLIENT_H_
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include "connection.h"
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <ctype.h>
|
||||||
|
/*
|
||||||
|
** ERRORS
|
||||||
|
*/
|
||||||
|
#define ERR_NOSUCHNICK 401
|
||||||
|
#define ERR_NOSUCHSERVER 402
|
||||||
|
#define ERR_NOSUCHCHANNEL 403
|
||||||
|
#define ERR_CANNOTSENDTOCHAN 404
|
||||||
|
#define ERR_TOOMANYCHANNELS 405
|
||||||
|
#define ERR_WASNOSUCHNICK 406
|
||||||
|
#define ERR_TOOMANYTARGETS 407
|
||||||
|
#define ERR_NOORIGIN 409
|
||||||
|
#define ERR_NORECIPIENT 411
|
||||||
|
#define ERR_NOTEXTTOSEND 412
|
||||||
|
#define ERR_NOTOPLEVEL 413
|
||||||
|
#define ERR_WILDTOPLEVEL 414
|
||||||
|
#define ERR_UNKNOWNCOMMAND 421
|
||||||
|
#define ERR_NOMOTD 422
|
||||||
|
#define ERR_NOADMININFO 423
|
||||||
|
#define ERR_FILEERROR 424
|
||||||
|
#define ERR_NONICKNAMEGIVEN 431
|
||||||
|
#define ERR_ERRONEUSNICKNAME 432
|
||||||
|
#define ERR_NICKNAMEINUSE 433
|
||||||
|
#define ERR_NICKCOLLISION 436
|
||||||
|
#define ERR_USERNOTINCHANNEL 441
|
||||||
|
#define ERR_NOTONCHANNEL 442
|
||||||
|
#define ERR_USERONCHANNEL 443
|
||||||
|
#define ERR_NOLOGIN 444
|
||||||
|
#define ERR_SUMMONDISABLED 445
|
||||||
|
#define ERR_USERSDISABLED 446
|
||||||
|
#define ERR_NOTREGISTERED 451
|
||||||
|
#define ERR_NEEDMOREPARAMS 461
|
||||||
|
#define ERR_ALREADYREGISTRED 462
|
||||||
|
#define ERR_NOPERMFORHOST 463
|
||||||
|
#define ERR_PASSWDMISMATCH 464
|
||||||
|
#define ERR_YOUREBANNEDCREEP 465
|
||||||
|
#define ERR_KEYSET 467
|
||||||
|
#define ERR_CHANNELISFULL 471
|
||||||
|
#define ERR_UNKNOWNMODE 472
|
||||||
|
#define ERR_INVITEONLYCHAN 473
|
||||||
|
#define ERR_BANNEDFROMCHAN 474
|
||||||
|
#define ERR_BADCHANNELKEY 475
|
||||||
|
#define ERR_NOPRIVILEGES 481
|
||||||
|
#define ERR_CHANOPRIVSNEEDED 482
|
||||||
|
#define ERR_CANTKILLSERVER 483
|
||||||
|
#define ERR_NOOPERHOST 491
|
||||||
|
#define ERR_UMODEUNKNOWNFLAG 501
|
||||||
|
#define ERR_USERSDONTMATCH 502
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Replies
|
||||||
|
*/
|
||||||
|
#define RPL_NONE 300
|
||||||
|
#define RPL_USERHOST 302
|
||||||
|
#define RPL_ISON 303
|
||||||
|
#define RPL_AWAY 301
|
||||||
|
#define RPL_UNAWAY 305
|
||||||
|
#define RPL_NOWAWAY 306
|
||||||
|
#define RPL_WHOISUSER 311
|
||||||
|
#define RPL_WHOISSERVER 312
|
||||||
|
#define RPL_WHOISOPERATOR 313
|
||||||
|
#define RPL_WHOISIDLE 317
|
||||||
|
#define RPL_ENDOFWHOIS 318
|
||||||
|
#define RPL_WHOISCHANNELS 319
|
||||||
|
#define RPL_WHOWASUSER 314
|
||||||
|
#define RPL_ENDOFWHOWAS 369
|
||||||
|
#define RPL_LISTSTART 321
|
||||||
|
#define RPL_LIST 322
|
||||||
|
#define RPL_LISTEND 323
|
||||||
|
#define RPL_CHANNELMODEIS 324
|
||||||
|
#define RPL_NOTOPIC 331
|
||||||
|
#define RPL_TOPIC 332
|
||||||
|
#define RPL_WHOISREALIP 338
|
||||||
|
#define RPL_INVITING 341
|
||||||
|
#define RPL_SUMMONING 342
|
||||||
|
#define RPL_VERSION 351
|
||||||
|
#define RPL_WHOREPLY 352
|
||||||
|
#define RPL_ENDOFWHO 315
|
||||||
|
#define RPL_NAMREPLY 353
|
||||||
|
#define RPL_ENDOFNAMES 366
|
||||||
|
#define RPL_LINKS 364
|
||||||
|
#define RPL_ENDOFLINKS 365
|
||||||
|
#define RPL_BANLIST 367
|
||||||
|
#define RPL_ENDOFBANLIST 368
|
||||||
|
#define RPL_INFO 371
|
||||||
|
#define RPL_ENDOFINFO 374
|
||||||
|
#define RPL_MOTDSTART 375
|
||||||
|
#define RPL_MOTD 372
|
||||||
|
#define RPL_ENDOFMOTD 376
|
||||||
|
#define RPL_YOUREOPER 381
|
||||||
|
#define RPL_REHASHING 382
|
||||||
|
#define RPL_TIME 391
|
||||||
|
#define RPL_USERSSTART 392
|
||||||
|
#define RPL_USERS 393
|
||||||
|
#define RPL_ENDOFUSERS 394
|
||||||
|
#define RPL_NOUSERS 395
|
||||||
|
#define RPL_TRACELINK 200
|
||||||
|
#define RPL_TRACECONNECTING 201
|
||||||
|
#define RPL_TRACEHANDSHAKE 202
|
||||||
|
#define RPL_TRACEUNKNOWN 203
|
||||||
|
#define RPL_TRACEOPERATOR 204
|
||||||
|
#define RPL_TRACEUSER 205
|
||||||
|
#define RPL_TRACESERVER 206
|
||||||
|
#define RPL_TRACENEWTYPE 208
|
||||||
|
#define RPL_TRACELOG 261
|
||||||
|
#define RPL_STATSLINKINFO 211
|
||||||
|
#define RPL_STATSCOMMANDS 212
|
||||||
|
#define RPL_STATSCLINE 213
|
||||||
|
#define RPL_STATSNLINE 214
|
||||||
|
#define RPL_STATSILINE 215
|
||||||
|
#define RPL_STATSKLINE 216
|
||||||
|
#define RPL_STATSYLINE 218
|
||||||
|
#define RPL_ENDOFSTATS 219
|
||||||
|
#define RPL_STATSLLINE 241
|
||||||
|
#define RPL_STATSUPTIME 242
|
||||||
|
#define RPL_STATSOLINE 243
|
||||||
|
#define RPL_STATSHLINE 244
|
||||||
|
#define RPL_STATSULINE 246
|
||||||
|
#define RPL_UMODEIS 221
|
||||||
|
#define RPL_LUSERCLIENT 251
|
||||||
|
#define RPL_LUSEROP 252
|
||||||
|
#define RPL_LUSERUNKNOWN 253
|
||||||
|
#define RPL_LUSERCHANNELS 254
|
||||||
|
#define RPL_LUSERME 255
|
||||||
|
#define RPL_ADMINME 256
|
||||||
|
#define RPL_ADMINLOC1 257
|
||||||
|
#define RPL_ADMINLOC2 258
|
||||||
|
#define RPL_ADMINEMAIL 259
|
||||||
|
#define RPL_LUSERLOCAL 265
|
||||||
|
#define RPL_LUSERGLOBAL 266
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
JNL_IRC_RETVAL_OK = 0,
|
||||||
|
JNL_IRC_RETVAL_FAIL
|
||||||
|
}JNL_IRC_RETVAL;
|
||||||
|
|
||||||
|
class JNL_IRCParams
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string middle;
|
||||||
|
std::string trailing;
|
||||||
|
JNL_IRCParams *m_params;
|
||||||
|
|
||||||
|
JNL_IRCParams::JNL_IRCParams()
|
||||||
|
{
|
||||||
|
m_params = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~JNL_IRCParams()
|
||||||
|
{
|
||||||
|
if(m_params)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** delete children first.
|
||||||
|
*/
|
||||||
|
delete m_params;
|
||||||
|
m_params = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class JNL_IRCMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JNL_IRCMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~JNL_IRCMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
std::string m_prefix;
|
||||||
|
std::string m_command;
|
||||||
|
JNL_IRCParams m_params;
|
||||||
|
|
||||||
|
const char *command()
|
||||||
|
{
|
||||||
|
return m_command.c_str();
|
||||||
|
}
|
||||||
|
int messagenum()
|
||||||
|
{
|
||||||
|
if(isdigit(m_command[0]))
|
||||||
|
{
|
||||||
|
return atoi(m_command.c_str());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** JNL_IRCConnection:
|
||||||
|
** sends and receives IRC messages
|
||||||
|
** When run is called, it stores IRC messages in its queue.
|
||||||
|
** After run, you may then call get_message() until there are none (null).
|
||||||
|
**
|
||||||
|
** The JNL_IRCClient exemplifies this in its version
|
||||||
|
** of run.
|
||||||
|
*/
|
||||||
|
class JNL_IRCConnection
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
JNL_Connection *m_con;
|
||||||
|
std::list<JNL_IRCMessage*> m_messagequeue;
|
||||||
|
public:
|
||||||
|
JNL_IRCConnection();
|
||||||
|
virtual ~JNL_IRCConnection();
|
||||||
|
bool connect(char *szHost, unsigned short nPort=6667);
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
m_con->close(1);
|
||||||
|
}
|
||||||
|
bool send_message(const char *fmt,...);
|
||||||
|
bool run(void);
|
||||||
|
JNL_IRCMessage *get_message();
|
||||||
|
protected:
|
||||||
|
bool _process_line(const char *szline);
|
||||||
|
int _parse_paramlist(const char *szline,JNL_IRCParams &p);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** JNL_IRCClient
|
||||||
|
** Very basic, and woefully incomplete client
|
||||||
|
** Here's what it can do, and what you probably should use from this:
|
||||||
|
** Use the 'sending' block of commands
|
||||||
|
** They are, sendpass, nick, oper, quit....etc.
|
||||||
|
**
|
||||||
|
** Next, there are quite a few virtual methods at your disposal to override.
|
||||||
|
** They will be called if this, the base class, JNL_IRCClient's process_message is called.
|
||||||
|
** If you want to short circuit those events, then override process_message and do your own
|
||||||
|
** event dispatching.
|
||||||
|
**
|
||||||
|
** Else, just let JNL_IRCClient's process_message run, and you override the on*** methods.
|
||||||
|
*/
|
||||||
|
class JNL_IRCClient
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
JNL_IRCConnection m_con;
|
||||||
|
public:
|
||||||
|
JNL_IRCClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~JNL_IRCClient()
|
||||||
|
{
|
||||||
|
m_con.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
m_con.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connect(char *szHost, unsigned short nPort=6667)
|
||||||
|
{
|
||||||
|
return m_con.connect(szHost,nPort);
|
||||||
|
}
|
||||||
|
bool run(void);
|
||||||
|
|
||||||
|
virtual JNL_IRC_RETVAL process_message(JNL_IRCMessage &m);
|
||||||
|
|
||||||
|
bool sendpass(char *password);
|
||||||
|
bool nick(char *nick);
|
||||||
|
bool oper(char *user, char *password);
|
||||||
|
bool quit(char *swansong);
|
||||||
|
bool part(char *swansong);
|
||||||
|
bool join(char *channel, char *key=NULL);
|
||||||
|
bool setmode(char *channel, int isadd, char mode, char *param=NULL);
|
||||||
|
bool topic(char *channel, char *topic=NULL);
|
||||||
|
bool userregistration(char *username="poopoo", char *hostname="hostname", char *servername="servername", char *realname="poopoo platter");
|
||||||
|
bool opuser(char *channel, char *nick)
|
||||||
|
{
|
||||||
|
return setmode(channel,1,'o',nick);
|
||||||
|
}
|
||||||
|
bool deopuser(char *channel, char *nick)
|
||||||
|
{
|
||||||
|
return setmode(channel,0,'o',nick);
|
||||||
|
}
|
||||||
|
bool voiceuser(char *channel, char *nick)
|
||||||
|
{
|
||||||
|
return setmode(channel,1,'v',nick);
|
||||||
|
}
|
||||||
|
bool devoiceuser(char *channel, char *nick)
|
||||||
|
{
|
||||||
|
return setmode(channel,0,'v',nick);
|
||||||
|
}
|
||||||
|
bool banuser(char *channel, char *banstring)
|
||||||
|
{
|
||||||
|
return setmode(channel,1,'b',banstring);
|
||||||
|
}
|
||||||
|
bool unbanuser(char *channel, char *banstring)
|
||||||
|
{
|
||||||
|
return setmode(channel,0,'b',banstring);
|
||||||
|
}
|
||||||
|
bool names(char *channel=NULL);
|
||||||
|
bool list(char *channel=NULL);
|
||||||
|
bool invite(char *nick, char *channel);
|
||||||
|
bool kick(char *channel, char *user, char *swansong=NULL);
|
||||||
|
bool version(char *server=NULL);
|
||||||
|
bool stats(char query = 0, char *server=NULL);
|
||||||
|
bool links(char *remote=NULL, char *mask=NULL);
|
||||||
|
bool time(char *server=NULL);
|
||||||
|
/*
|
||||||
|
** Missing trace and connect
|
||||||
|
*/
|
||||||
|
bool admin(char *server=NULL);
|
||||||
|
bool info(char *server=NULL);
|
||||||
|
bool privmsg(char *recipient, char *msg, bool baction=false);
|
||||||
|
bool notice(char *recipient, char *msg);
|
||||||
|
bool who(char *nick, char o=0);
|
||||||
|
bool whois(char *server,char *nick);
|
||||||
|
bool ping(char *server);
|
||||||
|
bool pong(char *server);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Missing whowas and kill, and error
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoSuckNick(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoSuchServer(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoSuchChannel(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrCannotSendToChan(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrTooManyChannels(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrWasNoSuchNick(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrTooManyTargets(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoOrigin(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoRecipient(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoTextToSend(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoTopLevel(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrWildTopLevel(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUnknownCommand(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoMOTD(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoAdminInfo(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrFileError(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoNickNameGiven(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrOneUSNickName(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNickNameInUse(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNickCollision(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNotOnChannel(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUserNotInChannel(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUserOnChannel(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoLogin(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrSummonDisabled(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUserDisabled(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNotRegistered(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNeedMoreParams(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrAlreadyRegistered(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoPermForHost(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrPasswdMismatch(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrYourBannedCreep(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrKeySet(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrChannelIsFull(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUnknownMode(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrInviteOnlyChan(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrBannedFromChan(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrBadChannelKey(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoPrivileges(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrChanOpPrivsNeeded(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrCantKillServer(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrNoOperHost(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUModeUnknownFlag(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onErrUsersDontMatch(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
/*
|
||||||
|
** REPLY BLOCK
|
||||||
|
*/
|
||||||
|
virtual JNL_IRC_RETVAL onRplNone(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplUserHost(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplIsOn(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplAway(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplNoAway(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplUnAway(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoIsUser(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoIsServer(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoIsIdle(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoIsOperator(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfWhoIs(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoIsChannels(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoWasUser(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfWhoWas(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplListStart(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplList(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplListEnd(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplChannelModeIs(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplNoTopic(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTopic(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoIsRealIP(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplInviting(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplSummoning(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplVersion(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplWhoReply(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndWho(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplNameReply(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfNames(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLinks(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfLinks(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplBanList(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfBanList(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplInfo(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEnofOfInfo(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplMOTDStart(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplMOTD(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfMOTD(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplYoureOper(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplRehasing(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTime(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplUserStart(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplUser(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfUsers(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplNoUsers(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceLink(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceConnecting(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceHandleShake(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceUnknown(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceOperator(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceUser(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceServer(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceNewType(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplTraceLog(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsLinkInfo(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsCommands(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsCLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsNLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsILine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsKLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsYLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplEndOfStats(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsLLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsUptime(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsOLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsHLine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplStatsULine(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplUModeIs(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserClient(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserOp(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserUknown(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserChannels(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserMe(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplAdminMe(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplAdminLoc1(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplAdminLoc2(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplAdminEmail(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserLocal(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onRplLUserGlobal(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Messages from server
|
||||||
|
*/
|
||||||
|
virtual JNL_IRC_RETVAL onJoin(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onPart(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onMode(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onTopic(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onInvite(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onKick(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onStats(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onPrivMsg(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
virtual JNL_IRC_RETVAL onNotice(JNL_IRCMessage &m){m.messagenum();return JNL_IRC_RETVAL_OK;};
|
||||||
|
/*
|
||||||
|
** Don't override this one (onPing), or if you do...make sure you call the base class.
|
||||||
|
*/
|
||||||
|
virtual JNL_IRC_RETVAL onPing(JNL_IRCMessage &m){pong((char*)m.m_params.trailing.c_str());return JNL_IRC_RETVAL_OK;};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
||||||
50
foo_httpcontrol/lib/jnetlib/jnetlib.h
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2003 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: jnetlib.h - JNL main include file (not really necessary).
|
||||||
|
**
|
||||||
|
** For documentation, look at the following files:
|
||||||
|
** Generic network initialization: netinc.h
|
||||||
|
** DNS: asyncdns.h
|
||||||
|
** TCP connections: connection.h
|
||||||
|
** HTTP GET connections: httpget.h
|
||||||
|
** TCP listen: listen.h
|
||||||
|
**
|
||||||
|
** license:
|
||||||
|
**
|
||||||
|
** This software is provided 'as-is', without any express or implied
|
||||||
|
** warranty. In no event will the authors be held liable for any damages
|
||||||
|
** arising from the use of this software.
|
||||||
|
**
|
||||||
|
** Permission is granted to anyone to use this software for any purpose,
|
||||||
|
** including commercial applications, and to alter it and redistribute it
|
||||||
|
** freely, subject to the following restrictions:
|
||||||
|
**
|
||||||
|
** 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
** claim that you wrote the original software. If you use this software
|
||||||
|
** in a product, an acknowledgment in the product documentation would be
|
||||||
|
** appreciated but is not required.
|
||||||
|
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
** misrepresented as being the original software.
|
||||||
|
** 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _JNETLIB_H_
|
||||||
|
#define _JNETLIB_H_
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "asyncdns.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include "sslconnection.h"
|
||||||
|
#include "httpget.h"
|
||||||
|
#include "httppost.h"
|
||||||
|
#include "httpserv.h"
|
||||||
|
#include "listen.h"
|
||||||
|
#include "ssllisten.h"
|
||||||
|
|
||||||
|
#endif//_JNETLIB_H_
|
||||||
168
foo_httpcontrol/lib/jnetlib/jnetlib.vcxproj
Executable file
@@ -0,0 +1,168 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release-speed|Win32">
|
||||||
|
<Configuration>Release-speed</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{7020DA42-3C98-4B37-89D2-683B32EE2DB8}</ProjectGuid>
|
||||||
|
<RootNamespace>jnetlib</RootNamespace>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-speed|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<PlatformToolset>v100</PlatformToolset>
|
||||||
|
<UseOfMfc>Static</UseOfMfc>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-speed|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)build\$(Configuration)\lib\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)build\$(Configuration)\lib\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
|
||||||
|
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release-speed|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
|
||||||
|
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release-speed|Win32'">$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<MinimalRebuild>true</MinimalRebuild>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||||
|
</ClCompile>
|
||||||
|
<Lib>
|
||||||
|
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
</Lib>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>false</IntrinsicFunctions>
|
||||||
|
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
|
||||||
|
<OmitFramePointers>false</OmitFramePointers>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||||
|
</ClCompile>
|
||||||
|
<Lib>
|
||||||
|
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
</Lib>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-speed|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Full</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
|
<OmitFramePointers>true</OmitFramePointers>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
</ClCompile>
|
||||||
|
<Lib>
|
||||||
|
<AdditionalDependencies>wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
</Lib>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="asyncdns.cpp" />
|
||||||
|
<ClCompile Include="connection.cpp" />
|
||||||
|
<ClCompile Include="httpget.cpp" />
|
||||||
|
<ClCompile Include="httppost.cpp" />
|
||||||
|
<ClCompile Include="httpserv.cpp" />
|
||||||
|
<ClCompile Include="ircclient.cpp" />
|
||||||
|
<ClCompile Include="listen.cpp" />
|
||||||
|
<ClCompile Include="sslconnection.cpp" />
|
||||||
|
<ClCompile Include="ssllisten.cpp" />
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release-speed|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="testbnc.cpp" />
|
||||||
|
<ClCompile Include="util.cpp" />
|
||||||
|
<ClCompile Include="webserver.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="asyncdns.h" />
|
||||||
|
<ClInclude Include="connection.h" />
|
||||||
|
<ClInclude Include="httpget.h" />
|
||||||
|
<ClInclude Include="httppost.h" />
|
||||||
|
<ClInclude Include="httpserv.h" />
|
||||||
|
<ClInclude Include="ircclient.h" />
|
||||||
|
<ClInclude Include="jnetlib.h" />
|
||||||
|
<ClInclude Include="listen.h" />
|
||||||
|
<ClInclude Include="netinc.h" />
|
||||||
|
<ClInclude Include="sslconnection.h" />
|
||||||
|
<ClInclude Include="ssllisten.h" />
|
||||||
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<ClInclude Include="udpconnection.h" />
|
||||||
|
<ClInclude Include="util.h" />
|
||||||
|
<ClInclude Include="webserver.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
3
foo_httpcontrol/lib/jnetlib/jnetlib.vcxproj.user
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
</Project>
|
||||||
75
foo_httpcontrol/lib/jnetlib/listen.cpp
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: listen.cpp - JNL TCP listen implementation
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "listen.h"
|
||||||
|
|
||||||
|
JNL_Listen::JNL_Listen(short port, unsigned long which_interface)
|
||||||
|
{
|
||||||
|
m_port=port;
|
||||||
|
m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (m_socket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
SET_SOCK_BLOCK(m_socket,1);
|
||||||
|
#ifndef _WIN32
|
||||||
|
int bflag = 1;
|
||||||
|
setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &bflag, sizeof(bflag));
|
||||||
|
#endif
|
||||||
|
memset((char *) &sin, 0,sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons( (short) port );
|
||||||
|
sin.sin_addr.s_addr = which_interface?which_interface:INADDR_ANY;
|
||||||
|
if (::bind(m_socket,(struct sockaddr *)&sin,sizeof(sin)))
|
||||||
|
{
|
||||||
|
::closesocket(m_socket); //IE9
|
||||||
|
m_socket=-1; //IE9
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (::listen(m_socket,8)==-1)
|
||||||
|
{
|
||||||
|
::closesocket(m_socket);
|
||||||
|
m_socket=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_Listen::~JNL_Listen()
|
||||||
|
{
|
||||||
|
if (m_socket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
closesocket(m_socket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_Connection *JNL_Listen::get_connect(int sendbufsize, int recvbufsize)
|
||||||
|
{
|
||||||
|
if (m_socket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
socklen_t length = sizeof(struct sockaddr_in);
|
||||||
|
SOCKET s = accept(m_socket, (struct sockaddr *) &saddr, &length);
|
||||||
|
|
||||||
|
if (s != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
JNL_Connection *c=new JNL_Connection(NULL,sendbufsize, recvbufsize);
|
||||||
|
c->connect(s,&saddr);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
39
foo_httpcontrol/lib/jnetlib/listen.h
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: listen.h - JNL interface for opening a TCP listen
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** Usage:
|
||||||
|
** 1. create a JNL_Listen object with the port and (optionally) the interface
|
||||||
|
** to listen on.
|
||||||
|
** 2. call get_connect() to get any new connections (optionally specifying what
|
||||||
|
** buffer sizes the connection should be created with)
|
||||||
|
** 3. check is_error() to see if an error has occured
|
||||||
|
** 4. call port() if you forget what port the listener is on.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LISTEN_H_
|
||||||
|
#define _LISTEN_H_
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
class JNL_Listen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JNL_Listen(short port, unsigned long which_interface=0);
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/28/2006
|
||||||
|
*/
|
||||||
|
virtual ~JNL_Listen();
|
||||||
|
virtual JNL_Connection *get_connect(int sendbufsize=8192, int recvbufsize=8192);
|
||||||
|
short port(void) { return m_port; }
|
||||||
|
bool is_error(void) { return m_socket == INVALID_SOCKET; }
|
||||||
|
|
||||||
|
SOCKET m_socket; // int m_socket
|
||||||
|
protected:
|
||||||
|
short m_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_LISTEN_H_
|
||||||
80
foo_httpcontrol/lib/jnetlib/netinc.h
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: netinc.h - network includes and portability defines (used internally)
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Undefine this if you don't want SSL compiled in
|
||||||
|
*/
|
||||||
|
//#define _JNETLIB_SSL_ 1
|
||||||
|
|
||||||
|
#ifndef _NETINC_H_
|
||||||
|
#define _NETINC_H_
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#define strcasecmp(x,y) stricmp(x,y)
|
||||||
|
#define ERRNO (WSAGetLastError())
|
||||||
|
#define SET_SOCK_BLOCK(s,block) { unsigned long __i=block?0:1; ioctlsocket(s,FIONBIO,&__i); }
|
||||||
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
|
#define EINPROGRESS WSAEWOULDBLOCK
|
||||||
|
typedef int socklen_t;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef THREAD_SAFE
|
||||||
|
#define THREAD_SAFE
|
||||||
|
#endif
|
||||||
|
#ifndef _REENTRANT
|
||||||
|
#define _REENTRANT
|
||||||
|
#endif
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ERRNO errno
|
||||||
|
//#define closesocket(s) close(s)
|
||||||
|
#define SET_SOCK_BLOCK(s,block) { int __flags; if ((__flags = fcntl(s, F_GETFL, 0)) != -1) { if (!block) __flags |= O_NONBLOCK; else __flags &= ~O_NONBLOCK; fcntl(s, F_SETFL, __flags); } }
|
||||||
|
|
||||||
|
#define stricmp(x,y) strcasecmp(x,y)
|
||||||
|
#define strnicmp(x,y,z) strncasecmp(x,y,z)
|
||||||
|
#define wsprintf sprintf
|
||||||
|
|
||||||
|
#ifdef MACOSX
|
||||||
|
typedef int socklen_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // !_WIN32
|
||||||
|
|
||||||
|
#ifndef INADDR_NONE
|
||||||
|
#define INADDR_NONE 0xffffffff
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INADDR_ANY
|
||||||
|
#define INADDR_ANY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SHUT_RDWR
|
||||||
|
#define SHUT_RDWR 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //_NETINC_H_
|
||||||
324
foo_httpcontrol/lib/jnetlib/sslconnection.cpp
Executable file
@@ -0,0 +1,324 @@
|
|||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include "sslconnection.h"
|
||||||
|
|
||||||
|
#ifdef _JNETLIB_SSL_
|
||||||
|
SSL_CTX *sslContext = 0;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
|
||||||
|
extern "C" void apps_ssl_info_callback (const SSL * s, int where, int ret)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** DEBUG INFO HERE
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Well, you should probably change this based on like...
|
||||||
|
** well, you're level of trust heh
|
||||||
|
** For now, this basically trusts all certs :)
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
extern "C" int verify_callback(int ok, X509_STORE_CTX * ctx)
|
||||||
|
{
|
||||||
|
/* For certificate verification */
|
||||||
|
int verify_depth = 0;
|
||||||
|
int verify_error = X509_V_OK;
|
||||||
|
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
X509 * err_cert = X509_STORE_CTX_get_current_cert(ctx);
|
||||||
|
int err = X509_STORE_CTX_get_error(ctx);
|
||||||
|
int depth = X509_STORE_CTX_get_error_depth(ctx);
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (verify_depth >= depth)
|
||||||
|
{
|
||||||
|
ok = 1;
|
||||||
|
verify_error = X509_V_OK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok = 0;
|
||||||
|
verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (ctx->error)
|
||||||
|
{
|
||||||
|
|
||||||
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||||
|
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, sizeof(buf));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||||
|
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||||
|
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_SSL_Connection::JNL_SSL_Connection(SSL* pssl, JNL_AsyncDNS *dns, int sendbufsize, int recvbufsize) : JNL_Connection(dns, sendbufsize, recvbufsize),
|
||||||
|
forceConnect(false)
|
||||||
|
{
|
||||||
|
m_ssl = pssl;
|
||||||
|
m_bsslinit = false;
|
||||||
|
|
||||||
|
if (m_ssl)
|
||||||
|
{
|
||||||
|
m_bcontextowned = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_bcontextowned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bcontextowned == false)
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bsslinit = true;
|
||||||
|
|
||||||
|
/* See the SSL states in our own callback */
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// SSL_CTX_set_info_callback(m_app_ctx, apps_ssl_info_callback);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set the certificate verification callback */
|
||||||
|
//SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER, verify_callback);
|
||||||
|
|
||||||
|
/* Not sure what this does */
|
||||||
|
//SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_CLIENT);
|
||||||
|
|
||||||
|
if(sslContext == NULL)
|
||||||
|
{
|
||||||
|
SSL_METHOD * meth = NULL;
|
||||||
|
SSLeay_add_ssl_algorithms();
|
||||||
|
SSL_load_error_strings();
|
||||||
|
meth = SSLv23_client_method();
|
||||||
|
|
||||||
|
if ((sslContext = SSL_CTX_new(meth)) == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_SSL_Connection::socket_connect()
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (m_bcontextowned == false)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** WTF?
|
||||||
|
*/
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (m_ssl != NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = JNL_Connection::socket_connect();
|
||||||
|
|
||||||
|
if (retval != 0)
|
||||||
|
{
|
||||||
|
if (ERRNO != EINPROGRESS)
|
||||||
|
{
|
||||||
|
return retval; // benski> if the underlying socket hasn't connected yet, then we can't start the SSL connection
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 3/2/2006
|
||||||
|
** Fatal error here
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ssl = SSL_new(sslContext);
|
||||||
|
|
||||||
|
if (m_ssl == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell that we are in connect mode */
|
||||||
|
SSL_set_connect_state(m_ssl);
|
||||||
|
|
||||||
|
/* Set socket descriptor with the socket we already have open */
|
||||||
|
if(SSL_set_fd(m_ssl, m_socket) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
void JNL_SSL_Connection::socket_shutdown()
|
||||||
|
{
|
||||||
|
if (m_ssl)
|
||||||
|
SSL_shutdown(m_ssl);
|
||||||
|
JNL_Connection::socket_shutdown();
|
||||||
|
|
||||||
|
if (m_ssl)
|
||||||
|
{
|
||||||
|
SSL_free(m_ssl);
|
||||||
|
m_ssl = NULL;
|
||||||
|
}
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL_SSL_Connection::run(int max_send_bytes, int max_recv_bytes, int *bytes_sent, int *bytes_rcvd)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!m_bsslinit)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
int e = 0;
|
||||||
|
|
||||||
|
rval = SSL_accept(m_ssl);
|
||||||
|
|
||||||
|
if (rval == -1)
|
||||||
|
{
|
||||||
|
e = SSL_get_error(m_ssl, rval);
|
||||||
|
|
||||||
|
if (!((e == SSL_ERROR_WANT_READ) || (e == SSL_ERROR_WANT_WRITE)))
|
||||||
|
{
|
||||||
|
m_state = STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_bsslinit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** benski - march 2, 2006
|
||||||
|
**if the underlying socket didn't connected yet, we need to try the SSL connection again
|
||||||
|
*/
|
||||||
|
if (forceConnect)
|
||||||
|
{
|
||||||
|
if(init_ssl_connection() == false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JNL_Connection::run(max_send_bytes, max_recv_bytes, bytes_sent, bytes_rcvd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** init_ssl_connection:
|
||||||
|
** Returns true, meaning can continue
|
||||||
|
** Else, cannot continue with underlying run
|
||||||
|
** side effects:
|
||||||
|
** sets forceConnect
|
||||||
|
*/
|
||||||
|
bool JNL_SSL_Connection::init_ssl_connection()
|
||||||
|
{
|
||||||
|
if(m_ssl == NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** WTF?
|
||||||
|
** cascade up.
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int retval = SSL_connect(m_ssl);
|
||||||
|
|
||||||
|
if (retval < 0)
|
||||||
|
{
|
||||||
|
int err = SSL_get_error(m_ssl, retval);
|
||||||
|
|
||||||
|
switch (err)
|
||||||
|
{
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
case SSL_ERROR_WANT_CONNECT:
|
||||||
|
forceConnect = true;
|
||||||
|
break;
|
||||||
|
// fall through
|
||||||
|
default: // TODO: benski> MOST other errors are OK, (especially "want read" and "want write", but we need to think through all the scenarios here
|
||||||
|
forceConnect=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(retval)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** success
|
||||||
|
*/
|
||||||
|
forceConnect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If retval == 0
|
||||||
|
** socket is closed, or serious error occurred.
|
||||||
|
** cascade up.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return forceConnect==false;
|
||||||
|
}
|
||||||
|
void JNL_SSL_Connection::on_socket_connected(void)
|
||||||
|
{
|
||||||
|
init_ssl_connection();
|
||||||
|
}
|
||||||
|
void JNL_SSL_Connection::connect(int s, struct sockaddr_in *loc)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 2/01/2006
|
||||||
|
** No need to close
|
||||||
|
** This is the reason for divergence as well as setting
|
||||||
|
** the connect state
|
||||||
|
*/
|
||||||
|
|
||||||
|
m_socket = s;
|
||||||
|
m_remote_port = 0;
|
||||||
|
m_dns = NULL;
|
||||||
|
if (loc) *m_saddr = *loc;
|
||||||
|
else memset(m_saddr, 0, sizeof(m_saddr));
|
||||||
|
if (m_socket != -1)
|
||||||
|
{
|
||||||
|
SET_SOCK_BLOCK(m_socket, 0);
|
||||||
|
m_state = STATE_CONNECTED;
|
||||||
|
SSL_set_fd(m_ssl, m_socket);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_errorstr = "invalid socket passed to connect";
|
||||||
|
m_state = STATE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_SSL_Connection::socket_recv(char *buf, int len, int options)
|
||||||
|
{
|
||||||
|
return SSL_read(m_ssl, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int JNL_SSL_Connection::socket_send(char *buf, int len, int options)
|
||||||
|
{
|
||||||
|
return SSL_write(m_ssl, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_SSL_Connection::~JNL_SSL_Connection()
|
||||||
|
{
|
||||||
|
if (m_ssl)
|
||||||
|
{
|
||||||
|
SSL_free(m_ssl);
|
||||||
|
m_ssl = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
63
foo_httpcontrol/lib/jnetlib/sslconnection.h
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2006 CockOS, Inc.
|
||||||
|
** Author: Justin Frankel, Joshua Teitelbaum
|
||||||
|
** File: sslconnection.h - JNL SSL TCP connection interface
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
#ifdef _JNETLIB_SSL_
|
||||||
|
|
||||||
|
#ifndef _JNETLIB_SSL_H_
|
||||||
|
#define _JNETLIB_SSL_H_
|
||||||
|
/*
|
||||||
|
** AUTOLINK WITH THESE GUYS NOT IN PROJECT HEH HEH :)
|
||||||
|
** Build and go, for you :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma comment(lib,"libeay32.lib")
|
||||||
|
#pragma comment(lib,"ssleay32.lib")
|
||||||
|
#pragma comment(lib,"ADVAPI32.LIB")
|
||||||
|
#pragma comment(lib,"USER32.LIB")
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
|
||||||
|
class JNL_SSL_Connection : public JNL_Connection
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SSL *m_ssl;
|
||||||
|
bool m_bcontextowned;
|
||||||
|
bool m_bsslinit;
|
||||||
|
public:
|
||||||
|
JNL_SSL_Connection(SSL* pssl = NULL,JNL_AsyncDNS *dns=JNL_CONNECTION_AUTODNS, int sendbufsize=8192, int recvbufsize=8192);
|
||||||
|
|
||||||
|
//JNL_SSL_Connection(SSL* pssl = NULL,api_dns *dns=API_DNS_AUTODNS, int sendbufsize=8192, int recvbufsize=8192);
|
||||||
|
virtual ~JNL_SSL_Connection();
|
||||||
|
virtual void connect(int sock, struct sockaddr_in *loc=NULL); // used by the listen object, usually not needed by users.
|
||||||
|
virtual void run(int max_send_bytes=-1, int max_recv_bytes=-1, int *bytes_sent=NULL, int *bytes_rcvd=NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006 Adding new BSD socket analogues for SSL compatibility
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
virtual void socket_shutdown();
|
||||||
|
virtual int socket_recv(char *buf, int len, int options);
|
||||||
|
virtual int socket_send(char *buf, int len, int options);
|
||||||
|
virtual int socket_connect();
|
||||||
|
virtual void on_socket_connected();
|
||||||
|
/*
|
||||||
|
** init_ssl_connection:
|
||||||
|
** returns true if can continue onwards (could be error, in which case
|
||||||
|
** we want the error to cascade through).
|
||||||
|
** Else, false if connection was not made, and we have to call this
|
||||||
|
** again.
|
||||||
|
*/
|
||||||
|
bool init_ssl_connection();
|
||||||
|
|
||||||
|
bool forceConnect;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SSL_CTX *sslContext;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
135
foo_httpcontrol/lib/jnetlib/ssllisten.cpp
Executable file
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2006 CockOS, Inc.
|
||||||
|
** Author: Justin Frankel, Joshua Teitelbaum
|
||||||
|
** File: ssllisten.cpp - JNL SSL TCP listen implementation
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "ssllisten.h"
|
||||||
|
|
||||||
|
#ifdef _JNETLIB_SSL_
|
||||||
|
|
||||||
|
|
||||||
|
JNL_SSL_Listen::JNL_SSL_Listen(short port, unsigned long which_interface, const char *certpath, const char *privatekeypath) :
|
||||||
|
JNL_Listen(port,which_interface) ,m_app_ctx(NULL)
|
||||||
|
{
|
||||||
|
SSL_METHOD *p_ssl_method;
|
||||||
|
m_lasterror[0] = 0;
|
||||||
|
unsigned long e;
|
||||||
|
|
||||||
|
if(m_socket <= 0 || (certpath==NULL) || (privatekeypath==NULL))
|
||||||
|
{
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_load_error_strings();
|
||||||
|
SSLeay_add_ssl_algorithms();
|
||||||
|
|
||||||
|
p_ssl_method = SSLv23_server_method();
|
||||||
|
m_app_ctx = SSL_CTX_new (p_ssl_method);
|
||||||
|
|
||||||
|
if (!m_app_ctx)
|
||||||
|
{
|
||||||
|
e = ERR_get_error();
|
||||||
|
ERR_error_string_n(e, m_lasterror, sizeof(m_lasterror) - 1);
|
||||||
|
|
||||||
|
if (m_socket>=0)
|
||||||
|
{
|
||||||
|
closesocket(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_CTX_use_certificate_file(m_app_ctx, certpath, SSL_FILETYPE_PEM) <= 0)
|
||||||
|
{
|
||||||
|
e = ERR_get_error();
|
||||||
|
ERR_error_string_n(e, m_lasterror, sizeof(m_lasterror) - 1);
|
||||||
|
if (m_socket>=0)
|
||||||
|
{
|
||||||
|
closesocket(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_CTX_use_RSAPrivateKey_file(m_app_ctx, privatekeypath, SSL_FILETYPE_PEM) <= 0)
|
||||||
|
{
|
||||||
|
e = ERR_get_error();
|
||||||
|
ERR_error_string_n(e, m_lasterror, sizeof(m_lasterror) - 1);
|
||||||
|
if (m_socket>=0)
|
||||||
|
{
|
||||||
|
closesocket(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SSL_CTX_check_private_key(m_app_ctx))
|
||||||
|
{
|
||||||
|
e = ERR_get_error();
|
||||||
|
ERR_error_string_n(e, m_lasterror, sizeof(m_lasterror) - 1);
|
||||||
|
if (m_socket>=0)
|
||||||
|
{
|
||||||
|
closesocket(m_socket);
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_SSL_Listen::~JNL_SSL_Listen()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL_Connection *JNL_SSL_Listen::get_connect(int sendbufsize, int recvbufsize)
|
||||||
|
{
|
||||||
|
if(m_app_ctx == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_socket < 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
socklen_t length = sizeof(struct sockaddr_in);
|
||||||
|
int s = accept(m_socket, (struct sockaddr *) &saddr, &length);
|
||||||
|
|
||||||
|
if(s == -1)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SSL* p_ssl = SSL_new(m_app_ctx);
|
||||||
|
|
||||||
|
if( p_ssl == NULL || m_socket < 0)
|
||||||
|
{
|
||||||
|
sprintf(m_lasterror,"Could not create SSL Context");
|
||||||
|
|
||||||
|
(m_socket>=0) ? closesocket(m_socket) : 0;
|
||||||
|
m_socket = -1;
|
||||||
|
|
||||||
|
if(p_ssl != NULL)
|
||||||
|
SSL_free(p_ssl);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
JNL_Connection *c=new JNL_SSL_Connection(p_ssl,NULL,sendbufsize, recvbufsize);
|
||||||
|
c->connect(s,&saddr);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
50
foo_httpcontrol/lib/jnetlib/ssllisten.h
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel, Joshua Teitelbaum
|
||||||
|
** File: ssllisten.h - JNL interface for opening a SSL TCP listen
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** Usage:
|
||||||
|
** 1. create a JNL_Listen object with the port and (optionally) the interface
|
||||||
|
** to listen on.
|
||||||
|
** 2. call get_connect() to get any new connections (optionally specifying what
|
||||||
|
** buffer sizes the connection should be created with)
|
||||||
|
** 3. check is_error() to see if an error has occured
|
||||||
|
** 4. call port() if you forget what port the listener is on.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
#include "listen.h"
|
||||||
|
#ifdef _JNETLIB_SSL_
|
||||||
|
|
||||||
|
#ifndef _SSL_LISTEN_H_
|
||||||
|
#define _SSL_LISTEN_H_
|
||||||
|
#include "sslconnection.h"
|
||||||
|
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/conf.h>
|
||||||
|
|
||||||
|
class JNL_SSL_Listen : public JNL_Listen
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SSL_CTX *m_app_ctx;
|
||||||
|
char m_lasterror[1024];
|
||||||
|
|
||||||
|
public:
|
||||||
|
JNL_SSL_Listen(short port, unsigned long which_interface=0,const char *certpath=NULL, const char *privatekeypath=NULL);
|
||||||
|
virtual ~JNL_SSL_Listen();
|
||||||
|
|
||||||
|
virtual JNL_Connection *get_connect(int sendbufsize=8192, int recvbufsize=8192);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_SSL_LISTEN_H_
|
||||||
|
#endif //_JNETLIB_SSL_
|
||||||
|
|
||||||
8
foo_httpcontrol/lib/jnetlib/stdafx.cpp
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
// stdafx.cpp : source file that includes just the standard includes
|
||||||
|
// jnetlib.pch will be the pre-compiled header
|
||||||
|
// stdafx.obj will contain the pre-compiled type information
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
// TODO: reference any additional headers you need in STDAFX.H
|
||||||
|
// and not in this file
|
||||||
13
foo_httpcontrol/lib/jnetlib/stdafx.h
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
// stdafx.h : include file for standard system include files,
|
||||||
|
// or project specific include files that are used frequently, but
|
||||||
|
// are changed infrequently
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: reference additional headers your program requires here
|
||||||
102
foo_httpcontrol/lib/jnetlib/testbnc.cpp
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: testbnc.cpp - JNL network bounce test code
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#define Sleep(x) usleep((x)*1000)
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "jnetlib.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
JNL_Connection *cons[32]={0,};
|
||||||
|
JNL_Connection *outcons[32]={0,};
|
||||||
|
int n_cons=0;
|
||||||
|
|
||||||
|
if (argc != 4 || !atoi(argv[1]) || !atoi(argv[3]) || !argv[2][0])
|
||||||
|
{
|
||||||
|
printf("usage: redir localport host remoteport\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNL::open_socketlib();
|
||||||
|
JNL_AsyncDNS dns;
|
||||||
|
JNL_Listen l((short)atoi(argv[1]));
|
||||||
|
printf("running...\n");
|
||||||
|
while (!l.is_error())
|
||||||
|
{
|
||||||
|
Sleep(10);
|
||||||
|
if (n_cons<32)
|
||||||
|
{
|
||||||
|
JNL_Connection *con=l.get_connect();
|
||||||
|
if (con)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < 32; x ++)
|
||||||
|
{
|
||||||
|
if (!cons[x])
|
||||||
|
{
|
||||||
|
outcons[x]=new JNL_Connection();
|
||||||
|
outcons[x]->connect(argv[2],atoi(argv[3]));
|
||||||
|
cons[x]=con;
|
||||||
|
char host[256];
|
||||||
|
JNL::addr_to_ipstr(cons[x]->get_remote(),host,sizeof(host));
|
||||||
|
n_cons++;
|
||||||
|
printf("Connection %d (%s) opened (%d).\n",x,host,n_cons);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < 32; x ++)
|
||||||
|
{
|
||||||
|
if (cons[x])
|
||||||
|
{
|
||||||
|
cons[x]->run();
|
||||||
|
outcons[x]->run();
|
||||||
|
|
||||||
|
int cerr=(cons[x]->get_state() == JNL_Connection::STATE_ERROR || cons[x]->get_state()==JNL_Connection::STATE_CLOSED);
|
||||||
|
int oerr=(outcons[x]->get_state() == JNL_Connection::STATE_ERROR || outcons[x]->get_state()==JNL_Connection::STATE_CLOSED);
|
||||||
|
|
||||||
|
if ((!outcons[x]->send_bytes_in_queue() && !cons[x]->recv_bytes_available() && cerr) ||
|
||||||
|
(!cons[x]->send_bytes_in_queue() && !outcons[x]->recv_bytes_available() && oerr) ||
|
||||||
|
(cerr && oerr))
|
||||||
|
{
|
||||||
|
char host[256];
|
||||||
|
JNL::addr_to_ipstr(cons[x]->get_remote(),host,sizeof(host));
|
||||||
|
delete cons[x];
|
||||||
|
delete outcons[x];
|
||||||
|
outcons[x]=0;
|
||||||
|
cons[x]=0;
|
||||||
|
n_cons--;
|
||||||
|
printf("Connection %d (%s) closed (%d)\n",x,host,n_cons);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
int l;
|
||||||
|
l=outcons[x]->send_bytes_available();
|
||||||
|
if (l > 4096) l=4096;
|
||||||
|
if (l) l=cons[x]->recv_bytes(buf,l);
|
||||||
|
if (l) outcons[x]->send(buf,l);
|
||||||
|
|
||||||
|
l=cons[x]->send_bytes_available();
|
||||||
|
if (l > 4096) l=4096;
|
||||||
|
if (l) l=outcons[x]->recv_bytes(buf,l);
|
||||||
|
if (l) cons[x]->send(buf,l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
JNL::close_socketlib();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
32
foo_httpcontrol/lib/jnetlib/udpconnection.h
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2006 CockOS, Inc.
|
||||||
|
** Author: Justin Frankel, Joshua Teitelbaum
|
||||||
|
** File: udpconnection.h - JNL SSL TCP connection interface
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UDPCONNECTION_H_
|
||||||
|
#define _UDPCONNECTION_H_
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
class JNL_UDP_Connection : public JNL_Connection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JNL_UDP_Connection(struct sockaddr_in *listenon, JNL_AsyncDNS *dns=JNL_CONNECTION_AUTODNS, int sendbufsize=8192, int recvbufsize=8192);
|
||||||
|
virtual ~JNL_UDP_Connection();
|
||||||
|
virtual void connect(int sock, struct sockaddr_in *loc=NULL); // used by the listen object, usually not needed by users.
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Joshua Teitelbaum 1/27/2006 Adding new BSD socket analogues for SSL compatibility
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
virtual void socket_shutdown();
|
||||||
|
virtual int socket_recv(char *buf, int len, int options);
|
||||||
|
virtual int socket_send(char *buf, int len, int options);
|
||||||
|
virtual int socket_connect();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
||||||
36
foo_httpcontrol/lib/jnetlib/util.cpp
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: util.cpp - JNL implementation of basic network utilities
|
||||||
|
** License: see jnetlib.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "netinc.h"
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int JNL::open_socketlib()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSADATA wsaData;
|
||||||
|
if (WSAStartup(MAKEWORD(1, 1), &wsaData)) return 1;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void JNL::close_socketlib()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
unsigned long JNL::ipstr_to_addr(const char *cp)
|
||||||
|
{
|
||||||
|
return ::inet_addr(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNL::addr_to_ipstr(unsigned long addr, char *host, int maxhostlen)
|
||||||
|
{
|
||||||
|
struct in_addr a; a.s_addr=addr;
|
||||||
|
char *p=::inet_ntoa(a); strncpy(host,p?p:"",maxhostlen);
|
||||||
|
}
|
||||||
39
foo_httpcontrol/lib/jnetlib/util.h
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2001 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: util.h - JNL interface for basic network utilities
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** routines you may be interested in:
|
||||||
|
** JNL::open_socketlib();
|
||||||
|
** opens the socket library. Call this once before using any network
|
||||||
|
** code. If you create a new thread, call this again. Only really an
|
||||||
|
** issue for Win32 support, but use it anyway for portability/
|
||||||
|
**
|
||||||
|
** JNL::close_Socketlib();
|
||||||
|
** closes the socketlib. Call this when you're done with the network,
|
||||||
|
** after all your JNetLib objects have been destroyed.
|
||||||
|
**
|
||||||
|
** unsigned long JNL::ipstr_to_addr(const char *cp);
|
||||||
|
** gives you the integer representation of a ip address in dotted
|
||||||
|
** decimal form.
|
||||||
|
**
|
||||||
|
** JNL::addr_to_ipstr(unsigned long addr, char *host, int maxhostlen);
|
||||||
|
** gives you the dotted decimal notation of an integer ip address.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UTIL_H_
|
||||||
|
#define _UTIL_H_
|
||||||
|
|
||||||
|
class JNL
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int open_socketlib();
|
||||||
|
static void close_socketlib();
|
||||||
|
static unsigned long ipstr_to_addr(const char *cp);
|
||||||
|
static void addr_to_ipstr(unsigned long addr, char *host, int maxhostlen);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_UTIL_H_
|
||||||
376
foo_httpcontrol/lib/jnetlib/webserver.cpp
Executable file
@@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2000-2003 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: webserver.cpp - Generic simple webserver baseclass
|
||||||
|
** License: see jnetlib.h
|
||||||
|
** see test.cpp for an example of how to use this class
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "jnetlib.h"
|
||||||
|
#include "webserver.h"
|
||||||
|
|
||||||
|
class WS_ItemList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WS_ItemList() { m_size=0; m_list=0; }
|
||||||
|
~WS_ItemList() { ::free(m_list); }
|
||||||
|
|
||||||
|
void *Add(void *i);
|
||||||
|
void *Get(int w);
|
||||||
|
void Del(int idx);
|
||||||
|
int GetSize(void) { return m_size; }
|
||||||
|
protected:
|
||||||
|
void **m_list;
|
||||||
|
int m_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WS_conInst
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WS_conInst(JNL_Connection *c, int which_port);
|
||||||
|
~WS_conInst();
|
||||||
|
|
||||||
|
// these will be used by WebServerBaseClass::onConnection yay
|
||||||
|
JNL_HTTPServ m_serv;
|
||||||
|
IPageGenerator *m_pagegen;
|
||||||
|
|
||||||
|
|
||||||
|
int m_port; // port this came in on
|
||||||
|
time_t m_connect_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *WS_ItemList::Add(void *i)
|
||||||
|
{
|
||||||
|
if (!m_list || !(m_size&31))
|
||||||
|
{
|
||||||
|
m_list=(void**)::realloc(m_list,sizeof(void*)*(m_size+32));
|
||||||
|
}
|
||||||
|
m_list[m_size++]=i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
void *WS_ItemList::Get(int w) { if (w >= 0 && w < m_size) return m_list[w]; return NULL; }
|
||||||
|
|
||||||
|
void WS_ItemList::Del(int idx)
|
||||||
|
{
|
||||||
|
if (m_list && idx >= 0 && idx < m_size)
|
||||||
|
{
|
||||||
|
m_size--;
|
||||||
|
if (idx != m_size) ::memcpy(m_list+idx,m_list+idx+1,sizeof(void *)*(m_size-idx));
|
||||||
|
if (!(m_size&31)&&m_size) // resize down
|
||||||
|
{
|
||||||
|
m_list=(void**)::realloc(m_list,sizeof(void*)*m_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WS_conInst::WS_conInst(JNL_Connection *c, int which_port) : m_serv(c), m_port(which_port)
|
||||||
|
{
|
||||||
|
m_pagegen=0;
|
||||||
|
time(&m_connect_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
WS_conInst::~WS_conInst()
|
||||||
|
{
|
||||||
|
delete m_pagegen;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebServerBaseClass::~WebServerBaseClass()
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < m_connections->GetSize(); x ++)
|
||||||
|
{
|
||||||
|
delete (WS_conInst *)m_connections->Get(x);
|
||||||
|
}
|
||||||
|
delete m_connections;
|
||||||
|
for (x = 0; x < m_listeners->GetSize(); x ++)
|
||||||
|
{
|
||||||
|
delete (JNL_Listen *)m_listeners->Get(x);
|
||||||
|
}
|
||||||
|
delete m_listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebServerBaseClass::WebServerBaseClass()
|
||||||
|
{
|
||||||
|
m_connections=new WS_ItemList;
|
||||||
|
m_listeners=new WS_ItemList;
|
||||||
|
m_listener_rot=0;
|
||||||
|
m_timeout_s=15;
|
||||||
|
m_max_con=100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WebServerBaseClass::setMaxConnections(int max_con)
|
||||||
|
{
|
||||||
|
m_max_con=max_con;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerBaseClass::setRequestTimeout(int timeout_s)
|
||||||
|
{
|
||||||
|
m_timeout_s=timeout_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebServerBaseClass::addListenPort(int port, unsigned long which_interface)
|
||||||
|
{
|
||||||
|
int ffree=-1;
|
||||||
|
removeListenPort(port);
|
||||||
|
|
||||||
|
JNL_Listen *p=new JNL_Listen(port,which_interface);
|
||||||
|
m_listeners->Add((void *)p);
|
||||||
|
if (p->is_error()) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerBaseClass::removeListenPort(int port)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < m_listeners->GetSize(); x ++)
|
||||||
|
{
|
||||||
|
JNL_Listen *p=(JNL_Listen *)m_listeners->Get(x);
|
||||||
|
if (p->port()==port)
|
||||||
|
{
|
||||||
|
delete p;
|
||||||
|
m_listeners->Del(x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerBaseClass::removeListenIdx(int idx)
|
||||||
|
{
|
||||||
|
if (idx >= 0 && idx < m_listeners->GetSize())
|
||||||
|
{
|
||||||
|
JNL_Listen *p=(JNL_Listen *)m_listeners->Get(idx);
|
||||||
|
delete p;
|
||||||
|
m_listeners->Del(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebServerBaseClass::getListenPort(int idx, int *err)
|
||||||
|
{
|
||||||
|
JNL_Listen *p=(JNL_Listen *)m_listeners->Get(idx);
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
if (err) *err=p->is_error();
|
||||||
|
return p->port();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerBaseClass::attachConnection(JNL_Connection *con, int port)
|
||||||
|
{
|
||||||
|
m_connections->Add((void*)new WS_conInst(con,port));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerBaseClass::run(void)
|
||||||
|
{
|
||||||
|
int nl;
|
||||||
|
if (m_connections->GetSize() < m_max_con && (nl=m_listeners->GetSize()))
|
||||||
|
{
|
||||||
|
JNL_Listen *l=(JNL_Listen *)m_listeners->Get(m_listener_rot++ % nl);
|
||||||
|
JNL_Connection *c=l->get_connect();
|
||||||
|
if (c)
|
||||||
|
{
|
||||||
|
attachConnection(c,l->port());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < m_connections->GetSize(); x ++)
|
||||||
|
{
|
||||||
|
if (run_connection((WS_conInst *)m_connections->Get(x)))
|
||||||
|
{
|
||||||
|
delete ((WS_conInst *)m_connections->Get(x));
|
||||||
|
m_connections->Del(x--);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebServerBaseClass::run_connection(WS_conInst *con)
|
||||||
|
{
|
||||||
|
int s=con->m_serv.run();
|
||||||
|
if (s < 0)
|
||||||
|
{
|
||||||
|
// m_serv.geterrorstr()
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (s < 2)
|
||||||
|
{
|
||||||
|
// return 1 if we timed out
|
||||||
|
return time(NULL)-con->m_connect_time > m_timeout_s;
|
||||||
|
}
|
||||||
|
if (s < 3)
|
||||||
|
{
|
||||||
|
con->m_pagegen=onConnection(&con->m_serv,con->m_port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (s < 4)
|
||||||
|
{
|
||||||
|
if (!con->m_pagegen)
|
||||||
|
{
|
||||||
|
return !con->m_serv.bytes_inqueue();
|
||||||
|
}
|
||||||
|
char buf[16384];
|
||||||
|
int l=con->m_serv.bytes_cansend();
|
||||||
|
if (l > 0)
|
||||||
|
{
|
||||||
|
if (l > sizeof(buf))l=sizeof(buf);
|
||||||
|
l=con->m_pagegen->GetData(buf,l);
|
||||||
|
if (l < (con->m_pagegen->IsNonBlocking() ? 0 : 1)) // if nonblocking, this is l < 0, otherwise it's l<1
|
||||||
|
{
|
||||||
|
return !con->m_serv.bytes_inqueue();
|
||||||
|
}
|
||||||
|
if (l>0)
|
||||||
|
con->m_serv.write_bytes(buf,l);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1; // we're done by this point
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void WebServerBaseClass::url_encode(char *in, char *out, int max_out)
|
||||||
|
{
|
||||||
|
while (*in && max_out > 4)
|
||||||
|
{
|
||||||
|
if ((*in >= 'A' && *in <= 'Z')||
|
||||||
|
(*in >= 'a' && *in <= 'z')||
|
||||||
|
(*in >= '0' && *in <= '9')|| *in == '.' || *in == '_' || *in == '-')
|
||||||
|
{
|
||||||
|
*out++=*in++;
|
||||||
|
max_out--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i=*in++;
|
||||||
|
*out++ = '%';
|
||||||
|
int b=(i>>4)&15;
|
||||||
|
if (b < 10) *out++='0'+b;
|
||||||
|
else *out++='A'+b-10;
|
||||||
|
b=i&15;
|
||||||
|
if (b < 10) *out++='0'+b;
|
||||||
|
else *out++='A'+b-10;
|
||||||
|
max_out-=3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WebServerBaseClass::url_decode(char *in, char *out, int maxlen)
|
||||||
|
{
|
||||||
|
while (*in && maxlen>1)
|
||||||
|
{
|
||||||
|
if (*in == '+')
|
||||||
|
{
|
||||||
|
in++;
|
||||||
|
*out++=' ';
|
||||||
|
}
|
||||||
|
else if (*in == '%' && in[1] != '%' && in[1])
|
||||||
|
{
|
||||||
|
int a=0;
|
||||||
|
int b=0;
|
||||||
|
for ( b = 0; b < 2; b ++)
|
||||||
|
{
|
||||||
|
int r=in[1+b];
|
||||||
|
if (r>='0'&&r<='9') r-='0';
|
||||||
|
else if (r>='a'&&r<='z') r-='a'-10;
|
||||||
|
else if (r>='A'&&r<='Z') r-='A'-10;
|
||||||
|
else break;
|
||||||
|
a*=16;
|
||||||
|
a+=r;
|
||||||
|
}
|
||||||
|
if (b < 2) *out++=*in++;
|
||||||
|
else { *out++=a; in += 3;}
|
||||||
|
}
|
||||||
|
else *out++=*in++;
|
||||||
|
maxlen--;
|
||||||
|
}
|
||||||
|
*out=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void WebServerBaseClass::base64decode(char *src, char *dest, int destsize)
|
||||||
|
{
|
||||||
|
int accum=0;
|
||||||
|
int nbits=0;
|
||||||
|
while (*src)
|
||||||
|
{
|
||||||
|
int x=0;
|
||||||
|
char c=*src++;
|
||||||
|
if (c >= 'A' && c <= 'Z') x=c-'A';
|
||||||
|
else if (c >= 'a' && c <= 'z') x=c-'a' + 26;
|
||||||
|
else if (c >= '0' && c <= '9') x=c-'0' + 52;
|
||||||
|
else if (c == '+') x=62;
|
||||||
|
else if (c == '/') x=63;
|
||||||
|
else break;
|
||||||
|
|
||||||
|
accum <<= 6;
|
||||||
|
accum |= x;
|
||||||
|
nbits += 6;
|
||||||
|
|
||||||
|
while (nbits >= 8)
|
||||||
|
{
|
||||||
|
if (--destsize<=0) break;
|
||||||
|
nbits-=8;
|
||||||
|
*dest++ = (char)((accum>>nbits)&0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*dest=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebServerBaseClass::base64encode(char *in, char *out)
|
||||||
|
{
|
||||||
|
char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
int shift = 0;
|
||||||
|
int accum = 0;
|
||||||
|
|
||||||
|
while (*in)
|
||||||
|
{
|
||||||
|
if (*in)
|
||||||
|
{
|
||||||
|
accum <<= 8;
|
||||||
|
shift += 8;
|
||||||
|
accum |= *in++;
|
||||||
|
}
|
||||||
|
while ( shift >= 6 )
|
||||||
|
{
|
||||||
|
shift -= 6;
|
||||||
|
*out++ = alphabet[(accum >> shift) & 0x3F];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shift == 4)
|
||||||
|
{
|
||||||
|
*out++ = alphabet[(accum & 0xF)<<2];
|
||||||
|
*out++='=';
|
||||||
|
}
|
||||||
|
else if (shift == 2)
|
||||||
|
{
|
||||||
|
*out++ = alphabet[(accum & 0x3)<<4];
|
||||||
|
*out++='=';
|
||||||
|
*out++='=';
|
||||||
|
}
|
||||||
|
|
||||||
|
*out++=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebServerBaseClass::parseAuth(char *auth_header, char *out, int out_len)//returns 0 on unknown auth, 1 on basic
|
||||||
|
{
|
||||||
|
char *authstr=auth_header;
|
||||||
|
*out=0;
|
||||||
|
if (!auth_header || !*auth_header) return 0;
|
||||||
|
while (*authstr == ' ') authstr++;
|
||||||
|
if (strnicmp(authstr,"basic ",6)) return 0;
|
||||||
|
authstr+=6;
|
||||||
|
while (*authstr == ' ') authstr++;
|
||||||
|
base64decode(authstr,out,out_len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
142
foo_httpcontrol/lib/jnetlib/webserver.h
Executable file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
** JNetLib
|
||||||
|
** Copyright (C) 2003 Nullsoft, Inc.
|
||||||
|
** Author: Justin Frankel
|
||||||
|
** File: webserver.h - Generic simple webserver baseclass
|
||||||
|
** License: see jnetlib.h
|
||||||
|
**
|
||||||
|
** You can derive your object from WebServerBaseClass to do simple web serving. Example:
|
||||||
|
|
||||||
|
class wwwServer : public WebServerBaseClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
wwwServer() { }
|
||||||
|
virtual IPageGenerator *onConnection(JNL_HTTPServ *serv, int port)
|
||||||
|
{
|
||||||
|
serv->set_reply_header("Server:jnetlib_test/0.0");
|
||||||
|
if (!strcmp(serv->get_request_file(),"/"))
|
||||||
|
{
|
||||||
|
serv->set_reply_string("HTTP/1.1 200 OK");
|
||||||
|
serv->set_reply_header("Content-Type:text/html");
|
||||||
|
serv->send_reply();
|
||||||
|
|
||||||
|
return new MemPageGenerator(strdup("Test Web Server v0.0"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serv->set_reply_string("HTTP/1.1 404 NOT FOUND");
|
||||||
|
serv->send_reply();
|
||||||
|
return 0; // no data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
wwwServer foo;
|
||||||
|
foo.addListenPort(8080);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
foo.run();
|
||||||
|
Sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
You will also need to derive from the IPageGenerator interface to provide a data stream, here is an
|
||||||
|
example of MemPageGenerator:
|
||||||
|
|
||||||
|
class MemPageGenerator : public IPageGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~MemPageGenerator() { free(m_buf); }
|
||||||
|
MemPageGenerator(char *buf, int buf_len=-1) { m_buf=buf; if (buf_len >= 0) m_buf_size=buf_len; else m_buf_size=strlen(buf); m_buf_pos=0; }
|
||||||
|
virtual int GetData(char *buf, int size) // return 0 when done
|
||||||
|
{
|
||||||
|
int a=m_buf_size-m_buf_pos;
|
||||||
|
if (a < size) size=a;
|
||||||
|
memcpy(buf,m_buf+m_buf_pos,size);
|
||||||
|
m_buf_pos+=size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char *m_buf;
|
||||||
|
int m_buf_size;
|
||||||
|
int m_buf_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _JNL_WEBSERVER_H_
|
||||||
|
#define _JNL_WEBSERVER_H_
|
||||||
|
|
||||||
|
#include "httpserv.h"
|
||||||
|
|
||||||
|
class IPageGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IPageGenerator() { };
|
||||||
|
virtual int IsNonBlocking() { return 0; } // override this and return 1 if GetData should be allowed to return 0
|
||||||
|
virtual int GetData(char *buf, int size)=0; // return < 0 when done (or 0 if IsNonBlocking() is 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WS_ItemList;
|
||||||
|
class WS_conInst;
|
||||||
|
|
||||||
|
class WebServerBaseClass
|
||||||
|
{
|
||||||
|
protected: // never create one of these directly, always derive
|
||||||
|
WebServerBaseClass();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~WebServerBaseClass();
|
||||||
|
|
||||||
|
// stuff for setting limits/timeouts
|
||||||
|
void setMaxConnections(int max_con);
|
||||||
|
void setRequestTimeout(int timeout_s);
|
||||||
|
|
||||||
|
// stuff for setting listener port
|
||||||
|
int addListenPort(int port, unsigned long which_interface=0);
|
||||||
|
int getListenPort(int idx, int *err=0);
|
||||||
|
void removeListenPort(int port);
|
||||||
|
void removeListenIdx(int idx);
|
||||||
|
|
||||||
|
// call this a lot :)
|
||||||
|
void run(void);
|
||||||
|
|
||||||
|
// if you want to manually attach a connection, use this:
|
||||||
|
// you need to specify the port it came in on so the web server can build
|
||||||
|
// links
|
||||||
|
void attachConnection(JNL_Connection *con, int port);
|
||||||
|
|
||||||
|
// derived classes need to override this one =)
|
||||||
|
virtual IPageGenerator *onConnection(JNL_HTTPServ *serv, int port)=0;
|
||||||
|
|
||||||
|
// stats getting functions
|
||||||
|
|
||||||
|
// these can be used externally, as well as are used by the web server
|
||||||
|
static void url_encode(char *in, char *out, int max_out);
|
||||||
|
static void url_decode(char *in, char *out, int maxlen);
|
||||||
|
static void base64decode(char *src, char *dest, int destsize);
|
||||||
|
static void base64encode(char *in, char *out);
|
||||||
|
|
||||||
|
static int parseAuth(char *auth_header, char *out, int out_len);//returns 0 on unknown auth, 1 on basic
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
int run_connection(WS_conInst *con);
|
||||||
|
|
||||||
|
int m_timeout_s;
|
||||||
|
int m_max_con;
|
||||||
|
|
||||||
|
JNL_AsyncDNS m_dns;
|
||||||
|
|
||||||
|
WS_ItemList *m_listeners;
|
||||||
|
int m_listener_rot;
|
||||||
|
WS_ItemList *m_connections;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//_JNL_WEBSERVER_H_
|
||||||
617
foo_httpcontrol/readme.html
Executable file
@@ -0,0 +1,617 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>foo_httpcontrol readme</title>
|
||||||
|
<style type="text/css">
|
||||||
|
body{ font: 0.75em "Arial", sans-serif; margin: 10px; background-color: #ffffff; max-width: 800px; }
|
||||||
|
ul#commands li { margin-bottom: 0.5em; }
|
||||||
|
h2 {border-bottom: 1px solid gray}
|
||||||
|
h2#warn {color: red; border: 0px;}
|
||||||
|
p {text-indent: 2em; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>foo_httpcontrol 0.97.15 02 Mar 2014</h2>
|
||||||
|
<p><a href="http://code.google.com/p/foo-httpcontrol/">http://code.google.com/p/foo-httpcontrol</a></p>
|
||||||
|
|
||||||
|
<h2 id="warn">Warning/disclaimer: this software comes without any warranties at all. It is still in the very early development stage, and so on, and so forth, blah-blah-blah.
|
||||||
|
Component can be very dangerous to your music collection when blindly exposed to Internet without any additional protection. Remember, it is intended for private, non-public use only!</h2>
|
||||||
|
|
||||||
|
<p>This <a href="http://foobar2000.org">foobar2000</a> 1.0 component is developed as replacement for Media Player Classic web control interface,
|
||||||
|
which I used quite a lot, but still didn't like it, as it missed quite a number of features I'd like to have. Also
|
||||||
|
I felt it's a shame such great player as foobar2000 couldn't be remotely controlled over http nowadays.
|
||||||
|
So, erm, I went ahead and somehow developed component featuring functions I use by myself on everyday basis.</p>
|
||||||
|
|
||||||
|
<p>It provides the following features via http requests:</p>
|
||||||
|
<ul>
|
||||||
|
<li>full control of playback, including seekbar</li>
|
||||||
|
<li>basic playlist support</li>
|
||||||
|
<li>basic playback queue support</li>
|
||||||
|
<li>basic media library support</li>
|
||||||
|
<li>basic file browser functions, including ability to browse Microsoft Network</li>
|
||||||
|
<li>a few UI customization abilities</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Default interface template is written using synchronious document model (with basic CSS and JS),
|
||||||
|
and has been tested and proved itself working on any modern browser: Opera, Firefox, Chrome, Safari.</p>
|
||||||
|
|
||||||
|
<h2>Installation</h2>
|
||||||
|
<p>Extract foo_httpcontrol.dll to foobar2000 components directory (%APPDATA%\foobar2000\user-components\foo_httpcontrol\).
|
||||||
|
Alternatively you can use foobar2000 own installer: foobar2000/Preferences/Components/Install... and point it to foo_httpcontrol zip archive.</p>
|
||||||
|
|
||||||
|
<p>Download at least one template (<a href="http://www.hydrogenaudio.org/forums/index.php?showtopic=62218">http://www.hydrogenaudio.org/forums/index.php?showtopic=62218</a>, <a href="http://code.google.com/p/foo-httpcontrol/">http://code.google.com/p/foo-httpcontrol</a>)
|
||||||
|
and follow bundled instructions to install it where it belongs.</p>
|
||||||
|
|
||||||
|
<p>Start foobar2000 and modify component settings according to your taste in
|
||||||
|
preferences (foobar2000/Preferences/Tools/HTTP Control). Nothing prevents you from
|
||||||
|
customizing any template you are using, or even writing your very own one.</p>
|
||||||
|
<p>Default configuration allows you to access foo_httpcontrol at least on
|
||||||
|
<a href="http://127.0.0.1:8888/">http://127.0.0.1:8888/</a> address.</p>
|
||||||
|
|
||||||
|
<p>Well, that's all, try to have fun! Just in case: I'm preventively sorry for all possible frustration.</p>
|
||||||
|
|
||||||
|
<h2>Preferences</h2>
|
||||||
|
<img src="readme.png" alt="foo_httpcontrol preferences">
|
||||||
|
<ol>
|
||||||
|
<li>Specifies the IP address and port used for listening to incoming connections. Both IP address and port must be valid, make sure specified port is not used by another program.</li>
|
||||||
|
<li>Check or uncheck to enable or disable listening for incoming connections.</li>
|
||||||
|
<li>Opens component page in default browser. Button is inactive if server/listener isn't started.</li>
|
||||||
|
<li>Limit access to component by setting the allowed IP address. Connections initiated from other addresses will be discarded. Setting this to 0.0.0.0 allows all connections.</li>
|
||||||
|
<li>Limit access to component by defining a login/password pair. Untick to disable passwords.</li>
|
||||||
|
<li>Built-in file browser can be limited to certain paths of your file system. It is useful to simplify the browsing process or hide your secret files from prying eyes. For example, setting Allowed paths to d:\music|c:\temp\music|e:\ permits browsing only in these three file system branches.</li>
|
||||||
|
<li>You can specify additional file extensions to be treated as playable files by built-in file browser. It is required for opening archives containing playable files.</li>
|
||||||
|
<li>Removes all files which foobar2000 core considers unplayable from built-in file browser.</li>
|
||||||
|
<li>Specifies path where component will look for template files. Pressing Open opens specified or default directory in Explorer. If not sure, leave it blank. </li>
|
||||||
|
<li>Enables gzip compression of component output. Enabling it is usually harmless and quite beneficial as component generates a lot of text which is very compressible. Disable if you are using some funky browser and having unexpected problems.</li>
|
||||||
|
<li>Enables logging of component access data to foobar2000 console. Useful for debugging etc.</li>
|
||||||
|
<li>Adds "Stop after queue" item in Playback menu. It works exactly as it's named, stops playback when end of playback queue is reached.</li>
|
||||||
|
</ol>
|
||||||
|
Don't forget to press Apply or your changes won't have any effect until fb2k is restarted.
|
||||||
|
|
||||||
|
<h2>Troubleshooting</h2>
|
||||||
|
|
||||||
|
<p>Discussion thread (please post all your questions and suggestions here):
|
||||||
|
<a href="http://www.hydrogenaudio.org/forums/index.php?showtopic=62218">http://www.hydrogenaudio.org/forums/index.php?showtopic=62218</a></p>
|
||||||
|
|
||||||
|
<h2>Changes history 2014</h2>
|
||||||
|
<p>v0.97.15 02 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: Seek command renamed to SeekPercent, old name still works;</li>
|
||||||
|
<li>add: SeekDelta command renamed to SeekSecondDelta, old name still works;</li>
|
||||||
|
<li>add: SeekSecond command, seek with a second precision;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.14 02 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: Implemented natural sorting (StrCmpLogicalW) in file browser and media library query;</li>
|
||||||
|
<li>fix: A few fixes discovered by awesome CppCat static analyzer software;</li>
|
||||||
|
<li>fix: (Probably) got rid of not very rare exception happening in file browser;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Changes history 2013</h2>
|
||||||
|
<p>v0.97.13 21 Jan</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: Sort command renamed to SortAscending, old name still supported;</li>
|
||||||
|
<li>add: SortDescending command, essentially the same as SortAscending but sorting result is reversed;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Changes history 2011</h2>
|
||||||
|
|
||||||
|
<p>v0.97.12 14 Aug</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: hide password text in Preferences;</li>
|
||||||
|
<li>fix: http protocol items left out when adding items using Browse cmd. it's now possible to "Add location" too by specifying url in Browse cmd param1;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.11 20 Jul</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: crash on unknown file format requests;</li>
|
||||||
|
<li>fix: inability to send zero length files;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.9 04 Jul</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: FormatTitles command results are now proper for now playing context;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.8 14 May</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: removed deprecated commands VolumeUp, VolumeDown, DequeueTrack;</li>
|
||||||
|
<li>add: FormatTitles cmd, parses the list of titleformatting strings passed in param1 (multiple values must be separated by |)
|
||||||
|
for active playlist item defined in param2 or currently played item if param2 is omitted, and returns the data in json array format.
|
||||||
|
make sure to pass reference to any filename with json extension in param3, so response has proper the content type.
|
||||||
|
if param3 is omitted, content type is set to default text/html and might confuse some browsers.<br>
|
||||||
|
for example, calling<br>
|
||||||
|
?cmd=FormatTitles¶m1=%artist%|%album%|%bitrate%¶m2=0¶m3=format.json <br>
|
||||||
|
formats supplied titleformatting strings for active playlist item number 0, resulting in following response:<br>
|
||||||
|
["Ozric Tentacles","Spirals in Hyperspace","980"]
|
||||||
|
</li>
|
||||||
|
<li>add: ability to ignore files with specific extensions in file browser: see "Ignored formats" preferences field;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.7 7 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: albumart_limit_size config key, defines maximum albumart size in bytes to retrieve. default is 0, no limit;</li>
|
||||||
|
<li>add: albumart_prefer_embedded config key, defines whether to prefer embedded albumart over external. default is 0, prefer external albumart;</li>
|
||||||
|
<li>add: Sort command, sorts whole active playlist or item list specified in param2, using sort pattern param1;</li>
|
||||||
|
<li>fix: setting playlist_items_per_page config key to 0 disables playlist retrieve;</li>
|
||||||
|
<li>fix: SelectionCommand additionally accepts list of items to be processed in param2;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.6 24 Jan</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: additional exception detection;</li>
|
||||||
|
<li>add: removed stripping non-text chars in json responses as most of the 3rd party templates requests have cr/lf's in wrong places;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.5 22 Jan</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: possible crash during media library query;</li>
|
||||||
|
<li>add: strip non-text chars in json responses;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Changes history 2010</h2>
|
||||||
|
|
||||||
|
<p>v0.97.4 21 Dec</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: SetSelection command, selects item list specified in param1 (numbers separated by any delitemeter),
|
||||||
|
optionally taking param2 as playlist number. empty param1 value removes all selection, if param1 equals to ~, all playlist items will be selected.
|
||||||
|
example: ?cmd=SetSelection&param1=1,2,3&param2=1 selects items 1,2,3 in playlist 1</li>
|
||||||
|
<li>add: SelectionCommand command, executes context menu command specified in param1 for currently selected items (don't forget to urlencode param1 value). Note that running playlist-specific context menu commands like Remove, Crop, etc is not possible.
|
||||||
|
example: ?cmd=SelectionCommand&param1=Playback%20Statistics%2FRating%2F3 sets rating 3 to active playlist selection.</li>
|
||||||
|
<li>fix: context menu commands are run on full context menu;</li>
|
||||||
|
<li>fix: removed 'allow fb2k command-line interface' option;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.3 15 Nov</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: PlayingCommand command, executes context menu command specified in param1 for currently playing item (don't forget to urlencode param1 value).
|
||||||
|
example: ?cmd=PlayingCommand&param1=Playback%20Statistics%2FRating%2F3</li>
|
||||||
|
<li>fix: Decapitalize stop after queue menu item;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97.2 31 Oct</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: CmdLine command doesn't work in fb2k 1.1 and newer;</li>
|
||||||
|
<li>fix: disabling command-line interface in preferences has no effect;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.97 24 Sep</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: removed forgotten console debug message;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.16 23 Sep</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: pseudo-multithreaded request processing to workaround the new dubious pre- and post- 'speedup' connections of Chrome 7 and IE9;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.15 13 Sep</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: \r\n characters escaping in *_JS macros;</li>
|
||||||
|
<li>fix: wrong compile optimization options;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.14 08 Aug</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: possible buffer overrun in file browser;</li>
|
||||||
|
<li>add: updated documentation;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.13.1 04 May</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: borked content-type in server responses;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.13 03 May</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: installed templates list shown before user authentification;</li>
|
||||||
|
<li>fix: removed display of home folder full path in templates list and error pages;</li>
|
||||||
|
<li>add: autoselect playlist if only one playlist present;</li>
|
||||||
|
<li>add: SeekDelta command, param1 specifies seek delta seconds (signed integer);</li>
|
||||||
|
<li>add: VolumeDBDelta command, param1 specifies dB volume level delta defined by signed integer multiplied by 10 (divided by 10 within the component);</li>
|
||||||
|
<li>add: VolumeDelta command, param1 specifies signed volume delta percentage;</li>
|
||||||
|
<li>add: VolumeUp VolumeDown commands are deprecated;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.12.1 19 Apr</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: stop after queue affected playlist refreshing on queue operations;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.12 17 Apr</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: optional gzip compression (reduces compressible html/css/json traffic 3-5 times). disable in preferences if you're experiencing problems.</li>
|
||||||
|
<li>add: user specified playable file extensions for file browser. helps to make archives appear playable, for example.</li>
|
||||||
|
<li>fix: random stuff;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.11 10 Apr</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: more accurate replication of DUI behaviour for Start/Pause commands;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.10 04 Apr</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: crashes on queue operations;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.9 30 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: added backslash 'escaping' in certain ui macros;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.8 22 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: crash in certain conditions;</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.7 21 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: wrong handling of multivalue tags in media library query</li>
|
||||||
|
<li>fix: some fixes and improvements</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.6 15 Mar</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: wrong parent in network shares browser</li>
|
||||||
|
<li>fix: some bugs here and there</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.5 22 Feb</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: VolumeMuteToggle command</li>
|
||||||
|
<li>add: VolumeDB command, param1 specifies positive integer dB volume level multiplied by 10 (divided by -10 within the component). accepted value range is 0...665 (0...-66.5 dB), or 1000 for mute (-100 dB)</li>
|
||||||
|
<li>add: [VOLUME_DB] integer db volume level (multiplied by -10, thus single digit precision)</li>
|
||||||
|
<li>fix: custom random play command replaced with foobar2000 standard one</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.4 23 Jan</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: fixes and improvements</li>
|
||||||
|
<li>add: FocusOnPlaying command</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.3 06 Jan</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: [HELPER1X], [HELPER2X], [HELPER3X] macros - xml friendly versions of [HELPERN] macros</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>v0.96.2 05 Jan</p>
|
||||||
|
<ul>
|
||||||
|
<li>fix: manual starting/stopping listener thread issues</li>
|
||||||
|
<li>fix: wrong [ALBUMART] macro url for embedded albumart</li>
|
||||||
|
<li>add: SAQ command ignored when "Enable stop after queue menu item" preferences option unchecked</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Changes history 2009</h2>
|
||||||
|
|
||||||
|
<p>v0.96.1 29 Dec</p>
|
||||||
|
<ul>
|
||||||
|
<li>add: [PLAYLIST_IS_UNDO_AVAILABLE] [PLAYLIST_IS_REDO_AVAILABLE] active playlist context macros</li>
|
||||||
|
<li>add: Redo cmd, reverting changes made by undo, param1 optionally specifies playlist</li>
|
||||||
|
<li>add: creating undo point prior to enqueue tracks and library query commands</li>
|
||||||
|
<li>add: removable stop after queue menu item</li>
|
||||||
|
<li>add: templates config file. see default template config file for syntax</li>
|
||||||
|
<li>add: fb2k 1.0+ is required</li>
|
||||||
|
<li>fix: various fixes</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Appendix #1</h2>
|
||||||
|
|
||||||
|
<p>Bundled foobar2000 icon (c) 2007 Florian Trendelenburg</p>
|
||||||
|
|
||||||
|
<p>foo_httpcontrol is developed using:</p>
|
||||||
|
|
||||||
|
<ul id="commands">
|
||||||
|
<li>foobar2000 1.0 SDK<br/>
|
||||||
|
Copyright (c) 2001-2009, Peter Pawlowski<br/>
|
||||||
|
All rights reserved.<br/>
|
||||||
|
<a href="http://foobar2000.org">http://foobar2000.org</a></li>
|
||||||
|
|
||||||
|
<li>JNetLib<br/>
|
||||||
|
Justin Frankel http://www.cockos.com<br/>
|
||||||
|
Joshua Teitelbaum http://www.cryptomail.org</li>
|
||||||
|
|
||||||
|
<li>zlib<br/>
|
||||||
|
http://www.zlib.net/<br/>
|
||||||
|
Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler</li>
|
||||||
|
|
||||||
|
<li>priceless inspiration of foo_httpserver sources<br/>
|
||||||
|
Erik http://foobar.daychanged.com<br/>
|
||||||
|
Jonatan Kronqvist http://fb2k.oxygenite.org</li>
|
||||||
|
|
||||||
|
<li>remains of my mental and physical health</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Appendix #2</h2>
|
||||||
|
|
||||||
|
<p>Command syntax:
|
||||||
|
http://>ip<[:<port>]/<?cmd=Command[&param1=param 1[&param2=param 2]][&param3=param 3]></p>
|
||||||
|
|
||||||
|
<p>Supported commands:</p>
|
||||||
|
<ul id="commands">
|
||||||
|
<li>Stop playback<br/>
|
||||||
|
cmd=Stop<br/></li>
|
||||||
|
|
||||||
|
<li>Play or pause playback<br/>
|
||||||
|
cmd=PlayOrPause</li>
|
||||||
|
|
||||||
|
<li>Start playback in active playlist<br/>
|
||||||
|
cmd=Start<br/>
|
||||||
|
param1=playlist item starting from 0</li>
|
||||||
|
|
||||||
|
<li>Start playback of random item in active playlist<br/>
|
||||||
|
cmd=StartRandom</li>
|
||||||
|
|
||||||
|
<li>Start playback of previous item in active playlist<br/>
|
||||||
|
cmd=StartPrevious</li>
|
||||||
|
|
||||||
|
<li>Start playback of next item in active playlist<br/>
|
||||||
|
cmd=StartNext</li>
|
||||||
|
|
||||||
|
<li>Volume level<br/>
|
||||||
|
cmd=Volume
|
||||||
|
param1=volume level, 0...100 (%)</li>
|
||||||
|
|
||||||
|
<li>Volume level delta<br/>
|
||||||
|
cmd=VolumeDelta
|
||||||
|
param1=signed volume level delta percentage, -N...N (%)</li>
|
||||||
|
|
||||||
|
<li>Volume level dB<br/>
|
||||||
|
cmd=VolumeDB
|
||||||
|
param1=volume level, 0...665 (0...-66.5 db), or 1000 to mute</li>
|
||||||
|
|
||||||
|
<li>Volume level dB delta<br/>
|
||||||
|
cmd=VolumeDBDelta
|
||||||
|
param1=signed delta, -N...N (-N/10...N/10 db)</li>
|
||||||
|
|
||||||
|
<li>Seek playing item by percentage<br/>
|
||||||
|
cmd=SeekPercent<br/>
|
||||||
|
param1=position, from 0 to 100 (percent)</li>
|
||||||
|
|
||||||
|
<li>Seek playing item by seconds<br/>
|
||||||
|
cmd=SeekSecond<br/>
|
||||||
|
param1=seconds (signed integer)</li>
|
||||||
|
|
||||||
|
<li>Seek playing item by delta seconds<br/>
|
||||||
|
cmd=SeekSecondDelta<br/>
|
||||||
|
param1=seconds (signed integer)</li>
|
||||||
|
|
||||||
|
<li>Empty active playlist<br/>
|
||||||
|
cmd=EmptyPlaylist</li>
|
||||||
|
|
||||||
|
<li>Change playback order<br/>
|
||||||
|
cmd=PlaybackOrder<br/>
|
||||||
|
param1=order number, from 0 to 7</li>
|
||||||
|
|
||||||
|
<li>Delete one or more playlist items<br/>
|
||||||
|
cmd=Del<br/>
|
||||||
|
param1=numbers separated by any delitemeter<br/>
|
||||||
|
param2=optionally specifies playlist</li>
|
||||||
|
|
||||||
|
<li>Undo changes made to playlist backed up by restore point<br/>
|
||||||
|
cmd=Undo<br/>
|
||||||
|
param1=optionally specifies playlist</li>
|
||||||
|
|
||||||
|
<li>Move one or more active playlist items<br/>
|
||||||
|
cmd=Move<br/>
|
||||||
|
param1=numbers separated by any delitemeter<br/>
|
||||||
|
param2=signed move delta</li>
|
||||||
|
|
||||||
|
<li>Set playlist selection<br/>
|
||||||
|
cmd=SetSelection<br/>
|
||||||
|
param1=numbers separated by any delitemeter, empty to remove selection, ~ to select all<br/>
|
||||||
|
param2=optionally specifies playlist</li>
|
||||||
|
|
||||||
|
<li>Change stop after current flag<br/>
|
||||||
|
cmd=SAC<br/>
|
||||||
|
param1=0 or 1</li>
|
||||||
|
|
||||||
|
<li>Switch playlist<br/>
|
||||||
|
cmd=SwitchPlaylist<br/>
|
||||||
|
param1=playlist index, from 0</li>
|
||||||
|
|
||||||
|
<li>Switch playlist page<br/>
|
||||||
|
cmd=SwitchPlaylistPage;P<br/>
|
||||||
|
param1=page index, from 0</li>
|
||||||
|
|
||||||
|
<li>Set focus to specific item of active playlist<br/>
|
||||||
|
cmd=SetFocus<br/>
|
||||||
|
param1=item starting from 0</li>
|
||||||
|
|
||||||
|
<li>Browse directory<br/>
|
||||||
|
cmd=Browse<br/>
|
||||||
|
param1=urlencoded path</li>
|
||||||
|
|
||||||
|
<li>Enqueue path<br/>
|
||||||
|
param2=EnqueueDir</li>
|
||||||
|
|
||||||
|
<li>Enqueue path including subdirectories<br/>
|
||||||
|
param2=EnqueueDirSubdirs</li>
|
||||||
|
|
||||||
|
<li>Put active playlist items to playback queue <br/>
|
||||||
|
cmd=QueueItems<br/>
|
||||||
|
param1=numbers separated by any delitemeter</li>
|
||||||
|
|
||||||
|
<li>Remove active playlist items from playback queue <br/>
|
||||||
|
cmd=DequeueItems<br/>
|
||||||
|
param1=numbers separated by any delitemeter</li>
|
||||||
|
|
||||||
|
<li>Search media library<br/>
|
||||||
|
cmd=SearchMediaLibrary;Search<br/>
|
||||||
|
param1=search query</li>
|
||||||
|
|
||||||
|
<li>Query media library<br/>
|
||||||
|
cmd=QueryAdvance<br/>
|
||||||
|
param1=search query</li>
|
||||||
|
|
||||||
|
<li>Query media library<br/>
|
||||||
|
cmd=QueryRetrace</li>
|
||||||
|
|
||||||
|
<li>Skip generating request response<br/>
|
||||||
|
param3=NoResponse</li>
|
||||||
|
|
||||||
|
<li>Use different template file<br/>
|
||||||
|
param3=template.html</li>
|
||||||
|
|
||||||
|
<li>PlaylistItemsPerPage<br/>
|
||||||
|
param1=number of playlist items per page, limited to 16384</li>
|
||||||
|
|
||||||
|
<li>QueueAlbum<br/>
|
||||||
|
param1=item album search starts from (focused item is used if param1 is omitted)</li>
|
||||||
|
|
||||||
|
<li>QueueRandomItems<br/>
|
||||||
|
param1=item count</li>
|
||||||
|
|
||||||
|
<li>FlushQueue</li>
|
||||||
|
|
||||||
|
<li>Parse<br/>
|
||||||
|
param1=string to parse and return</li>
|
||||||
|
|
||||||
|
<li>RemovePlaylist<br/>
|
||||||
|
param1=playlist index</li>
|
||||||
|
|
||||||
|
<li>CreatePlaylist<br/>
|
||||||
|
param1=playlist name<br/>
|
||||||
|
param2=insertion point index</li>
|
||||||
|
|
||||||
|
<li>RenamePlaylist<br/>
|
||||||
|
param1=playlist name<br/>
|
||||||
|
param2=playlist index</li>
|
||||||
|
|
||||||
|
<li>FocusOnPlaying</li>
|
||||||
|
|
||||||
|
<li>Update helper macros<br/>
|
||||||
|
cmd=RefreshPlayingInfo</li>
|
||||||
|
|
||||||
|
<li>Execute foobar2000 with specific command-line parameters<br/>
|
||||||
|
cmd=CmdLine<br/>
|
||||||
|
param1=parameters</li>
|
||||||
|
|
||||||
|
<li>Executes context menu command specified in param1 for currently playing item<br/>
|
||||||
|
cmd=PlayingCommand<br/>
|
||||||
|
param1=case sensitive context menu path, for example: Playback Statistics/Rating/3<br/>
|
||||||
|
don't forget to urlencode param1 value.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Executes context menu command specified in param1 for currently selected (or specified list of) items of active playlist. Note that running playlist-specific commands like Remove, Crop, etc is not possible.<br/>
|
||||||
|
cmd=SelectionCommand<br/>
|
||||||
|
param1=case sensitive context menu path, for example: Playback Statistics/Rating/3<br/>
|
||||||
|
param2=numbers separated by any delimeter (optional)<br/>
|
||||||
|
don't forget to urlencode param1 value.<br/>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Sorts whole active playlist or its specified items using sort pattern in ascending order<br/>
|
||||||
|
cmd=SortAscending (deprecated old name Sort)<br/>
|
||||||
|
param1=sort pattern<br/>
|
||||||
|
param2=numbers separated by any delimeter (optional)<br/>
|
||||||
|
don't forget to urlencode param1 value.<br/>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Sorts whole active playlist or its specified items using sort pattern in descending order<br/>
|
||||||
|
cmd=SortDescending<br/>
|
||||||
|
param1=sort pattern<br/>
|
||||||
|
param2=numbers separated by any delimeter (optional)<br/>
|
||||||
|
don't forget to urlencode param1 value.<br/>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Tileformats a list of titleformatting string using playing or certain active playlist item and returns result as json array<br/>
|
||||||
|
cmd=FormatTitles<br/>
|
||||||
|
param1=list of titleformatting strings (separated by |)<br/>
|
||||||
|
param2=active playlist item index (optional)<br/>
|
||||||
|
param3=file name to guess the resulting content type from, use file.json<br/>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Appendix #3</h2>
|
||||||
|
|
||||||
|
<p>Template macro substitutions:</p>
|
||||||
|
<ul>
|
||||||
|
<li>[HELPER1]</li>
|
||||||
|
<li>[HELPER2]</li>
|
||||||
|
<li>[HELPER3]</li>
|
||||||
|
<li>[HELPER1X]</li>
|
||||||
|
<li>[HELPER2X]</li>
|
||||||
|
<li>[HELPER3X]</li>
|
||||||
|
<li>[VOLUME]</li>
|
||||||
|
<li>[VOLUME_DB]</li>
|
||||||
|
<li>[VOLUME_OPTION]</li>
|
||||||
|
<li>[PLAYBACK_ORDER]</li>
|
||||||
|
<li>[PLAYBACK_ORDER_OPTION]</li>
|
||||||
|
<li>[PLAYLISTS_OPTION]</li>
|
||||||
|
<li>[SAC]</li>
|
||||||
|
<li>[SAQ]</li>
|
||||||
|
<li>[ITEM_PLAYING_POS]</li>
|
||||||
|
<li>[ITEM_PLAYING_LEN]</li>
|
||||||
|
<li>[QUEUE_TOTAL_TIME]</li>
|
||||||
|
<li>[IS_PLAYING]</li>
|
||||||
|
<li>[IS_PAUSED]</li>
|
||||||
|
<li>[IS_ENQUEUEING]</li>
|
||||||
|
<li>[AUTO_REFRESH]</li>
|
||||||
|
<li>[LAST_ACTION]</li>
|
||||||
|
<li>[ALBUMART]</li>
|
||||||
|
<li>[PLAYLIST]</li>
|
||||||
|
<li>[PLAYLIST_TOTAL_TIME]</li>
|
||||||
|
<li>[PLAYLIST_ACTIVE]</li>
|
||||||
|
<li>[PLAYLIST_PLAYING]</li>
|
||||||
|
<li>[PLAYLIST_PAGE]</li>
|
||||||
|
<li>[PLAYLIST_PAGES_COUNT]</li>
|
||||||
|
<li>[PLAYLIST_PAGES]</li>
|
||||||
|
<li>[PLAYLIST_PAGES_SELECT]</li>
|
||||||
|
<li>[PLAYLIST_ITEM_FOCUSED]</li>
|
||||||
|
<li>[PLAYLIST_ITEM_PLAYING]</li>
|
||||||
|
<li>[PLAYLIST_ITEM_PREV_PLAYED]</li>
|
||||||
|
<li>[PLAYLIST_ITEMS_COUNT]</li>
|
||||||
|
<li>[PLAYLIST_ITEMS_PER_PAGE]</li>
|
||||||
|
<li>[PLAYLIST_PLAYING_ITEMS_COUNT]</li>
|
||||||
|
<li>[PLAYLIST_IS_UNDO_AVAILABLE] </li>
|
||||||
|
<li>[PLAYLIST_IS_REDO_AVAILABLE] </li>
|
||||||
|
<li>[PLAYLIST_JS]</li>
|
||||||
|
<li>[PLAYLISTS_JS]</li>
|
||||||
|
<li>[SEARCH_REQUEST]</li>
|
||||||
|
<li>[QUERY]</li>
|
||||||
|
<li>[QUERY_JS]</li>
|
||||||
|
<li>[QUERY_INFO]</li>
|
||||||
|
<li>[QUERY_INFO_JS]</li>
|
||||||
|
<li>[PATH]</li>
|
||||||
|
<li>[PATH_JS]</li>
|
||||||
|
<li>[PATH_PARENT]</li>
|
||||||
|
<li>[BROWSER]</li>
|
||||||
|
<li>[BROWSER_JS]</li>
|
||||||
|
<li>[STATE_CHANGE]</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Appendix 4</h2>
|
||||||
|
|
||||||
|
<p>Sample template config file. Config file should be named config and put to template directory root.</p>
|
||||||
|
|
||||||
|
<code>
|
||||||
|
; default template configuration file<br/>
|
||||||
|
; <br/>
|
||||||
|
[foo_httpcontrol]<br/>
|
||||||
|
; base url of template. for example, if template is invoked as http://ip:port/template/, put / here.<br/>
|
||||||
|
url=/<br/>
|
||||||
|
; defines formatting of a playlist row using foobar2000 titleformatting.<br/>
|
||||||
|
playlist_row=<td>%album artist% - %album% - %tracknumber% - %title% - %length%<br/>
|
||||||
|
; defines formatting of a helper macros using foobar2000 titleformatting.<br/>
|
||||||
|
helper1=%album artist% - %title%<br/>
|
||||||
|
helper2=[%title% - ]<br/>
|
||||||
|
helper3=%codec% %bitrate%kbps %samplerate%Hz %channels%<br/>
|
||||||
|
; specifies wildcards where we should look for albumart files, separated by |. foobar2000 titleformatting is available there as well.<br/>
|
||||||
|
albumart=$directory_path(%path%)\folder.jpg|$directory_path(%path%)\*.jpg<br/>
|
||||||
|
; specifies path of a picture to show when albumart is not found.<br/>
|
||||||
|
albumart_not_found=default/nocover.jpg<br/>
|
||||||
|
; specifies path of a picture to show when albumart is requested but not currently available (no playing track).<br/>
|
||||||
|
albumart_not_available=default/nocover.jpg<br/>
|
||||||
|
; limits maximum albumart size to download, in bytes. default is 0 - no limit.<br/>
|
||||||
|
albumart_limit_size=0<br/>
|
||||||
|
; setting to 1 favors embedded albumart over external. default is 0.<br/>
|
||||||
|
albumart_prefer_embedded=0<br/>
|
||||||
|
; controls size of a playlist 'page'. setting to 0 completely disables playlist generation. default is 30.<br/>
|
||||||
|
playlist_items_per_page=30<br/>
|
||||||
|
</code>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
foo_httpcontrol/readme.png
Executable file
|
After Width: | Height: | Size: 76 KiB |
353
foo_httpcontrol/src/browsefiles.cpp
Executable file
@@ -0,0 +1,353 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "browsefiles.h"
|
||||||
|
|
||||||
|
#define MAX_NET_RESOURCES (1024)
|
||||||
|
|
||||||
|
void foo_browsefiles::buildpath_list(pfc::string8 path, pfc::list_t<path_entry_data> &res)
|
||||||
|
{
|
||||||
|
size_t path_len = strlen(path);
|
||||||
|
pfc::string8 tmp;
|
||||||
|
|
||||||
|
if (path_len > 2)
|
||||||
|
{
|
||||||
|
pfc::string8 dir;
|
||||||
|
size_t start = 0;
|
||||||
|
res.add_item(path_entry_data("%20", "Root:\\"));
|
||||||
|
|
||||||
|
if (strstr(path, "\\\\") == path)
|
||||||
|
{
|
||||||
|
start += 2;
|
||||||
|
res.add_item(path_entry_data("Network:\\", "Network:\\"));
|
||||||
|
}
|
||||||
|
if (start != 0)
|
||||||
|
dir << "\\\\";
|
||||||
|
|
||||||
|
char *buf = new char[sizeof(char)*(path_len) + 2];
|
||||||
|
size_t buf_enc_len = sizeof(char)*(path_len) * 5;
|
||||||
|
char *buf_enc = new char[buf_enc_len];
|
||||||
|
for (size_t i = start; i < path_len; ++i)
|
||||||
|
{
|
||||||
|
tmp = "";
|
||||||
|
memset(buf, 0, sizeof(char)*(path_len) + 2);
|
||||||
|
|
||||||
|
while (i < path_len && path[i] != '\\')
|
||||||
|
{
|
||||||
|
dir.add_byte(path[i]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir << "\\";
|
||||||
|
|
||||||
|
strncpy_s(buf, path_len+1, path, i);
|
||||||
|
|
||||||
|
memset(buf_enc, 0, buf_enc_len);
|
||||||
|
WebServerBaseClass::url_encode(buf, buf_enc, buf_enc_len);
|
||||||
|
|
||||||
|
tmp << buf_enc << "%5C";
|
||||||
|
res.add_item(path_entry_data(tmp, dir));
|
||||||
|
|
||||||
|
dir.reset();
|
||||||
|
}
|
||||||
|
delete[] buf;
|
||||||
|
delete[] buf_enc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pfc::string8 foo_browsefiles::separate_thousands(DWORD number)
|
||||||
|
{
|
||||||
|
pfc::string8 result;
|
||||||
|
|
||||||
|
result << (t_uint64)number;
|
||||||
|
|
||||||
|
int sep = 0;
|
||||||
|
for (int i = result.length()-1; i >= 0; --i, ++sep)
|
||||||
|
if (sep == 2)
|
||||||
|
{
|
||||||
|
result.insert_chars(i, " ", 1);
|
||||||
|
sep = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
pfc::string8 foo_browsefiles::format_size(DWORD dwFileSize)
|
||||||
|
{
|
||||||
|
const DWORD dwKB = 1024;
|
||||||
|
const DWORD dwMB = 1024 * dwKB;
|
||||||
|
const DWORD dwGB = 1024 * dwMB;
|
||||||
|
|
||||||
|
DWORD dwNumber, dwRemainder;
|
||||||
|
pfc::string8 strNumber;
|
||||||
|
|
||||||
|
if (dwFileSize < dwKB)
|
||||||
|
{
|
||||||
|
strNumber << separate_thousands(dwFileSize) << " B";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dwFileSize < dwMB)
|
||||||
|
{
|
||||||
|
dwNumber = dwFileSize / dwKB;
|
||||||
|
dwRemainder = (10*(dwFileSize - dwNumber * dwKB) / dwKB);
|
||||||
|
strNumber << separate_thousands(dwNumber) << "," << (int)dwRemainder << " KB";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dwFileSize < dwGB)
|
||||||
|
{
|
||||||
|
dwNumber = dwFileSize / dwMB;
|
||||||
|
dwRemainder = (10*(dwFileSize - dwNumber * dwMB) / dwMB);
|
||||||
|
strNumber << separate_thousands(dwNumber) << "," << (int)dwRemainder << " MB";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dwFileSize >= dwGB)
|
||||||
|
{
|
||||||
|
dwNumber = dwFileSize / dwGB;
|
||||||
|
dwRemainder = (10*(dwFileSize - dwNumber * dwGB) / dwGB);
|
||||||
|
strNumber << separate_thousands(dwNumber) << "," << (int)dwRemainder << " GB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *foo_browsefiles::get_path_parent(char *path)
|
||||||
|
{
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
if ( strlen(path) == 0
|
||||||
|
|| (strlen(path) <= 3) // root - nowhere to get upwards to or
|
||||||
|
|| strstr(path, "Network") == path ) // some drive root - getting up to root
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ( (strlen(path) > 3) // some path - getting up one level
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *end = (path + strlen(path) - 2); //skip trailing slash
|
||||||
|
while (end >= path && *end-- != '\\');
|
||||||
|
end += 2;
|
||||||
|
|
||||||
|
result = new char [strlen(path)];
|
||||||
|
memset (result, 0, strlen(path));
|
||||||
|
char *result_ptr = result;
|
||||||
|
|
||||||
|
while (path != end)
|
||||||
|
*(result_ptr++) = *(path++);
|
||||||
|
|
||||||
|
if (strlen(result) == 2 && result[0] == '\\')
|
||||||
|
{
|
||||||
|
delete[] result;
|
||||||
|
result = new char[16];
|
||||||
|
strcpy_s(result, 15, "Network:\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foo_browsefiles::ENTRY_TYPE foo_browsefiles::get_path_type(char *path)
|
||||||
|
{
|
||||||
|
if (strlen(path) < 3)
|
||||||
|
return ET_ROOT;
|
||||||
|
|
||||||
|
if (path[strlen(path)-1] != '\\')
|
||||||
|
return ET_FILE;
|
||||||
|
|
||||||
|
if (strcmp(path, "Network:\\") == 0)
|
||||||
|
return ET_NETWORK;
|
||||||
|
|
||||||
|
int slashes_count = 0;
|
||||||
|
char *path_ptr = path;
|
||||||
|
for (unsigned int i = 0; i < strlen(path); ++i)
|
||||||
|
if (*path_ptr++ == '\\')
|
||||||
|
++slashes_count;
|
||||||
|
|
||||||
|
if ((strstr(path, "\\") == path)
|
||||||
|
&& (slashes_count == 3))
|
||||||
|
return ET_NETWORK_PC;
|
||||||
|
|
||||||
|
if (path[strlen(path)-1] == '\\')
|
||||||
|
return ET_DIR;
|
||||||
|
|
||||||
|
return ET_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo_browsefiles::scan_network(ENTRY_TYPE searchfor, char *path, NETRESOURCE *pNr)
|
||||||
|
{
|
||||||
|
HANDLE hEnum;
|
||||||
|
DWORD dwRes;
|
||||||
|
|
||||||
|
dwRes = WNetOpenEnum( RESOURCE_GLOBALNET, RESOURCETYPE_DISK, 0, pNr, &hEnum);
|
||||||
|
|
||||||
|
if(dwRes!=NO_ERROR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NETRESOURCE NetResource[MAX_NET_RESOURCES];
|
||||||
|
DWORD dwCount = 0xFFFFFFFF, dwSize = sizeof(NETRESOURCE)*MAX_NET_RESOURCES;
|
||||||
|
|
||||||
|
dwRes = WNetEnumResource(hEnum, &dwCount, (LPVOID*)&NetResource, &dwSize);
|
||||||
|
|
||||||
|
if(dwRes!=NO_ERROR)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dw;
|
||||||
|
for(dw=0; dw < dwCount; dw++)
|
||||||
|
{
|
||||||
|
pfc::string8 remoteName;
|
||||||
|
pfc::stringcvt::string_utf8_from_wide buf(NetResource[dw].lpRemoteName);
|
||||||
|
remoteName << buf << "\\";
|
||||||
|
|
||||||
|
if ( (searchfor == ET_NETWORK_PC)
|
||||||
|
&& (NetResource[dw].dwUsage & RESOURCEUSAGE_CONTAINER)
|
||||||
|
&& (NetResource[dw].dwDisplayType == RESOURCEDISPLAYTYPE_SERVER) )
|
||||||
|
{
|
||||||
|
entries.add_item(entry_data(ET_NETWORK_PC, remoteName, "", 0, "", "", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (searchfor == ET_NETWORK_PC_SHARE &&
|
||||||
|
(strstr(remoteName, path) == remoteName)
|
||||||
|
)
|
||||||
|
&& (NetResource[dw].dwUsage & RESOURCEUSAGE_CONNECTABLE)
|
||||||
|
&& (NetResource[dw].dwDisplayType == RESOURCEDISPLAYTYPE_SHARE
|
||||||
|
&& NetResource[dw].dwType == RESOURCETYPE_DISK) )
|
||||||
|
{
|
||||||
|
entries.add_item(entry_data(ET_NETWORK_PC_SHARE, remoteName, "", 0, "", "", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(NetResource[dw].dwUsage & RESOURCEUSAGE_CONTAINER)
|
||||||
|
scan_network(searchfor, path, &NetResource[dw]);
|
||||||
|
}
|
||||||
|
|
||||||
|
WNetCloseEnum(hEnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foo_browsefiles::browse(pfc::string8 path)
|
||||||
|
{
|
||||||
|
entries.remove_all();
|
||||||
|
|
||||||
|
ENTRY_TYPE e_t = get_path_type(const_cast<char *>(path.toString()));
|
||||||
|
|
||||||
|
if (e_t == ET_ROOT)
|
||||||
|
{
|
||||||
|
if (cfg.restrict_to_path_list.get_count() > 0)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < cfg.restrict_to_path_list.get_count(); ++i)
|
||||||
|
entries.add_item(entry_data(ET_DIR, cfg.restrict_to_path_list[i], "", 0, "", "", ""));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD ld = GetLogicalDrives();
|
||||||
|
|
||||||
|
char drive[] = "A\0";
|
||||||
|
|
||||||
|
for (int i = 0; i <= 26; ++i,ld = ld >> 1, ++drive[0])
|
||||||
|
if ((ld & 1) == 1)
|
||||||
|
{
|
||||||
|
pfc::string8 path;
|
||||||
|
path << drive << ":\\";
|
||||||
|
pfc::string8 comment;
|
||||||
|
UINT d_type = GetDriveTypeA(path.toString());
|
||||||
|
switch (d_type)
|
||||||
|
{
|
||||||
|
case DRIVE_UNKNOWN: comment = "Unknown drive type"; break;
|
||||||
|
case DRIVE_NO_ROOT_DIR: comment = "No root directory"; break;
|
||||||
|
case DRIVE_REMOVABLE: comment = "Removable"; break;
|
||||||
|
case DRIVE_FIXED: comment = "Fixed"; break;
|
||||||
|
case DRIVE_REMOTE: comment = "Remote (network)"; break;
|
||||||
|
case DRIVE_CDROM: comment = "CD/DVD"; break;
|
||||||
|
case DRIVE_RAMDISK: comment = "RAM"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char fsname[64] = {0};
|
||||||
|
char volname[64] = {0};
|
||||||
|
GetVolumeInformationA(path.operator const char *(),
|
||||||
|
volname,
|
||||||
|
64,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
fsname,
|
||||||
|
64
|
||||||
|
);
|
||||||
|
|
||||||
|
entries.add_item(entry_data(ET_DIR, path, "", 0, fsname, volname, comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.add_item(entry_data(ET_NETWORK, "Network:\\", "", 0, "", "", "Microsoft LAN"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e_t == ET_DIR || e_t == ET_NETWORK_PC_SHARE)
|
||||||
|
{
|
||||||
|
HANDLE hFind;
|
||||||
|
LPWIN32_FIND_DATAW findFileData;
|
||||||
|
findFileData = new WIN32_FIND_DATAW;
|
||||||
|
|
||||||
|
pfc::string8 mask;
|
||||||
|
mask << path << "*";
|
||||||
|
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 mask_w(mask);
|
||||||
|
|
||||||
|
hFind = FindFirstFileW(mask_w, findFileData);
|
||||||
|
|
||||||
|
if (hFind != INVALID_HANDLE_VALUE)
|
||||||
|
do
|
||||||
|
if (! ( (wcsstr(findFileData->cFileName, TEXT("..")) == findFileData->cFileName || wcsstr(findFileData->cFileName, TEXT(".")) == findFileData->cFileName ) && ( (findFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
entry_data entry;
|
||||||
|
|
||||||
|
pfc::stringcvt::string_utf8_from_wide e_path (findFileData->cFileName);
|
||||||
|
entry.path << path << e_path;
|
||||||
|
|
||||||
|
if ( (findFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
entry.type = ET_DIR;
|
||||||
|
else
|
||||||
|
entry.type = ET_FILE;
|
||||||
|
|
||||||
|
// format entry modification time
|
||||||
|
format_time(&(findFileData->ftLastWriteTime), entry.time, 0);
|
||||||
|
|
||||||
|
// format entry file name
|
||||||
|
entry.filename = entry.path;
|
||||||
|
|
||||||
|
entry.filename.remove_chars(0, entry.filename.find_last('\\') + 1);
|
||||||
|
|
||||||
|
// format entry size
|
||||||
|
entry.size = ((t_uint64)findFileData->nFileSizeHigh << 8) | findFileData->nFileSizeLow;
|
||||||
|
if (entry.type == ET_FILE)
|
||||||
|
entry.size_str << format_size((DWORD)entry.size);
|
||||||
|
|
||||||
|
if (entry.type == ET_DIR)
|
||||||
|
entry.path << "\\";
|
||||||
|
|
||||||
|
entries.add_item(entry);
|
||||||
|
} while (FindNextFileW(hFind, findFileData) != NULL);
|
||||||
|
FindClose(hFind);
|
||||||
|
delete findFileData;
|
||||||
|
entries.sort_t(sortfunc_natural);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (e_t == ET_NETWORK
|
||||||
|
|| e_t == ET_NETWORK_PC)
|
||||||
|
{
|
||||||
|
if (e_t == ET_NETWORK)
|
||||||
|
e_t = ET_NETWORK_PC;
|
||||||
|
else
|
||||||
|
if (e_t == ET_NETWORK_PC)
|
||||||
|
e_t = ET_NETWORK_PC_SHARE;
|
||||||
|
|
||||||
|
scan_network(e_t, const_cast<char *>(path.toString()), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
70
foo_httpcontrol/src/browsefiles.h
Executable file
@@ -0,0 +1,70 @@
|
|||||||
|
#ifndef ___BROWSEFILES_H___
|
||||||
|
#define ___BROWSEFILES_H___
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
|
|
||||||
|
#pragma comment(lib, "mpr.lib")
|
||||||
|
|
||||||
|
#include <Winnetwk.h>
|
||||||
|
#include <lm.h>
|
||||||
|
|
||||||
|
class foo_browsefiles
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ENTRY_TYPE
|
||||||
|
{
|
||||||
|
ET_DRIVE,
|
||||||
|
ET_DIR,
|
||||||
|
ET_FILE,
|
||||||
|
ET_NETWORK,
|
||||||
|
ET_NETWORK_PC,
|
||||||
|
ET_NETWORK_PC_SHARE,
|
||||||
|
ET_ROOT,
|
||||||
|
ET_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
class entry_data
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ENTRY_TYPE type; // type of entry
|
||||||
|
pfc::string8 path; // full path to entry
|
||||||
|
pfc::string8 filename; // entry file name
|
||||||
|
pfc::string8 comment; // entry comment
|
||||||
|
t_uint64 size; // entry size (bytes)
|
||||||
|
pfc::string8 size_str; // human readable size
|
||||||
|
pfc::string8 time; // entry last modificaton time
|
||||||
|
|
||||||
|
entry_data() { };
|
||||||
|
entry_data(ENTRY_TYPE _type, pfc::string8 _path, pfc::string8 _filename, int _size, pfc::string8 _size_str, pfc::string8 _time, pfc::string8 _comment)
|
||||||
|
: type(_type), path(_path), filename(_filename), size(_size), size_str(_size_str), time(_time), comment(_comment) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
class path_entry_data
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
pfc::string8 cmd;
|
||||||
|
pfc::string8 url;
|
||||||
|
|
||||||
|
path_entry_data() { };
|
||||||
|
path_entry_data(pfc::string8 _cmd, pfc::string8 _url)
|
||||||
|
: cmd(_cmd), url(_url) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* static int sortfunc(entry_data & p1, entry_data & p2) {return stricmp_utf8(p1.path.operator const char *(),p2.path.operator const char *());}*/
|
||||||
|
static int sortfunc_natural(entry_data & p1, entry_data & p2) { return compare_natural_utf8(p1.path, p2.path); }
|
||||||
|
|
||||||
|
ENTRY_TYPE get_path_type(char *);
|
||||||
|
void scan_network(ENTRY_TYPE searchfor, char *path, NETRESOURCE *pNr);
|
||||||
|
public:
|
||||||
|
pfc::list_t<entry_data> entries;
|
||||||
|
|
||||||
|
bool browse(pfc::string8 path);
|
||||||
|
void buildpath_list(pfc::string8 path, pfc::list_t<path_entry_data> &res);
|
||||||
|
|
||||||
|
static char *get_path_parent(char *path);
|
||||||
|
pfc::string8 separate_thousands(DWORD number);
|
||||||
|
pfc::string8 format_size(DWORD filesize);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //___BROWSEFILES_H___
|
||||||
308
foo_httpcontrol/src/callbacks.cpp
Executable file
@@ -0,0 +1,308 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "httpcontrol.h"
|
||||||
|
|
||||||
|
struct sac {
|
||||||
|
class callback_sac_off : public main_thread_callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void callback_run()
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playback_control>()->set_stop_after_current(false);
|
||||||
|
httpc::sac = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class callback_sac_on : public main_thread_callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void callback_run()
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playback_control>()->set_stop_after_current(true);
|
||||||
|
httpc::sac = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static void on () {
|
||||||
|
service_ptr_t<callback_sac_on> myc = new service_impl_t<callback_sac_on>();
|
||||||
|
static_api_ptr_t<main_thread_callback_manager>()->add_callback(myc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void off() {
|
||||||
|
service_ptr_t<callback_sac_off> myc = new service_impl_t<callback_sac_off>();
|
||||||
|
static_api_ptr_t<main_thread_callback_manager>()->add_callback(myc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class callbacks : private play_callback_impl_base, private playlist_callback_impl_base {
|
||||||
|
public:
|
||||||
|
void on_playback_starting(play_control::t_track_command p_command, bool p_paused)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYBACK;
|
||||||
|
httpc::pb_state = p_paused ? httpc::FOO_PAUSED : httpc::FOO_PLAYING;
|
||||||
|
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playback_new_track(metadb_handle_ptr p_track)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYBACK;
|
||||||
|
|
||||||
|
if (cfg.misc.stop_after_queue && static_api_ptr_t<playlist_manager>()->queue_get_count() == 1)
|
||||||
|
{
|
||||||
|
httpc::reset_sac = true;
|
||||||
|
sac::on();
|
||||||
|
}
|
||||||
|
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
httpc::update_previouslyplayed();
|
||||||
|
httpc::pb_item = pfc::infinite_size ;
|
||||||
|
httpc::pb_time = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playback_stop(play_control::t_stop_reason reason)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYBACK;
|
||||||
|
|
||||||
|
httpc::update_previouslyplayed();
|
||||||
|
httpc::empty_info();
|
||||||
|
|
||||||
|
if (cfg.misc.stop_after_queue && httpc::reset_sac)
|
||||||
|
{
|
||||||
|
httpc::reset_sac = false;
|
||||||
|
sac::off();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playback_seek(double p_time)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYBACK;
|
||||||
|
httpc::pb_time = p_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playback_pause(bool p_state)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYBACK;
|
||||||
|
httpc::pb_state = p_state ? httpc::FOO_PAUSED : httpc::FOO_PLAYING;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playback_time(double p_time)
|
||||||
|
{
|
||||||
|
httpc::pb_time = p_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_volume_change(float p_new_val)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_VOLUME;
|
||||||
|
httpc::refresh_volume(p_new_val);
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_items_added(t_size p_playlist,t_size p_start, const pfc::list_base_const_t<metadb_handle_ptr> & p_data,const pfc::bit_array & p_selection)
|
||||||
|
{
|
||||||
|
if (static_api_ptr_t<playlist_manager>()->get_active_playlist() == p_playlist)
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_playlist_total_time = true;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_items_reordered(t_size p_playlist,const t_size * p_order,t_size p_count)
|
||||||
|
{
|
||||||
|
if (p_order && p_count && (p_playlist == static_api_ptr_t<playlist_manager>()->get_active_playlist()))
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_items_removed(t_size p_playlist,const pfc::bit_array & p_mask,t_size p_old_count,t_size p_new_count)
|
||||||
|
{
|
||||||
|
if (p_playlist == static_api_ptr_t<playlist_manager>()->get_active_playlist())
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_playlist_total_time = true;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
}
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
httpc::empty_previouslyplayed();
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_item_focus_change(t_size p_playlist,t_size p_from,t_size p_to)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_items_modified(t_size p_playlist,const pfc::bit_array & p_mask)
|
||||||
|
{
|
||||||
|
if (p_playlist == static_api_ptr_t<playlist_manager>()->get_active_playlist())
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_items_replaced(t_size p_playlist,const pfc::bit_array & p_mask,const pfc::list_base_const_t<t_on_items_replaced_entry> & p_data)
|
||||||
|
{
|
||||||
|
if (p_playlist == static_api_ptr_t<playlist_manager>()->get_active_playlist())
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_playlist_total_time = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playlist_activate(t_size p_old,t_size p_new)
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_playlist_total_time = true;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playlist_created(t_size p_index,const char * p_name,t_size p_name_len)
|
||||||
|
{
|
||||||
|
if (p_index == static_api_ptr_t<playlist_manager>()->get_active_playlist())
|
||||||
|
{
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_playlist_total_time = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST | httpc::FSC_PLAYLISTS;
|
||||||
|
}
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playlists_reorder(const t_size * p_order,t_size p_count)
|
||||||
|
{
|
||||||
|
httpc::query_playlist = static_api_ptr_t<playlist_manager>()->find_playlist(cfg.misc.query_playlist_name);
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLISTS;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playlists_removed(const pfc::bit_array & p_mask,t_size p_old_count,t_size p_new_count)
|
||||||
|
{
|
||||||
|
httpc::query_playlist = static_api_ptr_t<playlist_manager>()->find_playlist(cfg.misc.query_playlist_name);
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLISTS;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playlist_renamed(t_size p_index,const char * p_new_name,t_size p_new_name_len)
|
||||||
|
{
|
||||||
|
if (p_index == httpc::query_playlist)
|
||||||
|
cfg.misc.query_playlist_name = p_new_name;
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYLIST;
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
void on_playback_order_changed(t_size p_new_index)
|
||||||
|
{
|
||||||
|
httpc::state_changed |= httpc::FSC_PLAYBACK_ORDER;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class oninitquit : public initquit {
|
||||||
|
private:
|
||||||
|
callbacks *callbacks_ptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
oninitquit() { callbacks_ptr = NULL; }
|
||||||
|
|
||||||
|
virtual void on_init()
|
||||||
|
{
|
||||||
|
httpc::empty_info();
|
||||||
|
httpc::empty_previouslyplayed();
|
||||||
|
httpc::control::set_active(cfg.main.startserver);
|
||||||
|
httpc::ui::gen::gen_func_table();
|
||||||
|
httpc::control::gen_cmd_table();
|
||||||
|
|
||||||
|
InitializeCriticalSection(&httpc::cs);
|
||||||
|
|
||||||
|
// get registered extensions list
|
||||||
|
httpc::get_registered_extensions();
|
||||||
|
httpc::control_credentials_auth_hash_update();
|
||||||
|
|
||||||
|
// getting hang of where do we get templates and stuff
|
||||||
|
httpc::fb2k_profile_path = pfc::string8(file_path_display(core_api::get_profile_path())) << "\\foo_httpcontrol_data";
|
||||||
|
httpc::choose_srv_home_dir();
|
||||||
|
|
||||||
|
// getting fb2k executable path
|
||||||
|
HMODULE instance = GetModuleHandleW(NULL);
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
if (GetModuleFileNameW(instance, path, MAX_PATH) != 0)
|
||||||
|
httpc::fb2k_path = pfc::stringcvt::string_utf8_from_wide((const wchar_t*)path);
|
||||||
|
else
|
||||||
|
foo_info("coudln't retrieve foobar2000 executable path");
|
||||||
|
|
||||||
|
httpc::build_restrict_to_path_list();
|
||||||
|
|
||||||
|
// find out Query playlist index for later use
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
httpc::query_playlist = plm->find_playlist(cfg.misc.query_playlist_name);
|
||||||
|
|
||||||
|
// filling in initial data
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::should_update_playlists_list = true;
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
|
||||||
|
callbacks_ptr = new callbacks;
|
||||||
|
|
||||||
|
service_enum_t<contextmenu_item> e;
|
||||||
|
service_ptr_t<contextmenu_item> ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void on_quit()
|
||||||
|
{
|
||||||
|
if (httpc::control::is_active())
|
||||||
|
httpc::control::set_active(false);
|
||||||
|
|
||||||
|
httpc::script_playlist_row.release();
|
||||||
|
httpc::script_helper1.release();
|
||||||
|
httpc::script_helper2.release();
|
||||||
|
httpc::script_helper3.release();
|
||||||
|
|
||||||
|
delete callbacks_ptr;
|
||||||
|
|
||||||
|
DeleteCriticalSection(&httpc::cs);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static initquit_factory_t<oninitquit> g_oninitquit;
|
||||||
|
|
||||||
|
class queue_foo_httpcontrol : public playback_queue_callback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void on_changed(t_change_origin p_origin)
|
||||||
|
{
|
||||||
|
if (cfg.misc.stop_after_queue)
|
||||||
|
{
|
||||||
|
if (static_api_ptr_t<playback_control>()->is_playing())
|
||||||
|
{
|
||||||
|
if (static_api_ptr_t<playlist_manager>()->queue_get_count() == 0)
|
||||||
|
{
|
||||||
|
httpc::reset_sac = true;
|
||||||
|
sac::on();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
httpc::reset_sac = false;
|
||||||
|
sac::off();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static play_callback_static_factory_t<queue_foo_httpcontrol> foo_queue_playback;
|
||||||
1151
foo_httpcontrol/src/commands.cpp
Executable file
595
foo_httpcontrol/src/config.cpp
Executable file
@@ -0,0 +1,595 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
template_config tcfg;
|
||||||
|
|
||||||
|
// {555F213A-FBF5-44c5-AFD1-7B2307F92674}
|
||||||
|
static const GUID guid_cfg = { 0x555f213a, 0xfbf5, 0x44c5, { 0xaf, 0xd1, 0x7b, 0x23, 0x7, 0xf9, 0x26, 0x74 } };
|
||||||
|
config cfg(guid_cfg);
|
||||||
|
|
||||||
|
void config_main::copy(const config_main &cfg)
|
||||||
|
{
|
||||||
|
ip = cfg.ip;
|
||||||
|
port = cfg.port;
|
||||||
|
startserver = cfg.startserver;
|
||||||
|
albumart_embedded_retrieve = cfg.albumart_embedded_retrieve;
|
||||||
|
retrieve_playlist = cfg.retrieve_playlist;
|
||||||
|
hide_nonplayables = cfg.hide_nonplayables;
|
||||||
|
log_access = cfg.log_access;
|
||||||
|
server_root = cfg.server_root;
|
||||||
|
control_ip = cfg.control_ip;
|
||||||
|
control_credentials = cfg.control_credentials;
|
||||||
|
control_credentials_username = cfg.control_credentials_username;
|
||||||
|
control_credentials_password = cfg.control_credentials_password;
|
||||||
|
restrict_to_path = cfg.restrict_to_path;
|
||||||
|
allow_commandline = cfg.allow_commandline;
|
||||||
|
stop_after_queue_enable = cfg.stop_after_queue_enable;
|
||||||
|
gzip_enable = cfg.gzip_enable;
|
||||||
|
extra_formats = cfg.extra_formats;
|
||||||
|
ignored_formats = cfg.ignored_formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_main::reset()
|
||||||
|
{
|
||||||
|
ip = "0.0.0.0";
|
||||||
|
port = 8888;
|
||||||
|
startserver = true;
|
||||||
|
albumart_embedded_retrieve = false;
|
||||||
|
retrieve_playlist = true;
|
||||||
|
hide_nonplayables = false;
|
||||||
|
log_access = false;
|
||||||
|
server_root = "";
|
||||||
|
control_ip = "0.0.0.0";
|
||||||
|
control_credentials = false;
|
||||||
|
control_credentials_username = "";
|
||||||
|
control_credentials_password = "";
|
||||||
|
restrict_to_path = "";
|
||||||
|
allow_commandline = false;
|
||||||
|
stop_after_queue_enable = false;
|
||||||
|
gzip_enable = false;
|
||||||
|
extra_formats = "zip|rar";
|
||||||
|
ignored_formats = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_main::get_data_raw(stream_writer * p_stream,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
p_stream->write_lendian_t(albumart_embedded_retrieve, p_abort);
|
||||||
|
p_stream->write_lendian_t(allow_commandline, p_abort);
|
||||||
|
p_stream->write_lendian_t(control_credentials, p_abort);
|
||||||
|
p_stream->write_string(control_credentials_password, p_abort);
|
||||||
|
p_stream->write_string(control_credentials_username, p_abort);
|
||||||
|
p_stream->write_string(control_ip, p_abort);
|
||||||
|
p_stream->write_lendian_t(hide_nonplayables, p_abort);
|
||||||
|
p_stream->write_string(ip, p_abort);
|
||||||
|
p_stream->write_lendian_t(log_access, p_abort);
|
||||||
|
p_stream->write_lendian_t(port, p_abort);
|
||||||
|
p_stream->write_string(restrict_to_path, p_abort);
|
||||||
|
p_stream->write_lendian_t(retrieve_playlist, p_abort);
|
||||||
|
p_stream->write_string(server_root, p_abort);
|
||||||
|
p_stream->write_lendian_t(startserver, p_abort);
|
||||||
|
p_stream->write_lendian_t(stop_after_queue_enable, p_abort);
|
||||||
|
p_stream->write_lendian_t(gzip_enable, p_abort);
|
||||||
|
p_stream->write_string(extra_formats, p_abort);
|
||||||
|
p_stream->write_string(ignored_formats, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_main::set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
p_stream->read_lendian_t(albumart_embedded_retrieve, p_abort);
|
||||||
|
p_stream->read_lendian_t(allow_commandline, p_abort);
|
||||||
|
p_stream->read_lendian_t(control_credentials, p_abort);
|
||||||
|
p_stream->read_string(control_credentials_password, p_abort);
|
||||||
|
p_stream->read_string(control_credentials_username, p_abort);
|
||||||
|
p_stream->read_string(control_ip, p_abort);
|
||||||
|
p_stream->read_lendian_t(hide_nonplayables, p_abort);
|
||||||
|
p_stream->read_string(ip, p_abort);
|
||||||
|
p_stream->read_lendian_t(log_access, p_abort);
|
||||||
|
p_stream->read_lendian_t(port, p_abort);
|
||||||
|
p_stream->read_string(restrict_to_path, p_abort);
|
||||||
|
p_stream->read_lendian_t(retrieve_playlist, p_abort);
|
||||||
|
p_stream->read_string(server_root, p_abort);
|
||||||
|
p_stream->read_lendian_t(startserver, p_abort);
|
||||||
|
p_stream->read_lendian_t(stop_after_queue_enable, p_abort);
|
||||||
|
p_stream->read_lendian_t(gzip_enable, p_abort);
|
||||||
|
p_stream->read_string(extra_formats, p_abort);
|
||||||
|
p_stream->read_string(ignored_formats, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool config_main::operator == (const config_main &c)
|
||||||
|
{
|
||||||
|
return ((c.ip == ip)
|
||||||
|
&&(c.port == port)
|
||||||
|
&&(c.startserver == startserver)
|
||||||
|
&&(c.albumart_embedded_retrieve == albumart_embedded_retrieve)
|
||||||
|
&&(c.retrieve_playlist == retrieve_playlist)
|
||||||
|
&&(c.hide_nonplayables == hide_nonplayables)
|
||||||
|
&&(c.log_access == log_access)
|
||||||
|
&&(c.server_root == server_root)
|
||||||
|
&&(c.control_ip == control_ip)
|
||||||
|
&&(c.control_credentials == control_credentials)
|
||||||
|
&&(c.control_credentials_username == control_credentials_username)
|
||||||
|
&&(c.control_credentials_password == control_credentials_password)
|
||||||
|
&&(c.restrict_to_path == restrict_to_path)
|
||||||
|
&&(c.allow_commandline == allow_commandline)
|
||||||
|
&&(c.stop_after_queue_enable == stop_after_queue_enable)
|
||||||
|
&&(c.gzip_enable == gzip_enable)
|
||||||
|
&&(c.extra_formats == extra_formats)
|
||||||
|
&&(c.ignored_formats == ignored_formats));
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_misc::reset()
|
||||||
|
{
|
||||||
|
stop_after_queue = false;
|
||||||
|
last_browse_dir = "";
|
||||||
|
query_playlist_name = "Query";
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_misc::get_data_raw(stream_writer * p_stream,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
p_stream->write_lendian_t(stop_after_queue, p_abort);
|
||||||
|
p_stream->write_string(last_browse_dir, p_abort);
|
||||||
|
p_stream->write_string(query_playlist_name, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_misc::set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
p_stream->read_lendian_t(stop_after_queue, p_abort);
|
||||||
|
p_stream->read_string(last_browse_dir, p_abort);
|
||||||
|
p_stream->read_string(query_playlist_name, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_query::copy(const config_query &cfg)
|
||||||
|
{
|
||||||
|
sortpattern = cfg.sortpattern;
|
||||||
|
step1 = cfg.step1;
|
||||||
|
step2 = cfg.step2;
|
||||||
|
step3 = cfg.step3;
|
||||||
|
sendtodedicated = cfg.sendtodedicated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_query::reset()
|
||||||
|
{
|
||||||
|
sortpattern = "%date%|%artist%|%album%|%tracknumber%";
|
||||||
|
step1 = "%genre%";
|
||||||
|
step2 = "%artist%";
|
||||||
|
step3 = "%album%";
|
||||||
|
sendtodedicated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_query::get_data_raw(stream_writer * p_stream,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
p_stream->write_lendian_t(sendtodedicated, p_abort);
|
||||||
|
p_stream->write_string(sortpattern, p_abort);
|
||||||
|
p_stream->write_string(step1, p_abort);
|
||||||
|
p_stream->write_string(step2, p_abort);
|
||||||
|
p_stream->write_string(step3, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_query::set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
p_stream->read_lendian_t(sendtodedicated, p_abort);
|
||||||
|
p_stream->read_string(sortpattern, p_abort);
|
||||||
|
p_stream->read_string(step1, p_abort);
|
||||||
|
p_stream->read_string(step2, p_abort);
|
||||||
|
p_stream->read_string(step3, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool config_query::operator == (const config_query &c)
|
||||||
|
{
|
||||||
|
return ((c.sortpattern == sortpattern)
|
||||||
|
&& (c.step1 == step1)
|
||||||
|
&& (c.step2 == step2)
|
||||||
|
&& (c.step3 == step3)
|
||||||
|
&& (c.sendtodedicated == sendtodedicated));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool preferences_page_main::is_server_root_valid()
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (cfg_main_new.server_root.get_length())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foobar2000_io::abort_callback_dummy abort_c;
|
||||||
|
result = foobar2000_io::filesystem::g_exists(cfg_main_new.server_root, abort_c); // todo tofix g_exists
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::set_server_root_btn_state(bool state)
|
||||||
|
{
|
||||||
|
GetDlgItem(IDC_SERVER_ROOT_BTN).EnableWindow(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
|
||||||
|
{
|
||||||
|
switch(nID | (uNotifyCode << 16))
|
||||||
|
{
|
||||||
|
case IDC_INTERFACE | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.ip = string_utf8_from_window(wndCtl);
|
||||||
|
break;
|
||||||
|
case IDC_PORT | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.port = atoi(string_utf8_from_window(GetDlgItem(nID)));
|
||||||
|
break;
|
||||||
|
case IDC_SERVERSTARTED | BN_CLICKED:
|
||||||
|
cfg_main_new.startserver = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
break;
|
||||||
|
case IDC_SERVER_ROOT_BTN | (BN_CLICKED << 16):
|
||||||
|
{
|
||||||
|
pfc::string8 dir_to_open = cfg_main_new.server_root.get_length() == 0 ? httpc::srv_home_dir : cfg_main_new.server_root;
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 path_w(dir_to_open);
|
||||||
|
ShellExecute(NULL, _T("explore"), path_w, NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IDC_HIDE_NONPLAYABLES | (BN_CLICKED << 16):
|
||||||
|
cfg_main_new.hide_nonplayables = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
break;
|
||||||
|
case IDC_LOG_ACCESS | (BN_CLICKED << 16):
|
||||||
|
cfg_main_new.log_access = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
break;
|
||||||
|
case IDC_SERVER_ROOT | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.server_root = trim(pfc::string8(string_utf8_from_window(GetDlgItem(nID))));
|
||||||
|
set_server_root_btn_state(is_server_root_valid());
|
||||||
|
break;
|
||||||
|
case IDC_SERVER_ROOT | (EN_KILLFOCUS << 16):
|
||||||
|
if (!is_server_root_valid())
|
||||||
|
{
|
||||||
|
popup_message::g_show(pfc::string_formatter() << "It appears the home directory path you entered, " << cfg_main_new.server_root
|
||||||
|
<< ", is invalid. \n\nHome directory specifies the path foo_httpcontrol uses to look for templates.\nWhen left blank, it defaults to %APPDATA%\\foobar2000\\foo_httpcontrol if foobar2000 is installed in standard mode, or %FB2K_DIRECTORY%\\foo_httpcontrol if foobar2000 is installed in portable mode.",
|
||||||
|
"Home directory error", popup_message::icon_error);
|
||||||
|
set_server_root_btn_state(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_server_root_btn_state(true);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case IDC_LAUNCH_BROWSER | (BN_CLICKED << 16):
|
||||||
|
{
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 path_w(httpc::control::listener_info);
|
||||||
|
ShellExecute(NULL, _T("open"), path_w, NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IDC_CONTROL_IP | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.control_ip = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
break;
|
||||||
|
case IDC_CONTROL_CREDENTIALS | (BN_CLICKED << 16):
|
||||||
|
cfg_main_new.control_credentials = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
update_credentials();
|
||||||
|
break;
|
||||||
|
case IDC_CONTROL_PASSWORD | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.control_credentials_password = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_main_new.control_credentials_password = trim(cfg_main_new.control_credentials_password);
|
||||||
|
break;
|
||||||
|
case IDC_CONTROL_USERNAME | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.control_credentials_username = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_main_new.control_credentials_username = trim(cfg_main_new.control_credentials_username);
|
||||||
|
break;
|
||||||
|
case IDC_CONTROL_PATH | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.restrict_to_path = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_main_new.restrict_to_path = trim(cfg_main_new.restrict_to_path);
|
||||||
|
break;
|
||||||
|
case IDC_EXTRA_FORMATS | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.extra_formats = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_main_new.extra_formats = trim(cfg_main_new.extra_formats);
|
||||||
|
break;
|
||||||
|
case IDC_IGNORED_FORMATS | (EN_CHANGE << 16):
|
||||||
|
cfg_main_new.ignored_formats = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_main_new.ignored_formats = trim(cfg_main_new.ignored_formats);
|
||||||
|
break;
|
||||||
|
case IDC_STOP_AFTER_QUEUE_ENABLE | (BN_CLICKED << 16):
|
||||||
|
cfg_main_new.stop_after_queue_enable = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
break;
|
||||||
|
case IDC_GZIP_ENABLE | (BN_CLICKED << 16):
|
||||||
|
cfg_main_new.gzip_enable = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void preferences_page_main::update_credentials()
|
||||||
|
{
|
||||||
|
GetDlgItem(IDC_CONTROL_PASSWORD).EnableWindow(cfg_main_new.control_credentials);
|
||||||
|
GetDlgItem(IDC_CONTROL_USERNAME).EnableWindow(cfg_main_new.control_credentials);
|
||||||
|
GetDlgItem(IDC_STATIC_PASSWORD).EnableWindow(cfg_main_new.control_credentials);
|
||||||
|
GetDlgItem(IDC_STATIC_USERNAME).EnableWindow(cfg_main_new.control_credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::update_server_status()
|
||||||
|
{
|
||||||
|
if (!httpc::control::listener_error)
|
||||||
|
{
|
||||||
|
uSetDlgItemText(m_hWnd, IDC_LAUNCH_BROWSER, pfc::string_formatter() << "Open " << httpc::control::listener_info);
|
||||||
|
GetDlgItem(IDC_LAUNCH_BROWSER).EnableWindow(true);
|
||||||
|
}
|
||||||
|
if (httpc::control::listener_error)
|
||||||
|
{
|
||||||
|
SetDlgItemText(IDC_LAUNCH_BROWSER, _T("Bind failed"));
|
||||||
|
GetDlgItem(IDC_LAUNCH_BROWSER).EnableWindow(false);
|
||||||
|
}
|
||||||
|
if (!cfg_main_new.startserver)
|
||||||
|
{
|
||||||
|
SetDlgItemText(IDC_LAUNCH_BROWSER, _T(""));
|
||||||
|
GetDlgItem(IDC_LAUNCH_BROWSER).EnableWindow(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::updateDialog()
|
||||||
|
{
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_INTERFACE, cfg_main_new.ip);
|
||||||
|
SetDlgItemInt(IDC_PORT, cfg_main_new.port);
|
||||||
|
CheckDlgButton(IDC_SERVERSTARTED,cfg_main_new.startserver);
|
||||||
|
CheckDlgButton(IDC_HIDE_NONPLAYABLES,cfg_main_new.hide_nonplayables);
|
||||||
|
CheckDlgButton(IDC_LOG_ACCESS,cfg_main_new.log_access);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_CONTROL_IP,cfg_main_new.control_ip);
|
||||||
|
CheckDlgButton(IDC_CONTROL_CREDENTIALS,cfg_main_new.control_credentials);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_CONTROL_USERNAME,cfg_main_new.control_credentials_username);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_CONTROL_PASSWORD,cfg_main_new.control_credentials_password);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_CONTROL_PATH,cfg_main_new.restrict_to_path);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_EXTRA_FORMATS,cfg_main_new.extra_formats);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_IGNORED_FORMATS,cfg_main_new.ignored_formats);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_SERVER_ROOT,cfg_main_new.server_root);
|
||||||
|
CheckDlgButton(IDC_STOP_AFTER_QUEUE_ENABLE,cfg_main_new.stop_after_queue_enable);
|
||||||
|
CheckDlgButton(IDC_GZIP_ENABLE,cfg_main_new.gzip_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL preferences_page_main::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
|
||||||
|
{
|
||||||
|
updateDialog();
|
||||||
|
update_credentials();
|
||||||
|
update_server_status();
|
||||||
|
|
||||||
|
set_server_root_btn_state(is_server_root_valid());
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_uint32 preferences_page_main::get_state() {
|
||||||
|
t_uint32 state = preferences_state::resettable;
|
||||||
|
if (!(cfg.main == cfg_main_new)) state |= preferences_state::changed;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::reset() {
|
||||||
|
cfg_main_new.reset();
|
||||||
|
|
||||||
|
updateDialog();
|
||||||
|
update_credentials();
|
||||||
|
update_server_status();
|
||||||
|
|
||||||
|
onChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::apply() {
|
||||||
|
if (httpc::control::running_threads == 0)
|
||||||
|
{
|
||||||
|
cfg.main = cfg_main_new;
|
||||||
|
|
||||||
|
httpc::choose_srv_home_dir();
|
||||||
|
|
||||||
|
httpc::control_credentials_auth_hash_update();
|
||||||
|
|
||||||
|
httpc::get_registered_extensions();
|
||||||
|
|
||||||
|
httpc::build_restrict_to_path_list();
|
||||||
|
|
||||||
|
if (cfg.main.startserver != httpc::control::is_active())
|
||||||
|
httpc::control::set_active(cfg.main.startserver);
|
||||||
|
|
||||||
|
update_server_status();
|
||||||
|
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
httpc::should_update_queue = true;
|
||||||
|
|
||||||
|
if (!cfg.main.stop_after_queue_enable)
|
||||||
|
cfg.misc.stop_after_queue = false;
|
||||||
|
|
||||||
|
onChanged();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
popup_message::g_show(pfc::string_formatter() << "Client request proceesing is active, settings not saved.\nPlease press Apply when request is processed.",
|
||||||
|
"Warning", popup_message::icon_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_main::onChanged() {
|
||||||
|
m_callback->on_state_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void config::get_data_raw(stream_writer * p_stream,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
cfg.main.get_data_raw(p_stream, p_abort);
|
||||||
|
cfg.query.get_data_raw(p_stream, p_abort);
|
||||||
|
cfg.misc.get_data_raw(p_stream, p_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void config::set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cfg.main.set_data_raw(p_stream, p_sizehint, p_abort);
|
||||||
|
cfg.query.set_data_raw(p_stream, p_sizehint, p_abort);
|
||||||
|
cfg.misc.set_data_raw(p_stream, p_sizehint, p_abort);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_size template_config::find(pfc::string8 &name)
|
||||||
|
{
|
||||||
|
if (name.get_length())
|
||||||
|
{
|
||||||
|
t_size l = cfg.get_count();
|
||||||
|
for (t_size i = 0; i < l; ++i)
|
||||||
|
if (pfc::stringCompareCaseInsensitive(name, get(i).root) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfc::infinite_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool template_config::loadtemplate(pfc::string_base &path, pfc::string8 &tpl_name)
|
||||||
|
{
|
||||||
|
if (tpl_name.get_length() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foobar2000_io::t_filetimestamp timestamp;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foobar2000_io::t_filestats filestats;
|
||||||
|
foobar2000_io::abort_callback_dummy abort_c;
|
||||||
|
bool is_writeable;
|
||||||
|
|
||||||
|
foobar2000_io::filesystem::g_get_stats(path, filestats, is_writeable, abort_c);
|
||||||
|
|
||||||
|
timestamp = filestats.m_timestamp;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_size n = find(tpl_name);
|
||||||
|
|
||||||
|
if (n != pfc::infinite_size && (timestamp == get(n).timestamp)) // template already loaded and config timestamp didn't change
|
||||||
|
{
|
||||||
|
choose(n);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// template is not loaded or config timestamp changed;
|
||||||
|
|
||||||
|
pfc::string8 tmp;
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 path_w(path);
|
||||||
|
|
||||||
|
if (n == pfc::infinite_size )
|
||||||
|
{
|
||||||
|
set_size(cfg.get_count() + 1);
|
||||||
|
n = cfg.get_count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
choose(n);
|
||||||
|
|
||||||
|
get().timestamp = timestamp;
|
||||||
|
get().root = tpl_name;
|
||||||
|
read_ini_key("url", get().url, path_w);
|
||||||
|
read_ini_key("playlist_row", get().playlist_row, path_w);
|
||||||
|
read_ini_key("helper1", get().helper1, path_w);
|
||||||
|
read_ini_key("helper2", get().helper2, path_w);
|
||||||
|
read_ini_key("helper3", get().helper3, path_w);
|
||||||
|
read_ini_key("albumart", get().albumart, path_w);
|
||||||
|
read_ini_key("albumart_not_found", tmp, path_w);
|
||||||
|
if (tmp.get_length() && tmp[0] != '/')
|
||||||
|
get().albumart_not_found = pfc::string_formatter("/") << tmp;
|
||||||
|
else
|
||||||
|
get().albumart_not_found = tmp;
|
||||||
|
|
||||||
|
read_ini_key("albumart_not_available", tmp, path_w);
|
||||||
|
if (tmp.get_length() && tmp[0] != '/')
|
||||||
|
get().albumart_not_available = pfc::string_formatter("/") << tmp;
|
||||||
|
else
|
||||||
|
get().albumart_not_available = tmp;
|
||||||
|
|
||||||
|
read_ini_key("playlist_items_per_page", tmp, path_w);
|
||||||
|
t_size item_count = atoi(tmp);
|
||||||
|
|
||||||
|
get().playlist_items_per_page = item_count > PLAYLIST_ITEMS_PER_PAGE_MAX ? PLAYLIST_ITEMS_PER_PAGE_MAX : item_count;
|
||||||
|
|
||||||
|
read_ini_key("albumart_limit_size", tmp, path_w);
|
||||||
|
get().albumart_limit_size = atoi(tmp);
|
||||||
|
|
||||||
|
read_ini_key("albumart_prefer_embedded", tmp, path_w);
|
||||||
|
get().albumart_prefer_embedded = atoi(tmp) == 1? true : false;
|
||||||
|
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
httpc::choose_srv_home_dir();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_query::updateDialog()
|
||||||
|
{
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_AUTOPLAYLIST_SORT_PATTERN,cfg_query_new.sortpattern);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_AUTOPLAYLIST_QUERY_STEP1,cfg_query_new.step1);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_AUTOPLAYLIST_QUERY_STEP2,cfg_query_new.step2);
|
||||||
|
uSetDlgItemText(m_hWnd,IDC_AUTOPLAYLIST_QUERY_STEP3,cfg_query_new.step3);
|
||||||
|
CheckDlgButton(IDC_AUTOPLAYLIST_SENDTODEDICATED,cfg_query_new.sendtodedicated);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL preferences_page_query::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
|
||||||
|
{
|
||||||
|
updateDialog();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_query::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
|
||||||
|
{
|
||||||
|
switch(nID | (uNotifyCode << 16))
|
||||||
|
{
|
||||||
|
case (EN_CHANGE<<16) | IDC_AUTOPLAYLIST_SORT_PATTERN:
|
||||||
|
cfg_query_new.sortpattern = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_query_new.sortpattern = trim(cfg_query_new.sortpattern);
|
||||||
|
break;
|
||||||
|
case (EN_CHANGE<<16) | IDC_AUTOPLAYLIST_QUERY_STEP1:
|
||||||
|
cfg_query_new.step1 = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_query_new.step1 = trim(cfg_query_new.step1);
|
||||||
|
break;
|
||||||
|
case (EN_CHANGE<<16) | IDC_AUTOPLAYLIST_QUERY_STEP2:
|
||||||
|
cfg_query_new.step2 = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_query_new.step2 = trim(cfg_query_new.step2);
|
||||||
|
break;
|
||||||
|
case (EN_CHANGE<<16) | IDC_AUTOPLAYLIST_QUERY_STEP3:
|
||||||
|
cfg_query_new.step3 = string_utf8_from_window(GetDlgItem(nID));
|
||||||
|
cfg_query_new.step3 = trim(cfg_query_new.step3);
|
||||||
|
break;
|
||||||
|
case IDC_AUTOPLAYLIST_SENDTODEDICATED:
|
||||||
|
cfg_query_new.sendtodedicated = IsDlgButtonChecked(nID) == BST_CHECKED;
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_uint32 preferences_page_query::get_state() {
|
||||||
|
t_uint32 state = preferences_state::resettable;
|
||||||
|
if (!(cfg.query == cfg_query_new)) state |= preferences_state::changed;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_query::reset() {
|
||||||
|
cfg_query_new.reset();
|
||||||
|
|
||||||
|
updateDialog();
|
||||||
|
|
||||||
|
onChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_query::apply() {
|
||||||
|
cfg.query = cfg_query_new;
|
||||||
|
|
||||||
|
onChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void preferences_page_query::onChanged() {
|
||||||
|
m_callback->on_state_changed();
|
||||||
|
}
|
||||||
313
foo_httpcontrol/src/config.h
Executable file
@@ -0,0 +1,313 @@
|
|||||||
|
#ifndef __FOO_CONFIG_H__
|
||||||
|
#define __FOO_CONFIG_H__
|
||||||
|
|
||||||
|
#define foo_name "foo_httpcontrol"
|
||||||
|
#define forum "http://www.hydrogenaudio.org/forums/index.php?showtopic=62218"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
//externs
|
||||||
|
namespace httpc{
|
||||||
|
namespace control {
|
||||||
|
extern volatile bool listener_started;
|
||||||
|
extern volatile bool listener_error;
|
||||||
|
extern volatile bool listener_stop;
|
||||||
|
extern volatile int running_threads;
|
||||||
|
extern pfc::string8 listener_info;
|
||||||
|
extern void set_active(bool activate);
|
||||||
|
extern bool is_active();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// {E7E34E73-F17E-4c30-8FBE-435C649060C5}
|
||||||
|
static const GUID guid_preferences_page1 = { 0xe7e34e73, 0xf17e, 0x4c30, { 0x8f, 0xbe, 0x43, 0x5c, 0x64, 0x90, 0x60, 0xc5 } };
|
||||||
|
// {21CB8CF4-0332-4d57-9740-C8443E2B873B}
|
||||||
|
static const GUID guid_preferences_page2 = { 0x21cb8cf4, 0x332, 0x4d57, { 0x97, 0x40, 0xc8, 0x44, 0x3e, 0x2b, 0x87, 0x3b } };
|
||||||
|
|
||||||
|
class config_main {
|
||||||
|
public:
|
||||||
|
pfc::string8 ip;
|
||||||
|
t_size port;
|
||||||
|
bool startserver;
|
||||||
|
bool albumart_embedded_retrieve; /* dump completely in future */
|
||||||
|
bool retrieve_playlist; /* dump completely in future */
|
||||||
|
bool hide_nonplayables;
|
||||||
|
bool log_access;
|
||||||
|
pfc::string8 server_root;
|
||||||
|
pfc::string8 control_ip;
|
||||||
|
bool control_credentials;
|
||||||
|
pfc::string8 control_credentials_username;
|
||||||
|
pfc::string8 control_credentials_password;
|
||||||
|
pfc::string8 restrict_to_path;
|
||||||
|
bool allow_commandline; /* dump completely in future */
|
||||||
|
bool stop_after_queue_enable;
|
||||||
|
bool gzip_enable;
|
||||||
|
pfc::string8 extra_formats;
|
||||||
|
pfc::string8 ignored_formats;
|
||||||
|
|
||||||
|
config_main() { reset(); }
|
||||||
|
config_main(const config_main &cfg) { copy(cfg); }
|
||||||
|
void get_data_raw(stream_writer * p_stream,abort_callback & p_abort);
|
||||||
|
void set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort);
|
||||||
|
config_main &operator = (const config_main &cfg) { copy(cfg); return *this; }
|
||||||
|
bool operator == (const config_main &c);
|
||||||
|
void copy(const config_main &cfg);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class config_misc {
|
||||||
|
public:
|
||||||
|
pfc::string8 last_browse_dir;
|
||||||
|
pfc::string8 query_playlist_name;
|
||||||
|
bool stop_after_queue;
|
||||||
|
|
||||||
|
config_misc() { reset(); }
|
||||||
|
void get_data_raw(stream_writer * p_stream,abort_callback & p_abort);
|
||||||
|
void set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class config_query {
|
||||||
|
public:
|
||||||
|
pfc::string8 sortpattern;
|
||||||
|
pfc::string8 step1;
|
||||||
|
pfc::string8 step2;
|
||||||
|
pfc::string8 step3;
|
||||||
|
bool sendtodedicated;
|
||||||
|
|
||||||
|
config_query() { reset(); }
|
||||||
|
config_query(const config_query &cfg) { copy(cfg); }
|
||||||
|
void get_data_raw(stream_writer * p_stream,abort_callback & p_abort);
|
||||||
|
void set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort);
|
||||||
|
config_query &operator = (const config_query &cfg) { copy(cfg); return *this; }
|
||||||
|
bool operator == (const config_query &c);
|
||||||
|
void copy(const config_query &g_c);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class config: public cfg_var {
|
||||||
|
virtual void get_data_raw(stream_writer * p_stream,abort_callback & p_abort);
|
||||||
|
virtual void set_data_raw(stream_reader * p_stream,unsigned p_sizehint,abort_callback & p_abort);
|
||||||
|
|
||||||
|
public:
|
||||||
|
config_main main;
|
||||||
|
config_query query;
|
||||||
|
config_misc misc;
|
||||||
|
|
||||||
|
pfc::list_t<pfc::string8> restrict_to_path_list;
|
||||||
|
|
||||||
|
config(const GUID & p_guid) : cfg_var(p_guid) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
extern config cfg;
|
||||||
|
|
||||||
|
class preferences_page_main : public preferences_page_instance, public CDialogImpl<preferences_page_main>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
config_main cfg_main_new;
|
||||||
|
|
||||||
|
void update_credentials();
|
||||||
|
void update_server_status();
|
||||||
|
void updateDialog();
|
||||||
|
bool is_server_root_valid();
|
||||||
|
void set_server_root_btn_state(bool state);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { IDD = IDD_TAB1 };
|
||||||
|
|
||||||
|
preferences_page_main(preferences_page_callback::ptr callback) : m_callback(callback) { cfg_main_new = cfg.main; }
|
||||||
|
|
||||||
|
t_uint32 get_state();
|
||||||
|
void apply();
|
||||||
|
void reset();
|
||||||
|
HWND get_wnd() { return m_hWnd; }
|
||||||
|
|
||||||
|
BEGIN_MSG_MAP_EX(preferences_page_main)
|
||||||
|
MSG_WM_INITDIALOG(OnInitDialog)
|
||||||
|
MSG_WM_COMMAND(OnCommand)
|
||||||
|
END_MSG_MAP()
|
||||||
|
|
||||||
|
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
|
||||||
|
void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl);
|
||||||
|
|
||||||
|
void onChanged();
|
||||||
|
|
||||||
|
const preferences_page_callback::ptr m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class preferences_page_main_impl : public preferences_page_impl<preferences_page_main> {
|
||||||
|
public:
|
||||||
|
const char * get_name() { return "HTTP Control"; }
|
||||||
|
GUID get_guid() { return guid_preferences_page1; }
|
||||||
|
GUID get_parent_guid() { return preferences_page::guid_tools; }
|
||||||
|
bool get_help_url(pfc::string_base & p_out) { p_out = forum; return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static preferences_page_factory_t<preferences_page_main_impl> g_preferences_page1_impl_factory;
|
||||||
|
|
||||||
|
struct httpc_template {
|
||||||
|
pfc::string8 root;
|
||||||
|
pfc::string8 url;
|
||||||
|
pfc::string8 local_path;
|
||||||
|
pfc::string8 playlist_row;
|
||||||
|
pfc::string8 helper1;
|
||||||
|
pfc::string8 helper2;
|
||||||
|
pfc::string8 helper3;
|
||||||
|
pfc::string8 albumart;
|
||||||
|
pfc::string8 albumart_not_found;
|
||||||
|
pfc::string8 albumart_not_available;
|
||||||
|
t_size playlist_items_per_page;
|
||||||
|
t_size albumart_limit_size;
|
||||||
|
bool albumart_prefer_embedded;
|
||||||
|
|
||||||
|
foobar2000_io::t_filetimestamp timestamp;
|
||||||
|
httpc_template(): playlist_items_per_page(30) {} ;
|
||||||
|
};
|
||||||
|
|
||||||
|
class template_config{
|
||||||
|
pfc::list_t<httpc_template> cfg;
|
||||||
|
httpc_template cfg_empty;
|
||||||
|
t_size cfg_id;
|
||||||
|
bool changed;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template_config() { /* cfg_id = pfc::infinite_size;*/ cfg += cfg_empty; cfg_id = 0; }
|
||||||
|
|
||||||
|
bool checkrange(t_size c_id) { if (c_id != pfc::infinite_size && c_id < cfg.get_count()) return true; else return false; }
|
||||||
|
bool checkrange() { if (cfg_id != pfc::infinite_size && cfg_id < cfg.get_count()) return true; else return false; }
|
||||||
|
bool choose(t_size new_cfg_id) { if (checkrange(new_cfg_id)) { if (cfg_id != new_cfg_id) changed = true; cfg_id = new_cfg_id; return true; } else return false; }
|
||||||
|
t_size get_count() { return cfg.get_count(); }
|
||||||
|
const t_size get_id() { return cfg_id; }
|
||||||
|
void remove(t_size c_id) { if (checkrange(c_id)) { cfg.remove_by_idx(c_id); cfg_id = c_id == 0? c_id : c_id - 1; changed = true; } }
|
||||||
|
void set_size(t_size new_size) { cfg.set_size(new_size); changed = true; }
|
||||||
|
bool is_changed() { if (changed) { changed = false; return true; } else return false; }
|
||||||
|
t_size find(pfc::string8 &name);
|
||||||
|
bool loadtemplate(pfc::string_base &path, pfc::string8 &tpl_name);
|
||||||
|
httpc_template &get() {/* if (checkrange(cfg_id))*/ return cfg[cfg_id];/* else return cfg_empty;*/ }
|
||||||
|
httpc_template &get(t_size c_id) { /*if (checkrange(c_id)) */return cfg[c_id]; /*else return cfg_empty;*/ }
|
||||||
|
};
|
||||||
|
|
||||||
|
extern template_config tcfg;
|
||||||
|
|
||||||
|
class preferences_page_query : public preferences_page_instance, public CDialogImpl<preferences_page_query>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
config_query cfg_query_new;
|
||||||
|
|
||||||
|
void updateDialog();
|
||||||
|
public:
|
||||||
|
enum { IDD = IDD_TAB3 };
|
||||||
|
|
||||||
|
preferences_page_query(preferences_page_callback::ptr callback) : m_callback(callback) { cfg_query_new = cfg.query; }
|
||||||
|
|
||||||
|
t_uint32 get_state();
|
||||||
|
void apply();
|
||||||
|
void reset();
|
||||||
|
HWND get_wnd() { return m_hWnd; }
|
||||||
|
|
||||||
|
BEGIN_MSG_MAP_EX(preferences_page_query)
|
||||||
|
MSG_WM_INITDIALOG(OnInitDialog)
|
||||||
|
MSG_WM_COMMAND(OnCommand)
|
||||||
|
END_MSG_MAP()
|
||||||
|
|
||||||
|
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
|
||||||
|
void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl);
|
||||||
|
|
||||||
|
void onChanged();
|
||||||
|
|
||||||
|
const preferences_page_callback::ptr m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
class preferences_page_query_impl : public preferences_page_impl<preferences_page_query> {
|
||||||
|
public:
|
||||||
|
const char * get_name() { return "Media Library"; }
|
||||||
|
GUID get_guid() { return guid_preferences_page2; }
|
||||||
|
GUID get_parent_guid() { return guid_preferences_page1; }
|
||||||
|
bool get_help_url(pfc::string_base & p_out) { p_out = "http://www.hydrogenaudio.org/forums/index.php?showtopic=62218"; return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
static preferences_page_factory_t<preferences_page_query_impl> g_preferences_page1_query_factory;
|
||||||
|
|
||||||
|
class stop_after_qeueue_menu_command : public mainmenu_commands
|
||||||
|
{
|
||||||
|
// number of commands
|
||||||
|
virtual t_uint32 get_command_count()
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All commands are identified by a GUID.
|
||||||
|
virtual GUID get_command(t_uint32 p_index)
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable)
|
||||||
|
{
|
||||||
|
static const GUID g_guid_stop_after_queue = { 0xa643b240, 0x70be, 0x4eba, { 0x92, 0xfd, 0xc4, 0x8, 0x82, 0x7b, 0x28, 0xe3 } };
|
||||||
|
|
||||||
|
if (p_index == 0) return g_guid_stop_after_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfc::guid_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void get_name(t_uint32 p_index, pfc::string_base & p_out)
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable)
|
||||||
|
if (p_index == 0) p_out = "Stop after queue";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool get_description(t_uint32 p_index, pfc::string_base & p_out)
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable)
|
||||||
|
if (p_index == 0)
|
||||||
|
{
|
||||||
|
p_out = "Stops playback after completing playback queue.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual GUID get_parent() { return mainmenu_groups::playback_etc; }
|
||||||
|
|
||||||
|
// execute command
|
||||||
|
virtual void execute(t_uint32 p_index, service_ptr_t<service_base> p_callback)
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable && p_index == 0)
|
||||||
|
cfg.misc.stop_after_queue = cfg.misc.stop_after_queue ? false : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether the item should be checked
|
||||||
|
bool is_checked(t_uint32 p_index)
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable)
|
||||||
|
if (p_index == 0) return cfg.misc.stop_after_queue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The standard version of this command does not support checked or disabled
|
||||||
|
// commands, so we use our own version.
|
||||||
|
virtual bool get_display(t_uint32 p_index, pfc::string_base & p_text, t_uint32 & p_flags)
|
||||||
|
{
|
||||||
|
if (cfg.main.stop_after_queue_enable)
|
||||||
|
{
|
||||||
|
p_flags = 0;
|
||||||
|
if (is_checked(p_index))
|
||||||
|
{
|
||||||
|
p_flags |= flag_checked;
|
||||||
|
}
|
||||||
|
get_name(p_index,p_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static mainmenu_commands_factory_t< stop_after_qeueue_menu_command > saq_menu_command;
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*__FOO_CONFIG_*/
|
||||||
227
foo_httpcontrol/src/facets.cpp
Executable file
@@ -0,0 +1,227 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "facets.h"
|
||||||
|
|
||||||
|
namespace httpc
|
||||||
|
{
|
||||||
|
namespace facets
|
||||||
|
{
|
||||||
|
string8 query[facets_total];
|
||||||
|
t_size facet_current;
|
||||||
|
pfc::list_t<string8> filtered;
|
||||||
|
string8 selected[facets_total];
|
||||||
|
|
||||||
|
void fill_playlist()
|
||||||
|
{
|
||||||
|
if (!static_api_ptr_t<library_manager>()->is_library_enabled()
|
||||||
|
|| facet_current == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static_api_ptr_t<autoplaylist_manager> apm;
|
||||||
|
static_api_ptr_t<playlist_manager> pm;
|
||||||
|
t_size playlist;
|
||||||
|
|
||||||
|
if (cfg.query.sendtodedicated)
|
||||||
|
playlist = pm->find_or_create_playlist(cfg.misc.query_playlist_name, pfc::infinite_size);
|
||||||
|
else
|
||||||
|
playlist = pm->get_active_playlist();
|
||||||
|
|
||||||
|
if (playlist != pfc::infinite_size)
|
||||||
|
{
|
||||||
|
pm->playlist_undo_backup(playlist);
|
||||||
|
|
||||||
|
if (apm->is_client_present(playlist))
|
||||||
|
apm->remove_client(playlist);
|
||||||
|
|
||||||
|
autoplaylist_client::ptr foo_apl_client_ptr = new service_impl_t<foo_autoplaylist_client>;
|
||||||
|
|
||||||
|
apm->add_client(foo_apl_client_ptr, playlist, autoplaylist_flag_sort);
|
||||||
|
|
||||||
|
if (apm->is_client_present(playlist))
|
||||||
|
apm->remove_client(playlist);
|
||||||
|
|
||||||
|
pm->set_active_playlist(playlist);
|
||||||
|
|
||||||
|
httpc::should_update_playlist = true;
|
||||||
|
|
||||||
|
httpc::query_playlist = playlist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter(t_size which_facet)
|
||||||
|
{
|
||||||
|
query[0] = cfg.query.step1;
|
||||||
|
query[1] = cfg.query.step2;
|
||||||
|
query[2] = cfg.query.step3;
|
||||||
|
|
||||||
|
if (!static_api_ptr_t<library_manager>()->is_library_enabled()
|
||||||
|
|| which_facet >= facets_total
|
||||||
|
|| strlen(query[which_facet]) == 0)
|
||||||
|
{
|
||||||
|
filtered.remove_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pfc::hires_timer timer;
|
||||||
|
timer.start();
|
||||||
|
*/
|
||||||
|
list_t<metadb_handle_ptr> library;
|
||||||
|
string8_fast_aggressive facet;
|
||||||
|
|
||||||
|
service_ptr_t<titleformat_object> script_query;
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(script_query,query[which_facet]);
|
||||||
|
|
||||||
|
static_api_ptr_t<metadb>()->database_lock();
|
||||||
|
|
||||||
|
static_api_ptr_t<library_manager>()->get_all_items(library);
|
||||||
|
|
||||||
|
pfc::map_t<pfc::string8, boolean> items;
|
||||||
|
pfc::string8_fast_aggressive var_name;
|
||||||
|
|
||||||
|
t_size lc = library.get_count();
|
||||||
|
pfc::chain_list_v2_t<pfc::string8> field_values;
|
||||||
|
if (which_facet == 0) // don't have to do extra search
|
||||||
|
for (size_t i = 0; i < lc; ++i)
|
||||||
|
{
|
||||||
|
if (library.get_item(i)->format_title(NULL, facet, script_query, NULL))
|
||||||
|
{
|
||||||
|
if (facet.find_first(';') == pfc::infinite_size)
|
||||||
|
items[facet] = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_values.remove_all();
|
||||||
|
pfc::splitStringSimple_toList(field_values, ";", facet);
|
||||||
|
|
||||||
|
for (pfc::iterator<pfc::string8> walk = field_values.first(); walk.is_valid(); ++walk)
|
||||||
|
{
|
||||||
|
walk->skip_trailing_char();
|
||||||
|
items[*walk] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t_size j;
|
||||||
|
bool acceptable;
|
||||||
|
|
||||||
|
list_t<service_ptr_t<titleformat_object>> scripts;
|
||||||
|
scripts.set_count(which_facet+1);
|
||||||
|
for (j = 0; j <= which_facet; ++j)
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(scripts[j],query[j]);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lc; ++i)
|
||||||
|
{
|
||||||
|
acceptable = true;
|
||||||
|
for (j = 0; j < which_facet && acceptable; ++j)
|
||||||
|
if (library.get_item(i)->format_title(NULL, facet, scripts[j], NULL))
|
||||||
|
{
|
||||||
|
if ((facet.find_first(';') == pfc::infinite_size) && (facet != selected[j]))
|
||||||
|
acceptable = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_values.remove_all();
|
||||||
|
pfc::splitStringSimple_toList(field_values, ";", facet);
|
||||||
|
acceptable = list_find(field_values, selected[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
acceptable = false;
|
||||||
|
|
||||||
|
if (acceptable && library.get_item(i)->format_title(NULL, facet, script_query, NULL))
|
||||||
|
if (facet.get_length() > 0)
|
||||||
|
{
|
||||||
|
if (facet.find_first(';') == pfc::infinite_size)
|
||||||
|
items[facet] = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_values.remove_all();
|
||||||
|
pfc::splitStringSimple_toList(field_values, ";", facet);
|
||||||
|
|
||||||
|
for (pfc::iterator<pfc::string8> walk = field_values.first(); walk.is_valid(); ++walk)
|
||||||
|
{
|
||||||
|
walk->skip_trailing_char();
|
||||||
|
items[*walk] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j <= which_facet; ++j)
|
||||||
|
scripts[j].release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static_api_ptr_t<metadb>()->database_unlock();
|
||||||
|
|
||||||
|
filtered.remove_all();
|
||||||
|
pfc::map_t<string8, boolean>::const_iterator iter;
|
||||||
|
for (iter = items.first(); iter.is_valid(); ++iter)
|
||||||
|
filtered.add_item(xml_friendly_string(pfc::string8(iter->m_key)));
|
||||||
|
|
||||||
|
filtered.sort_t(sortfunc_natural);
|
||||||
|
|
||||||
|
script_query.release();
|
||||||
|
|
||||||
|
/*
|
||||||
|
console::formatter() << "facet " << which_facet;
|
||||||
|
console::formatter() << "library items " << library.get_count();
|
||||||
|
console::formatter() << "filtered items " << filtered.get_count();
|
||||||
|
console::formatter() << "filtered list in " << pfc::format_time_ex(timer.query(),6);
|
||||||
|
timer.start();
|
||||||
|
console::formatter() << "filtered list sorted in " << pfc::format_time_ex(timer.query(),6);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < filtered.get_count(); ++i)
|
||||||
|
console::info(filtered.get_item(i));
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void prev_facet()
|
||||||
|
{
|
||||||
|
if (facet_current < facets_total)
|
||||||
|
selected[facet_current].reset();
|
||||||
|
|
||||||
|
if (facet_current > 0)
|
||||||
|
{
|
||||||
|
--facet_current;
|
||||||
|
selected[facet_current].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(facet_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_facet(string8 &request)
|
||||||
|
{
|
||||||
|
if (facet_current > facets_total - 1)
|
||||||
|
facet_current = facets_total - 1;
|
||||||
|
|
||||||
|
selected[facet_current] = request;
|
||||||
|
|
||||||
|
++facet_current;
|
||||||
|
|
||||||
|
filter(facet_current);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool list_find(pfc::chain_list_v2_t<pfc::string8> &list, pfc::string_base &str)
|
||||||
|
{
|
||||||
|
bool acceptable = false;
|
||||||
|
|
||||||
|
for (pfc::iterator<pfc::string8> walk = list.first(); walk.is_valid(); ++walk)
|
||||||
|
{
|
||||||
|
walk->skip_trailing_char();
|
||||||
|
|
||||||
|
if (*walk == str)
|
||||||
|
{
|
||||||
|
acceptable = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acceptable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
101
foo_httpcontrol/src/facets.h
Executable file
@@ -0,0 +1,101 @@
|
|||||||
|
#ifndef ___FACETS_H___
|
||||||
|
#define ___FACETS_H___
|
||||||
|
|
||||||
|
using namespace pfc;
|
||||||
|
|
||||||
|
namespace httpc
|
||||||
|
{
|
||||||
|
namespace facets
|
||||||
|
{
|
||||||
|
static const t_size facets_total = 3;
|
||||||
|
|
||||||
|
extern string8 query[facets_total];
|
||||||
|
extern t_size facet_current;
|
||||||
|
extern pfc::list_t<string8> filtered;
|
||||||
|
extern string8 selected[facets_total];
|
||||||
|
|
||||||
|
/* static int sortfunc_basic(string8 &p1, string8 &p2) {
|
||||||
|
return stricmp_utf8(p1.operator const char *(),p2.operator const char *());
|
||||||
|
}*/
|
||||||
|
|
||||||
|
static int sortfunc_natural(string8 &p1, string8 &p2) { return compare_natural_utf8(p1, p2); }
|
||||||
|
|
||||||
|
extern void filter(t_size which_facet);
|
||||||
|
extern void fill_playlist();
|
||||||
|
extern void prev_facet();
|
||||||
|
extern void next_facet(string8 &request);
|
||||||
|
|
||||||
|
extern bool list_find(pfc::chain_list_v2_t<pfc::string8> &list, pfc::string_base &str);
|
||||||
|
|
||||||
|
class foo_autoplaylist_client : public autoplaylist_client {
|
||||||
|
public:
|
||||||
|
foo_autoplaylist_client() {}
|
||||||
|
GUID get_guid() {
|
||||||
|
static const GUID apl = { 0x97e0fef2, 0x7c8b, 0x4d7e, { 0xa0, 0x72, 0x5b, 0x25, 0x47, 0xe9, 0x9e, 0xa1 } };
|
||||||
|
return apl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filter(metadb_handle_list_cref data, bool * out){
|
||||||
|
t_size i, j, l;
|
||||||
|
bool acceptable;
|
||||||
|
pfc::string8 facet;
|
||||||
|
|
||||||
|
list_t<service_ptr_t<titleformat_object>> scripts;
|
||||||
|
scripts.set_count(facet_current+1);
|
||||||
|
for (j = 0; j <= facet_current; ++j)
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(scripts[j],query[j]);
|
||||||
|
|
||||||
|
pfc::chain_list_v2_t<pfc::string8> field_values;
|
||||||
|
|
||||||
|
l = data.get_count();
|
||||||
|
for (i = 0; i < l; ++i)
|
||||||
|
{
|
||||||
|
acceptable = true;
|
||||||
|
|
||||||
|
for (t_size j = 0; j < facet_current && selected[j].get_length(); ++j)
|
||||||
|
if (data.get_item(i)->format_title(NULL, facet, scripts[j], NULL))
|
||||||
|
{
|
||||||
|
if (facet.find_first(';') == pfc::infinite_size && facet != selected[j])
|
||||||
|
{
|
||||||
|
acceptable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
field_values.remove_all();
|
||||||
|
pfc::splitStringSimple_toList(field_values, ';', facet);
|
||||||
|
|
||||||
|
if (!list_find(field_values, selected[j]))
|
||||||
|
{
|
||||||
|
acceptable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
acceptable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out[i] = acceptable;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j <= facet_current; ++j)
|
||||||
|
scripts[j].release();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool sort(metadb_handle_list_cref p_items,t_size * p_orderbuffer)
|
||||||
|
{
|
||||||
|
metadb_handle_list_helper::sort_by_format_get_order(p_items, p_orderbuffer, cfg.query.sortpattern, NULL);
|
||||||
|
// todo! hack, I suppose
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
//! Retrieves your configuration data to be used later when re-instantiating your autoplaylist_client after a restart.
|
||||||
|
void get_configuration(stream_writer * p_stream,abort_callback & p_abort) { }
|
||||||
|
|
||||||
|
void show_ui(t_size p_source_playlist) { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //___FACETS_H___
|
||||||
72
foo_httpcontrol/src/foo_httpcontrol_preferences.rc
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
// Generated by ResEdit 1.5.4
|
||||||
|
// Copyright (C) 2006-2010
|
||||||
|
// http://www.resedit.net
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <commctrl.h>
|
||||||
|
#include <richedit.h>
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Dialog resources
|
||||||
|
//
|
||||||
|
LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA
|
||||||
|
IDD_TAB1 DIALOGEX 0, 0, 318, 294
|
||||||
|
STYLE DS_SHELLFONT | WS_CHILDWINDOW
|
||||||
|
EXSTYLE WS_EX_TRANSPARENT
|
||||||
|
FONT 8, "MS Shell Dlg", 400, 0, 1
|
||||||
|
{
|
||||||
|
CONTROL "", IDC_INTERFACE, WC_IPADDRESS, WS_TABSTOP, 81, 9, 100, 14
|
||||||
|
EDITTEXT IDC_PORT, 189, 9, 36, 14, ES_AUTOHSCROLL | ES_NUMBER
|
||||||
|
AUTOCHECKBOX "Start server", IDC_SERVERSTARTED, 26, 32, 63, 10, BS_LEFTTEXT, WS_EX_RIGHT
|
||||||
|
PUSHBUTTON "Button1", IDC_LAUNCH_BROWSER, 92, 30, 133, 12
|
||||||
|
CONTROL "", IDC_CONTROL_IP, WC_IPADDRESS, WS_TABSTOP, 81, 63, 99, 15
|
||||||
|
AUTOCHECKBOX "Credentials", IDC_CONTROL_CREDENTIALS, 37, 84, 51, 8, BS_LEFTTEXT | BS_NOTIFY, WS_EX_RIGHT
|
||||||
|
EDITTEXT IDC_CONTROL_USERNAME, 81, 99, 74, 13, WS_DISABLED | ES_AUTOHSCROLL
|
||||||
|
EDITTEXT IDC_CONTROL_PASSWORD, 220, 99, 73, 13, WS_DISABLED | ES_AUTOHSCROLL | ES_PASSWORD
|
||||||
|
EDITTEXT IDC_CONTROL_PATH, 81, 138, 212, 13, ES_AUTOHSCROLL
|
||||||
|
EDITTEXT IDC_EXTRA_FORMATS, 81, 158, 70, 13, ES_AUTOHSCROLL
|
||||||
|
AUTOCHECKBOX "Hide non-playable files", IDC_HIDE_NONPLAYABLES, 160, 179, 133, 15, BS_LEFTTEXT | BS_NOTIFY, WS_EX_RIGHT
|
||||||
|
EDITTEXT IDC_SERVER_ROOT, 81, 203, 183, 13, ES_AUTOHSCROLL
|
||||||
|
PUSHBUTTON "Open", IDC_SERVER_ROOT_BTN, 267, 203, 34, 12
|
||||||
|
AUTOCHECKBOX "HTTP compression (gzip)", IDC_GZIP_ENABLE, 37, 226, 116, 10, BS_LEFTTEXT, WS_EX_RIGHT
|
||||||
|
AUTOCHECKBOX "Log access to console", IDC_LOG_ACCESS, 45, 242, 108, 10, BS_LEFTTEXT | BS_NOTIFY, WS_EX_RIGHT
|
||||||
|
AUTOCHECKBOX "Stop after queue feature", IDC_STOP_AFTER_QUEUE_ENABLE, 160, 226, 121, 10, BS_LEFTTEXT, WS_EX_RIGHT
|
||||||
|
RTEXT "Listen on", IDC_STATIC, 10, 13, 67, 12, SS_RIGHT
|
||||||
|
GROUPBOX "Restrict access by", IDC_STATIC, 15, 49, 286, 70
|
||||||
|
RTEXT "Remote IP", IDC_STATIC, 26, 67, 51, 11, SS_RIGHT
|
||||||
|
RTEXT "Username", IDC_STATIC_USERNAME, 26, 102, 51, 13, WS_DISABLED | SS_RIGHT
|
||||||
|
RTEXT "Password", IDC_STATIC_PASSWORD, 164, 102, 52, 13, WS_DISABLED | SS_RIGHT
|
||||||
|
RTEXT "Allowed paths", IDC_STATIC, 15, 141, 62, 15, SS_RIGHT
|
||||||
|
RTEXT "Home directory", IDC_STATIC, 15, 205, 62, 12, SS_RIGHT
|
||||||
|
CTEXT ":", IDC_STATIC, 181, 11, 8, 12, SS_CENTER
|
||||||
|
GROUPBOX "File browser", IDC_STATIC, 15, 126, 286, 70
|
||||||
|
RTEXT "Extra formats", IDC_STATIC, 20, 160, 57, 15, SS_RIGHT
|
||||||
|
LTEXT """Allowed paths"", ""Extra formats"" and ""Hide formats"" fields accept several values separated by |.", IDC_STATIC, 30, 264, 260, 23, SS_LEFT
|
||||||
|
EDITTEXT IDC_IGNORED_FORMATS, 223, 159, 70, 13, ES_AUTOHSCROLL
|
||||||
|
RTEXT "Ignored formats", IDC_STATIC, 157, 161, 62, 15, SS_RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA
|
||||||
|
IDD_TAB3 DIALOGEX 0, 0, 316, 269
|
||||||
|
STYLE DS_SHELLFONT | WS_CHILDWINDOW | WS_SYSMENU
|
||||||
|
FONT 8, "MS Shell Dlg", 400, 0, 1
|
||||||
|
{
|
||||||
|
EDITTEXT IDC_AUTOPLAYLIST_SORT_PATTERN, 89, 99, 198, 13, ES_AUTOHSCROLL
|
||||||
|
RTEXT "Results sort pattern", IDC_STATIC, 7, 101, 73, 13, SS_RIGHT
|
||||||
|
AUTOCHECKBOX "Send results to separate playlist", IDC_AUTOPLAYLIST_SENDTODEDICATED, 8, 126, 118, 12, BS_LEFTTEXT | BS_CENTER | BS_NOTIFY, WS_EX_RIGHT
|
||||||
|
EDITTEXT IDC_AUTOPLAYLIST_QUERY_STEP1, 89, 28, 198, 13, ES_AUTOHSCROLL
|
||||||
|
RTEXT "Step 1", IDC_STATIC, 31, 30, 49, 13, SS_RIGHT
|
||||||
|
EDITTEXT IDC_AUTOPLAYLIST_QUERY_STEP2, 89, 47, 198, 13, ES_AUTOHSCROLL
|
||||||
|
RTEXT "Step 2", IDC_STATIC, 32, 49, 48, 13, SS_RIGHT
|
||||||
|
EDITTEXT IDC_AUTOPLAYLIST_QUERY_STEP3, 89, 66, 198, 13, ES_AUTOHSCROLL
|
||||||
|
RTEXT "Step 3", IDC_STATIC, 31, 68, 49, 13, SS_RIGHT
|
||||||
|
GROUPBOX "Query steps", IDC_STATIC, 16, 14, 285, 75
|
||||||
|
LTEXT "You have to fill at least first query step to get query filter working.", IDC_STATIC, 17, 205, 270, 19, SS_LEFT
|
||||||
|
LTEXT "$meta_sep(genre,';')-like syntax of query step is required to support multiple metadata field values. Only one field per step can be properly expanded.", IDC_STATIC, 17, 224, 270, 19, SS_LEFT
|
||||||
|
}
|
||||||
297
foo_httpcontrol/src/httpcontrol.cpp
Executable file
@@ -0,0 +1,297 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "httpcontrol.h"
|
||||||
|
|
||||||
|
DECLARE_COMPONENT_VERSION(
|
||||||
|
"HTTP Control",
|
||||||
|
"0.97.15",
|
||||||
|
"control foobar2000 via http "__DATE__)
|
||||||
|
|
||||||
|
VALIDATE_COMPONENT_FILENAME("foo_httpcontrol.dll");
|
||||||
|
|
||||||
|
namespace httpc
|
||||||
|
{
|
||||||
|
namespace control
|
||||||
|
{
|
||||||
|
ATOM g_class_atom;
|
||||||
|
pfc::string8 class_name;
|
||||||
|
pfc::stringcvt::string_os_from_utf8 os_class_name;
|
||||||
|
HANDLE m_io_thread;
|
||||||
|
HWND m_hwnd;
|
||||||
|
HANDLE listener_stop_event;
|
||||||
|
HANDLE listener_init_event;
|
||||||
|
HANDLE process_command_event;
|
||||||
|
volatile bool listener_started;
|
||||||
|
volatile bool listener_error;
|
||||||
|
volatile bool listener_stop;
|
||||||
|
volatile int running_threads;
|
||||||
|
pfc::string8 listener_info;
|
||||||
|
|
||||||
|
void process_command(pfc::string_base &cmd, pfc::string_base ¶m1, pfc::string_base ¶m2, pfc::string_base ¶m3)
|
||||||
|
{
|
||||||
|
if (httpc::control::is_active())
|
||||||
|
uSendMessage(httpc::control::m_hwnd, WM_HTTPSERVER_CMD, 0, (LPARAM) (new foo_httpserver_command(cmd, param1, param2, param3)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long WINAPI foo_process_request_thread(LPVOID param)
|
||||||
|
{
|
||||||
|
++running_threads;
|
||||||
|
foo_httpserv *httpserv = reinterpret_cast<foo_httpserv *>(param);
|
||||||
|
httpserv->process_request();
|
||||||
|
--running_threads;
|
||||||
|
delete httpserv;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_active(bool activate)
|
||||||
|
{
|
||||||
|
listener_info.reset();
|
||||||
|
|
||||||
|
if(activate) // start listener
|
||||||
|
{
|
||||||
|
WNDCLASS wc;
|
||||||
|
memset(&wc,0,sizeof(wc));
|
||||||
|
wc.style = 0;
|
||||||
|
wc.lpfnWndProc = wndproc;
|
||||||
|
wc.hInstance = core_api::get_my_instance();
|
||||||
|
class_name = pfc::string8(foo_name) << pfc::string8("_class_") << pfc::format_hex((t_uint64)GetTickCount());
|
||||||
|
os_class_name = pfc::stringcvt::string_os_from_utf8(class_name);
|
||||||
|
wc.lpszClassName = os_class_name;
|
||||||
|
g_class_atom = RegisterClass(&wc);
|
||||||
|
|
||||||
|
m_hwnd = uCreateWindowEx(0,
|
||||||
|
class_name,
|
||||||
|
foo_name,
|
||||||
|
0,
|
||||||
|
CW_USEDEFAULT,
|
||||||
|
CW_USEDEFAULT,
|
||||||
|
0,0,
|
||||||
|
core_api::get_main_window(),
|
||||||
|
0,
|
||||||
|
core_api::get_my_instance(),
|
||||||
|
0);
|
||||||
|
if(!m_hwnd)
|
||||||
|
foo_error("couldn't create helper window");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
listener_stop = false;
|
||||||
|
listener_init_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
m_io_thread = CreateThread(NULL,0,http_listener,NULL,0,NULL);
|
||||||
|
|
||||||
|
WaitForSingleObject(listener_init_event,5000);
|
||||||
|
|
||||||
|
CloseHandle(listener_init_event);
|
||||||
|
|
||||||
|
if(m_io_thread == NULL || ! listener_started || listener_error)
|
||||||
|
foo_error("couldn't create helper thread");
|
||||||
|
}
|
||||||
|
} else // stop listener
|
||||||
|
{
|
||||||
|
if(m_io_thread != NULL)
|
||||||
|
{
|
||||||
|
listener_stop = true;
|
||||||
|
SetEvent(listener_stop_event);
|
||||||
|
CloseHandle(m_io_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_hwnd != NULL)
|
||||||
|
{
|
||||||
|
uDestroyWindow(m_hwnd);
|
||||||
|
m_hwnd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_class_atom)
|
||||||
|
UnregisterClassW(os_class_name, core_api::get_my_instance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_active()
|
||||||
|
{
|
||||||
|
return listener_started;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long WINAPI http_listener(LPVOID param)
|
||||||
|
{
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
JNL::open_socketlib();
|
||||||
|
JNL_Listen l((short)cfg.main.port, cfg.main.ip != ""? inet_addr(cfg.main.ip) : 0);
|
||||||
|
|
||||||
|
listener_error = true;
|
||||||
|
listener_started = false;
|
||||||
|
|
||||||
|
if (l.is_error())
|
||||||
|
foo_error("bind failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
listener_stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
|
HANDLE handles[2];
|
||||||
|
handles[0] = listener_stop_event; // stop listening
|
||||||
|
handles[1] = WSACreateEvent(); // network activity
|
||||||
|
|
||||||
|
if (handles[1] == WSA_INVALID_EVENT)
|
||||||
|
foo_error("WSACreateEvent failed.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (WSAEventSelect(l.m_socket, handles[1], FD_ACCEPT/* | FD_CONNECT | FD_READ | FD_CLOSE*/) != 0)
|
||||||
|
foo_error("WSAEventSelect failed. Make sure IP address specified in \"Listen on\" component preferences field is valid and Port:IP combination is not used by another process.");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
listener_started = true;
|
||||||
|
listener_error = false;
|
||||||
|
|
||||||
|
if (strcmp(cfg.main.ip, "0.0.0.0") == 0)
|
||||||
|
listener_info = pfc::string_formatter() << "http://127.0.0.1:" << cfg.main.port;
|
||||||
|
else
|
||||||
|
listener_info = pfc::string_formatter() << "http://" << cfg.main.ip << ":" << cfg.main.port;
|
||||||
|
|
||||||
|
SetEvent(listener_init_event);
|
||||||
|
|
||||||
|
while (!l.is_error())
|
||||||
|
{
|
||||||
|
ret = WSAWaitForMultipleEvents(2, handles, FALSE, pfc::infinite_size, TRUE);
|
||||||
|
|
||||||
|
WSAResetEvent(handles[1]); // assuming network activity event occured
|
||||||
|
|
||||||
|
if(listener_stop || ret == WSA_INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
if (ret == WSA_INVALID_HANDLE)
|
||||||
|
foo_error("WSAWaitForMultipleEvents got invalid handle, stopping listener thread.");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != WSA_WAIT_TIMEOUT && ret != WSA_WAIT_IO_COMPLETION)
|
||||||
|
{
|
||||||
|
JNL_Connection *con;
|
||||||
|
|
||||||
|
while (!listener_stop && running_threads >= MAX_THREADS)
|
||||||
|
Sleep(1);
|
||||||
|
|
||||||
|
while ((con = l.get_connect(SEND_BUFFER, RECIEVE_BUFFER)) && !listener_stop)
|
||||||
|
if (con)
|
||||||
|
{
|
||||||
|
foo_httpserv *httpserv = new foo_httpserv(con);
|
||||||
|
|
||||||
|
HANDLE m_worker_thread =
|
||||||
|
CreateThread(NULL,0,foo_process_request_thread,reinterpret_cast<void *>(httpserv),0,NULL);
|
||||||
|
|
||||||
|
if (m_worker_thread == NULL)
|
||||||
|
{
|
||||||
|
delete httpserv;
|
||||||
|
foo_error("cannot spawn request processing thread");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CloseHandle(m_worker_thread);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(listener_stop_event);
|
||||||
|
WSACloseEvent(handles[1]);
|
||||||
|
|
||||||
|
listener_started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetEvent(listener_init_event);
|
||||||
|
|
||||||
|
JNL::close_socketlib();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute_command (commands_map::iterator &cmd_it, foo_httpserver_command *cmd)
|
||||||
|
{
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
return (* cmd_it->m_value)(cmd);
|
||||||
|
}
|
||||||
|
__except_instacrash {}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch(msg)
|
||||||
|
{
|
||||||
|
case WM_HTTPSERVER_CMD:
|
||||||
|
{
|
||||||
|
bool config_changed = tcfg.is_changed();
|
||||||
|
|
||||||
|
if (config_changed)
|
||||||
|
httpc::playlist_page = pfc::infinite_size;
|
||||||
|
|
||||||
|
foo_httpserver_command *cmd = (foo_httpserver_command*)lParam;
|
||||||
|
|
||||||
|
if (cmd)
|
||||||
|
{
|
||||||
|
pfc::string8 &command = cmd->get_command();
|
||||||
|
|
||||||
|
httpc::last_action = httpc::FLC_START;
|
||||||
|
httpc::sac = static_api_ptr_t<playback_control>()->get_stop_after_current();
|
||||||
|
httpc::refresh_volume(1);
|
||||||
|
|
||||||
|
commands_map::iterator cmd_it = commands.find(command);
|
||||||
|
|
||||||
|
if (cmd_it != NULL)
|
||||||
|
{
|
||||||
|
bool result = execute_command(cmd_it, cmd);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
foo_error(string_formatter() << "command " << command << " failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (command.get_length())
|
||||||
|
foo_error(string_formatter() << "unknown command: " << command);
|
||||||
|
|
||||||
|
delete cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_changed)
|
||||||
|
{
|
||||||
|
httpc::titleformat_compile();
|
||||||
|
|
||||||
|
if (httpc::playlist_page == pfc::infinite_size)
|
||||||
|
httpc::should_focus_on_playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_update_playlist
|
||||||
|
|| config_changed
|
||||||
|
|| httpc::pb_item == pfc::infinite_size
|
||||||
|
|| (httpc::active_playlist == httpc::pb_playlist && httpc::playlist_page_switched))
|
||||||
|
{
|
||||||
|
httpc::refresh_playing_info();
|
||||||
|
httpc::refresh_playlist_view();
|
||||||
|
httpc::refresh_playback_queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_update_playlist_total_time
|
||||||
|
|| config_changed)
|
||||||
|
httpc::refresh_playlist_total_time();
|
||||||
|
|
||||||
|
if (httpc::should_update_queue)
|
||||||
|
httpc::refresh_playback_queue();
|
||||||
|
|
||||||
|
if (httpc::should_update_playlists_list)
|
||||||
|
httpc::refresh_playlist_list();
|
||||||
|
|
||||||
|
if (httpc::control::process_command_event)
|
||||||
|
SetEvent(httpc::control::process_command_event);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uDefWindowProc(hwnd,msg,wParam,lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
29
foo_httpcontrol/src/httpcontrol.h
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __FOO_HTTPCONTROL_H__
|
||||||
|
#define __FOO_HTTPCONTROL_H__
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
|
|
||||||
|
#include "ui.h"
|
||||||
|
#include "httpserver.h"
|
||||||
|
|
||||||
|
#define WM_HTTPSERVER_CMD 0x8899
|
||||||
|
#define MAX_THREADS 8
|
||||||
|
|
||||||
|
namespace httpc
|
||||||
|
{
|
||||||
|
namespace control
|
||||||
|
{
|
||||||
|
extern commands_map commands;
|
||||||
|
|
||||||
|
extern void gen_cmd_table();
|
||||||
|
|
||||||
|
extern void set_active(bool activate);
|
||||||
|
extern bool is_active();
|
||||||
|
|
||||||
|
static unsigned long WINAPI read_command_thread(LPVOID param);
|
||||||
|
static unsigned long WINAPI http_listener(LPVOID param);
|
||||||
|
static LRESULT CALLBACK wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*__FOO_HTTPCONTROL_H__*/
|
||||||
645
foo_httpcontrol/src/httpserver.cpp
Executable file
@@ -0,0 +1,645 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "browsefiles.h"
|
||||||
|
#include "httpserver.h"
|
||||||
|
|
||||||
|
char *access_denied_body = "<h1>403 Forbidden</h1><p>You don't have permission to access this document on this server.</p>";
|
||||||
|
char *content_type_str = "Connection: close\r\nContent-Type: text/html; Charset=UTF-8;";
|
||||||
|
char *content_no_refresh = "Cache-Control: no-cache\r\nPragma: no-cache\r\nExpires: Mon, 02 Jun 1980 01:02:03 GMT";
|
||||||
|
|
||||||
|
mimetypes mime;
|
||||||
|
|
||||||
|
namespace httpc {
|
||||||
|
namespace control {
|
||||||
|
pfc::string8 command_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo_httpserv::log(pfc::string_base &cmd, pfc::string_base ¶m1, pfc::string_base ¶m2, pfc::string_base ¶m3, char *remotehost, pfc::string_base &request_url)
|
||||||
|
{
|
||||||
|
pfc::string8 bufs;
|
||||||
|
|
||||||
|
char buf[32] = { };
|
||||||
|
GetDateFormatA(NULL, 0, NULL, "[ dd.MM ", buf,31);
|
||||||
|
bufs << buf;
|
||||||
|
GetTimeFormatA(NULL, 0, NULL, "HH:mm:ss ] ", buf,31);
|
||||||
|
bufs << buf << remotehost << " \t" << request_url;
|
||||||
|
|
||||||
|
if (cmd.get_length()) bufs << "?cmd=" << cmd;
|
||||||
|
if (param1.get_length()) bufs << "¶m1=" << param1;
|
||||||
|
if (param2.get_length()) bufs << "¶m2=" << param2;
|
||||||
|
if (param3.get_length()) bufs << "¶m3=" << param3;
|
||||||
|
|
||||||
|
char *ua = getheader("User-Agent");
|
||||||
|
if (ua)
|
||||||
|
{
|
||||||
|
bufs << " \t" << ua;
|
||||||
|
free(ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
foo_info(bufs);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t foo_httpserv::send_data(char *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
size_t result_len = buf_len;
|
||||||
|
char *result_ptr = buf;
|
||||||
|
|
||||||
|
timeval SendTimeout;
|
||||||
|
SendTimeout.tv_sec = 0;
|
||||||
|
SendTimeout.tv_usec = 250000; // 250 ms
|
||||||
|
fd_set fds;
|
||||||
|
|
||||||
|
size_t run_result = 1;
|
||||||
|
size_t cansend;
|
||||||
|
size_t select_res = 0;
|
||||||
|
|
||||||
|
while (((result_len > 0 || bytes_inqueue())
|
||||||
|
&& run_result > 0 && run_result != 4) && !httpc::control::listener_stop && select_res != SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
cansend = bytes_cansend();
|
||||||
|
|
||||||
|
if (cansend > result_len)
|
||||||
|
cansend = result_len;
|
||||||
|
|
||||||
|
if (cansend > 0)
|
||||||
|
{
|
||||||
|
write_bytes(result_ptr,cansend);
|
||||||
|
result_ptr += cansend;
|
||||||
|
result_len -= cansend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Sleep(1);
|
||||||
|
|
||||||
|
run_result = run();
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(get_con()->m_socket, &fds);
|
||||||
|
select_res = select(0, NULL, &fds, NULL, &SendTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select_res == SOCKET_ERROR)
|
||||||
|
return SEND_SOCKET_ERROR;
|
||||||
|
else
|
||||||
|
if (result_len > 0)
|
||||||
|
return SEND_INCOMPLETE;
|
||||||
|
else
|
||||||
|
return SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t foo_httpserv::send_data_zlib(char *buf, size_t length)
|
||||||
|
{
|
||||||
|
z_stream strm;
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
|
||||||
|
t_size ret, flush, result_len;
|
||||||
|
|
||||||
|
ret = deflateInit2(&strm, Z_CLEVEL, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY);
|
||||||
|
if (ret != Z_OK)
|
||||||
|
return SEND_ZLIB_ERROR;
|
||||||
|
|
||||||
|
size_t buf_len = length;
|
||||||
|
char *buf_ptr = buf;
|
||||||
|
|
||||||
|
size_t send_result;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
strm.avail_in = Z_CHUNK > buf_len ? buf_len : Z_CHUNK;
|
||||||
|
strm.next_in = (unsigned char *) buf_ptr;
|
||||||
|
|
||||||
|
buf_ptr += strm.avail_in;
|
||||||
|
buf_len -= strm.avail_in;
|
||||||
|
|
||||||
|
flush = buf_len > 0? Z_NO_FLUSH : Z_FINISH;
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_out = Z_CHUNK;
|
||||||
|
strm.next_out = z_outbuf;
|
||||||
|
|
||||||
|
ret = deflate(&strm, flush);
|
||||||
|
|
||||||
|
if (ret == Z_STREAM_ERROR) return SEND_ZLIB_ERROR;
|
||||||
|
|
||||||
|
result_len = Z_CHUNK - strm.avail_out;
|
||||||
|
unsigned char *result_ptr = z_outbuf;
|
||||||
|
|
||||||
|
send_result = send_data((char *)result_ptr, result_len);
|
||||||
|
|
||||||
|
} while (strm.avail_out == 0 && !httpc::control::listener_stop && send_result == SEND_OK);
|
||||||
|
} while ((buf_len > 0) && !httpc::control::listener_stop && send_result == SEND_OK);
|
||||||
|
|
||||||
|
strm.next_in = Z_NULL;
|
||||||
|
strm.next_out = Z_NULL;
|
||||||
|
(void)deflateEnd(&strm);
|
||||||
|
|
||||||
|
if (send_result != SEND_OK)
|
||||||
|
return send_result;
|
||||||
|
else
|
||||||
|
if (buf_len > 0)
|
||||||
|
return SEND_INCOMPLETE;
|
||||||
|
else
|
||||||
|
return SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t foo_httpserv::send_file(pfc::string_base &filepath)
|
||||||
|
{
|
||||||
|
size_t send_ret = pfc::infinite_size;
|
||||||
|
|
||||||
|
HANDLE inFile;
|
||||||
|
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 path_w(filepath);
|
||||||
|
inFile = CreateFileW(path_w, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||||
|
|
||||||
|
if (inFile == INVALID_HANDLE_VALUE)
|
||||||
|
return SEND_IO_ERROR;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD bytesread;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!ReadFile(inFile, filebuf, FILE_BUFFER, &bytesread, NULL))
|
||||||
|
{
|
||||||
|
send_ret = SEND_IO_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_ret = send_data(filebuf, bytesread);
|
||||||
|
|
||||||
|
if (bytesread <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
} while (bytesread > 0 && send_ret == SEND_OK && !httpc::control::listener_stop);
|
||||||
|
|
||||||
|
CloseHandle(inFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_ret != SEND_OK)
|
||||||
|
return send_ret;
|
||||||
|
else
|
||||||
|
return SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t foo_httpserv::send_file_zlib(pfc::string_base &filepath)
|
||||||
|
{
|
||||||
|
size_t send_ret = pfc::infinite_size;
|
||||||
|
HANDLE inFile;
|
||||||
|
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 path_w(filepath);
|
||||||
|
inFile = CreateFileW(path_w, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||||
|
|
||||||
|
if (inFile == INVALID_HANDLE_VALUE)
|
||||||
|
return SEND_IO_ERROR;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD bytesread;
|
||||||
|
|
||||||
|
z_stream strm;
|
||||||
|
strm.zalloc = Z_NULL;
|
||||||
|
strm.zfree = Z_NULL;
|
||||||
|
strm.opaque = Z_NULL;
|
||||||
|
|
||||||
|
t_size flush, result_len;
|
||||||
|
|
||||||
|
if (deflateInit2(&strm, Z_CLEVEL, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||||
|
{
|
||||||
|
CloseHandle(inFile);
|
||||||
|
return SEND_ZLIB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!ReadFile(inFile, filebuf, FILE_BUFFER, &bytesread, NULL))
|
||||||
|
{
|
||||||
|
send_ret = SEND_IO_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
strm.avail_in = Z_CHUNK > bytesread ? bytesread : Z_CHUNK;
|
||||||
|
strm.next_in = (unsigned char *) filebuf;
|
||||||
|
|
||||||
|
flush = bytesread > 0? Z_NO_FLUSH : Z_FINISH;
|
||||||
|
|
||||||
|
do {
|
||||||
|
strm.avail_out = Z_CHUNK;
|
||||||
|
strm.next_out = z_outbuf;
|
||||||
|
|
||||||
|
if (deflate(&strm, flush) == Z_STREAM_ERROR)
|
||||||
|
{
|
||||||
|
CloseHandle(inFile);
|
||||||
|
return SEND_ZLIB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
result_len = Z_CHUNK - strm.avail_out;
|
||||||
|
|
||||||
|
send_ret = send_data((char *)z_outbuf, result_len);
|
||||||
|
|
||||||
|
} while (strm.avail_out == 0 && !httpc::control::listener_stop && send_ret == SEND_OK);
|
||||||
|
} while (bytesread > 0 && send_ret == SEND_OK && !httpc::control::listener_stop);
|
||||||
|
|
||||||
|
CloseHandle(inFile);
|
||||||
|
strm.next_in = Z_NULL;
|
||||||
|
strm.next_out = Z_NULL;
|
||||||
|
(void)deflateEnd(&strm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_ret != SEND_OK)
|
||||||
|
return send_ret;
|
||||||
|
else
|
||||||
|
return SEND_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool foo_httpserv::is_gzip_encoding_supported()
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
char *accept_encoding = getheader("Accept-Encoding:");
|
||||||
|
if (accept_encoding)
|
||||||
|
{
|
||||||
|
result = strstr(accept_encoding, "gzip") == 0? false : true;
|
||||||
|
free(accept_encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo_httpserv::process_request()
|
||||||
|
{
|
||||||
|
pfc::string8 cmd, param1, param2, param3, request_url, fullpathfile, lastwritetime_str, tmp;
|
||||||
|
bool query_root, gzip_encoding_supported, gzip_compressible;
|
||||||
|
DWORD content_length = pfc::infinite_size;
|
||||||
|
|
||||||
|
timer.start();
|
||||||
|
m_err_str.reset();
|
||||||
|
t_size r = 0, ret = WSA_WAIT_TIMEOUT;
|
||||||
|
|
||||||
|
r = run();
|
||||||
|
|
||||||
|
if (r == 0)
|
||||||
|
{
|
||||||
|
HANDLE handle = WSACreateEvent();
|
||||||
|
if (WSAEventSelect(m_con->m_socket, handle, FD_READ | FD_CLOSE | FD_OOB) != 0)
|
||||||
|
foo_error("WSAEventSelect in process_request failed");
|
||||||
|
|
||||||
|
// sleeping while browser decided do keep stale tcp connection opened
|
||||||
|
while (r == 0 && ret != WSA_INVALID_HANDLE && (ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_TIMEOUT) )
|
||||||
|
{
|
||||||
|
ret = WSAWaitForMultipleEvents(1, &handle, FALSE, ~1, TRUE);
|
||||||
|
WSAResetEvent(handle);
|
||||||
|
r = run();
|
||||||
|
}
|
||||||
|
|
||||||
|
WSACloseEvent(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r != -1 && r != 0) // got something!
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&httpc::cs);
|
||||||
|
while (r != -1 && r != 4)
|
||||||
|
{
|
||||||
|
r = run();
|
||||||
|
|
||||||
|
if (r == 0) // wrong call...
|
||||||
|
{
|
||||||
|
Sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == 2)
|
||||||
|
{
|
||||||
|
cmd = string8_safe(get_request_parm("cmd"));
|
||||||
|
url_decode(string8_safe(get_request_file()), request_url);
|
||||||
|
url_decode(string8_safe(get_request_parm("param1")), param1);
|
||||||
|
url_decode(string8_safe(get_request_parm("param2")), param2);
|
||||||
|
url_decode(string8_safe(get_request_parm("param3")), param3);
|
||||||
|
|
||||||
|
if (param3.get_length())
|
||||||
|
if (param3.find_first("..\\") != pfc::infinite_size
|
||||||
|
|| param3.find_first("../") != pfc::infinite_size)
|
||||||
|
param3.reset(); // defend against level-up
|
||||||
|
|
||||||
|
pfc::list_t<pfc::string8> args;
|
||||||
|
pfc::splitStringSimple_toList(args, "/", request_url);
|
||||||
|
query_root = args.get_count() > 1 ? false : true;
|
||||||
|
|
||||||
|
// get remote IP address
|
||||||
|
char remotehost[16] = {0};
|
||||||
|
JNL::addr_to_ipstr(get_con()->get_remote(), remotehost, 15);
|
||||||
|
|
||||||
|
// remote IP doesn't match the set restriction
|
||||||
|
if(cfg.main.control_ip.get_length() && (strcmp(cfg.main.control_ip, "0.0.0.0") != 0) && strcmp(remotehost, cfg.main.control_ip) != 0)
|
||||||
|
{
|
||||||
|
set_reply_string("HTTP/1.0 403 Forbidden");
|
||||||
|
set_reply_header(content_type_str);
|
||||||
|
send_reply();
|
||||||
|
httpc::ui::generate_html_response(m_err_str, pfc::string_formatter() << "403 Forbidden", pfc::string_formatter() << access_denied_body);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// suggest user to authenticate if authentication is set
|
||||||
|
if(cfg.main.control_credentials)
|
||||||
|
{
|
||||||
|
char *auth = getheader("Authorization:");
|
||||||
|
|
||||||
|
if (auth && strcmp(auth, httpc::control_credentials_auth_hash) != 0 || !auth )
|
||||||
|
{
|
||||||
|
if (auth)
|
||||||
|
foo_error(pfc::string_formatter() << "AUTH request from " << remotehost << " denied. Auth: " << auth);
|
||||||
|
|
||||||
|
free(auth);
|
||||||
|
|
||||||
|
set_reply_string("HTTP/1.0 401 Authorization Required");
|
||||||
|
set_reply_header("WWW-Authenticate: Basic realm=\"Authorization\"");
|
||||||
|
set_reply_header(content_type_str);
|
||||||
|
send_reply();
|
||||||
|
httpc::ui::generate_html_response(m_err_str, pfc::string_formatter() << "403 Forbidden", pfc::string_formatter() << access_denied_body);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.get_count() >= 1)
|
||||||
|
{
|
||||||
|
pfc::string8 configpath = pfc::string_formatter() << httpc::srv_home_dir << "\\" << args[0] << "\\config";
|
||||||
|
if (!tcfg.loadtemplate(configpath, args[0]))
|
||||||
|
{
|
||||||
|
pfc::string8 body;
|
||||||
|
body << "<p>Error loading template configuration file:<br>foo_httpcontrol_data\\" << args[0] << "\\config</p><p>Most likely it happened because the directory are trying to open doesn't contain template, or template files there are incomplete.<p><font color=\"red\">Check foobar2000 console (View/Console) for error details.</font></p>";
|
||||||
|
body << "<p><a href=\"/\">Show installed templates</a></p>";
|
||||||
|
httpc::ui::generate_html_response(m_err_str, pfc::string_formatter() << "Template error", body);
|
||||||
|
set_reply_string("HTTP/1.0 404 Not Found");
|
||||||
|
foo_error(pfc::string_formatter() << "couldn't load " << configpath);
|
||||||
|
set_reply_header(content_type_str);
|
||||||
|
send_reply();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_reply_string("HTTP/1.0 200 OK");
|
||||||
|
httpc::ui::generate_installed_templates_list(m_err_str);
|
||||||
|
set_reply_header(content_type_str);
|
||||||
|
send_reply();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// proceeding with user request
|
||||||
|
{
|
||||||
|
bool request_ok = true;
|
||||||
|
|
||||||
|
fullpathfile = pfc::string_formatter() << httpc::srv_home_dir << request_url;
|
||||||
|
|
||||||
|
if (cfg.main.log_access)
|
||||||
|
log(cmd, param1, param2, param3, remotehost, request_url);
|
||||||
|
|
||||||
|
if (request_url.get_length() && !query_root)
|
||||||
|
{
|
||||||
|
// albumart requested
|
||||||
|
if (strstr(request_url, "/albumart_") > request_url)
|
||||||
|
{
|
||||||
|
// albumart from file
|
||||||
|
if (httpc::pb_albumart_status & httpc::AS_FILE)
|
||||||
|
{
|
||||||
|
fullpathfile = httpc::pb_albumart_path;
|
||||||
|
request_ok = is_fileexists(fullpathfile, content_length, lastwritetime_str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// invalid albumart memory
|
||||||
|
if ((httpc::pb_albumart_status & httpc::AS_MEMORY)
|
||||||
|
&& httpc::pb_albumart_embedded_ptr.is_empty())
|
||||||
|
{
|
||||||
|
fullpathfile = pfc::string_formatter() << tcfg.get().local_path << tcfg.get().albumart_not_found;
|
||||||
|
request_ok = is_fileexists(fullpathfile, content_length, lastwritetime_str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// albumart from memory
|
||||||
|
if ((httpc::pb_albumart_status & httpc::AS_MEMORY)
|
||||||
|
&& httpc::pb_albumart_embedded_ptr.is_valid())
|
||||||
|
{
|
||||||
|
request_url.reset();
|
||||||
|
is_fileexists(httpc::pb_albumart_embedded_file, content_length, lastwritetime_str);
|
||||||
|
content_length = httpc::pb_albumart_embedded_ptr->get_size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
request_ok = false;
|
||||||
|
}
|
||||||
|
// requested other file
|
||||||
|
else
|
||||||
|
{
|
||||||
|
request_ok = false;
|
||||||
|
|
||||||
|
if (fullpathfile.find_first("..\\") == pfc::infinite_size
|
||||||
|
&& fullpathfile.find_first("../") == pfc::infinite_size ) // don't do this, dudley :-)
|
||||||
|
request_ok = is_fileexists(fullpathfile, content_length, lastwritetime_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request_ok)
|
||||||
|
{
|
||||||
|
pfc::string8_fast_aggressive response_headers("Content-Type: ");
|
||||||
|
pfc::string8_fast_aggressive content_type;
|
||||||
|
|
||||||
|
pfc::string8 p3_mime = mime.get_content_type(param3, gzip_compressible);
|
||||||
|
|
||||||
|
if ((request_url.get_length() == 1 || query_root) && !p3_mime.get_length())
|
||||||
|
content_type << mime.get_content_type(pfc::string8("x.htm"), gzip_compressible);
|
||||||
|
else if ((strstr(request_url, "/albumart_") > request_url) && (httpc::pb_albumart_status & httpc::AS_FILE))
|
||||||
|
content_type << mime.get_content_type(httpc::pb_albumart_path, gzip_compressible);
|
||||||
|
else
|
||||||
|
if (p3_mime.get_length())
|
||||||
|
content_type << p3_mime;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p3_mime = mime.get_content_type(request_url, gzip_compressible);
|
||||||
|
|
||||||
|
if (p3_mime.get_length())
|
||||||
|
content_type << p3_mime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_type.get_length())
|
||||||
|
response_headers << content_type;
|
||||||
|
else
|
||||||
|
response_headers << "application/octet-stream";
|
||||||
|
|
||||||
|
response_headers << "\r\nConnection: close";
|
||||||
|
|
||||||
|
gzip_encoding_supported = is_gzip_encoding_supported();
|
||||||
|
|
||||||
|
if (gzip_compressible && gzip_encoding_supported && cfg.main.gzip_enable)
|
||||||
|
response_headers << "\r\nContent-Encoding: gzip";
|
||||||
|
|
||||||
|
set_reply_string("HTTP/1.0 200 OK");
|
||||||
|
|
||||||
|
// returning generated response
|
||||||
|
if (!request_url.get_length() || query_root)
|
||||||
|
{
|
||||||
|
if (!httpc::control::process_command_event)
|
||||||
|
httpc::control::process_command_event = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||||
|
|
||||||
|
ResetEvent(httpc::control::process_command_event);
|
||||||
|
httpc::control::process_command(cmd, param1, param2, param3);
|
||||||
|
WaitForSingleObject(httpc::control::process_command_event, 15000);
|
||||||
|
|
||||||
|
set_reply_header(const_cast<char *>(response_headers.toString()));
|
||||||
|
set_reply_header(content_no_refresh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// returning requested file
|
||||||
|
{
|
||||||
|
set_reply_header(const_cast<char *>(response_headers.toString()));
|
||||||
|
|
||||||
|
if (lastwritetime_str)
|
||||||
|
{
|
||||||
|
pfc::string8 last_modified_str = pfc::string_formatter() << "Last-Modified: " << lastwritetime_str;
|
||||||
|
set_reply_header(const_cast<char *>(last_modified_str.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(gzip_compressible && gzip_encoding_supported && cfg.main.gzip_enable))
|
||||||
|
{
|
||||||
|
pfc::string8 content_length_str;
|
||||||
|
content_length_str << "Content-Length: " << (size_t) content_length;
|
||||||
|
set_reply_header(const_cast<char *>(content_length_str.toString()) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_reply();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_reply_string("HTTP/1.0 404 Not Found");
|
||||||
|
set_reply_header(content_type_str);
|
||||||
|
set_reply_header(content_no_refresh);
|
||||||
|
send_reply();
|
||||||
|
httpc::ui::generate_html_response(m_err_str, pfc::string_formatter() << "404 Not Found", pfc::string_formatter() << "<h1>404 Not Found</h1>The requested url " << request_url << " was not found on the server.");
|
||||||
|
foo_error(pfc::string_formatter() << "couldn't load " << fullpathfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r == 3)
|
||||||
|
{
|
||||||
|
t_size send_result = pfc_infinite;
|
||||||
|
|
||||||
|
if (m_err_str.get_length()) // sending error msg if available
|
||||||
|
{
|
||||||
|
send_result = send_data(const_cast<char *>(m_err_str.toString()), m_err_str.get_length());
|
||||||
|
m_err_str.reset();
|
||||||
|
}
|
||||||
|
else // no error msg, proceeding
|
||||||
|
{
|
||||||
|
pfc::string8_fast_aggressive show = " ";
|
||||||
|
|
||||||
|
// sending albumart
|
||||||
|
if (request_url.get_length() == 0 && httpc::pb_albumart_status == httpc::AS_MEMORY && httpc::pb_albumart_embedded_ptr.is_valid())
|
||||||
|
send_result = send_data(static_cast<char *>(const_cast<void *>(httpc::pb_albumart_embedded_ptr->get_ptr())), httpc::pb_albumart_embedded_ptr->get_size());
|
||||||
|
else
|
||||||
|
// returning actual file
|
||||||
|
if (request_url.get_length() > 1 && !query_root)
|
||||||
|
if (gzip_compressible && gzip_encoding_supported && cfg.main.gzip_enable)
|
||||||
|
send_result = send_file_zlib(fullpathfile);
|
||||||
|
else
|
||||||
|
send_result = send_file(fullpathfile);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// returning generated response
|
||||||
|
if (strcmp(cmd, "Parse") == 0)
|
||||||
|
{
|
||||||
|
httpc::ui::set_buffer_from_string(param1);
|
||||||
|
httpc::ui::parse_buffer_controls(show, timer);
|
||||||
|
}
|
||||||
|
else if (httpc::control::command_result.get_length())
|
||||||
|
{
|
||||||
|
show = httpc::control::command_result;
|
||||||
|
httpc::control::command_result.reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (strcmp(cmd, "Browse") == 0)
|
||||||
|
{
|
||||||
|
if (param1.get_length() == 0)
|
||||||
|
param1 = cfg.misc.last_browse_dir;
|
||||||
|
|
||||||
|
if (cfg.restrict_to_path_list.get_count()) // allowing to browse only specified dirs (if any)
|
||||||
|
{
|
||||||
|
bool isallowed = false;
|
||||||
|
|
||||||
|
if (param1.get_length() > 0)
|
||||||
|
{
|
||||||
|
pfc::string tmp2(param1.toString());
|
||||||
|
t_size l = cfg.restrict_to_path_list.get_count();
|
||||||
|
|
||||||
|
if ((tmp2.indexOf("..\\") == ~0) && (tmp2.indexOf("../") == ~0)) // check for stuff like d:\music\..\..\..\temp
|
||||||
|
for (size_t i = 0; i < l; ++i)
|
||||||
|
{
|
||||||
|
pfc::string8_fast_aggressive tmp(param1);
|
||||||
|
tmp.truncate(cfg.restrict_to_path_list[i].get_length());
|
||||||
|
|
||||||
|
if (pfc::stringCompareCaseInsensitive(tmp, cfg.restrict_to_path_list[i]) == 0)
|
||||||
|
{
|
||||||
|
isallowed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! isallowed)
|
||||||
|
param1 = " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip file name from path if the user clicked on file
|
||||||
|
bool is_file = false;
|
||||||
|
|
||||||
|
if (param1.length() > 3 && param1[param1.length()-1] != '\\')
|
||||||
|
{
|
||||||
|
char *stripped_filename = foo_browsefiles::get_path_parent((char *)param1.operator const char *());
|
||||||
|
if (stripped_filename)
|
||||||
|
{
|
||||||
|
param1 = stripped_filename;
|
||||||
|
delete[] stripped_filename;
|
||||||
|
}
|
||||||
|
else // invalid request, displaying root
|
||||||
|
param1 = " ";
|
||||||
|
|
||||||
|
is_file = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(strcmp(param3, "NoResponse") == 0))
|
||||||
|
{
|
||||||
|
httpc::ui::set_buffer_from_file(param3, 2);
|
||||||
|
httpc::ui::parse_buffer_browser(param1, show, timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param1.get_length() != 0 && !is_file)
|
||||||
|
cfg.misc.last_browse_dir = param1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(strcmp(param3, "NoResponse") == 0))
|
||||||
|
{
|
||||||
|
httpc::ui::set_buffer_from_file(param3, 1);
|
||||||
|
httpc::ui::parse_buffer_controls(show, timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gzip_compressible && gzip_encoding_supported && cfg.main.gzip_enable)
|
||||||
|
send_result = send_data_zlib(const_cast<char *>(show.get_ptr()), show.get_length());
|
||||||
|
else
|
||||||
|
send_result = send_data(const_cast<char *>(show.get_ptr()), show.get_length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_result != 0)
|
||||||
|
foo_error(pfc::string_formatter() << "send: " << send_result << " on request: " << request_url);
|
||||||
|
|
||||||
|
r = 4;
|
||||||
|
|
||||||
|
close(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&httpc::cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
150
foo_httpcontrol/src/httpserver.h
Executable file
@@ -0,0 +1,150 @@
|
|||||||
|
#ifndef ___HTTPSERVER_H___
|
||||||
|
#define ___HTTPSERVER_H___
|
||||||
|
|
||||||
|
#define SEND_BUFFER 262144
|
||||||
|
#define RECIEVE_BUFFER 16384
|
||||||
|
|
||||||
|
#define Z_CHUNK SEND_BUFFER / 2
|
||||||
|
#define Z_CLEVEL Z_DEFAULT_COMPRESSION
|
||||||
|
|
||||||
|
#define FILE_BUFFER SEND_BUFFER / 2
|
||||||
|
|
||||||
|
#if (FILE_BUFFER_SIZE > Z_CHUNK)
|
||||||
|
#error file buffer size must be less or equal to Z_CHUNK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern char *access_denied_body;
|
||||||
|
extern char *auth_str;
|
||||||
|
extern char *content_type_str;
|
||||||
|
extern char *content_no_refresh;
|
||||||
|
|
||||||
|
class foo_httpserver_command;
|
||||||
|
|
||||||
|
namespace httpc {
|
||||||
|
namespace control {
|
||||||
|
typedef pfc::map_t<const char *, bool (* )(foo_httpserver_command *), pfc::comparator_strcmp> commands_map;
|
||||||
|
|
||||||
|
extern HANDLE process_command_event;
|
||||||
|
|
||||||
|
extern void process_command(pfc::string_base &cmd, pfc::string_base ¶m1, pfc::string_base ¶m2, pfc::string_base ¶m3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class foo_httpserv : public JNL_HTTPServ
|
||||||
|
{
|
||||||
|
enum send_codes {
|
||||||
|
SEND_OK,
|
||||||
|
SEND_INCOMPLETE,
|
||||||
|
SEND_SOCKET_ERROR,
|
||||||
|
SEND_IO_ERROR,
|
||||||
|
SEND_ZLIB_ERROR
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
unsigned char z_outbuf[Z_CHUNK];
|
||||||
|
char filebuf[FILE_BUFFER];
|
||||||
|
|
||||||
|
pfc::string8 m_err_str;
|
||||||
|
size_t send_data(char *buf, size_t buf_len);
|
||||||
|
size_t send_data_zlib(char *buf, size_t buf_len);
|
||||||
|
size_t send_file(pfc::string_base &filepath);
|
||||||
|
size_t send_file_zlib(pfc::string_base &filepath);
|
||||||
|
size_t content_type(const char *request);
|
||||||
|
bool is_gzip_encoding_supported();
|
||||||
|
pfc::hires_timer timer;
|
||||||
|
void foo_httpserv::log(pfc::string_base &cmd, pfc::string_base ¶m1, pfc::string_base ¶m2, pfc::string_base ¶m3, char *remotehost, pfc::string_base &request_url);
|
||||||
|
public:
|
||||||
|
foo_httpserv(JNL_Connection *con) : JNL_HTTPServ(con) { }
|
||||||
|
|
||||||
|
int threadnum;
|
||||||
|
|
||||||
|
void process_request();
|
||||||
|
};
|
||||||
|
|
||||||
|
class foo_httpserver_command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
foo_httpserver_command() { };
|
||||||
|
foo_httpserver_command(pfc::string8 cmd, pfc::string8 param1, pfc::string8 param2, pfc::string8 param3) : m_cmd(cmd), m_param1(param1), m_param2(param2), m_param3(param3) { };
|
||||||
|
|
||||||
|
pfc::string8 &get_command() { return m_cmd; }
|
||||||
|
pfc::string8 &get_param(int index)
|
||||||
|
{
|
||||||
|
switch(index) {
|
||||||
|
case 0: return m_param1;
|
||||||
|
case 1: return m_param2;
|
||||||
|
case 2: return m_param3;
|
||||||
|
default: return m_param1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
pfc::string8 m_cmd;
|
||||||
|
pfc::string8 m_param1;
|
||||||
|
pfc::string8 m_param2;
|
||||||
|
pfc::string8 m_param3;
|
||||||
|
};
|
||||||
|
|
||||||
|
class mimetypes {
|
||||||
|
private:
|
||||||
|
pfc::map_t<const char *, const char *, pfc::comparator_stricmp_ascii> m_mimeTypes;
|
||||||
|
pfc::map_t<const char *, bool, pfc::comparator_stricmp_ascii> m_compressibleTypes;
|
||||||
|
public:
|
||||||
|
|
||||||
|
mimetypes ()
|
||||||
|
{
|
||||||
|
m_mimeTypes["json"] = "application/json; Charset=UTF-8";
|
||||||
|
m_mimeTypes["html"] = "text/html; Charset=UTF-8";
|
||||||
|
m_mimeTypes["jpg"] = "image/jpeg";
|
||||||
|
m_mimeTypes["js"] = "application/x-javascript; Charset=UTF-8";
|
||||||
|
m_mimeTypes["css"] = "text/css";
|
||||||
|
m_mimeTypes["ico"] = "image/x-icon";
|
||||||
|
m_mimeTypes["gif"] = "image/gif";
|
||||||
|
m_mimeTypes["jpe"] = m_mimeTypes["jpg"];
|
||||||
|
m_mimeTypes["jpeg"] = m_mimeTypes["jpg"];
|
||||||
|
m_mimeTypes["png"] = "image/png";
|
||||||
|
m_mimeTypes["xml"] = "text/xml; Charset=UTF-8";
|
||||||
|
m_mimeTypes["htm"] = m_mimeTypes["html"];
|
||||||
|
|
||||||
|
m_compressibleTypes["json"] = true;
|
||||||
|
m_compressibleTypes["html"] = true;
|
||||||
|
m_compressibleTypes["js"] = true;
|
||||||
|
m_compressibleTypes["css"] = true;
|
||||||
|
m_compressibleTypes["xml"] = true;
|
||||||
|
m_compressibleTypes["htm"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfc::string_simple get_content_type(pfc::string_base &request, bool &compressible)
|
||||||
|
{
|
||||||
|
const char *extension = NULL;
|
||||||
|
t_size l = request.get_length();
|
||||||
|
int shift = pfc::infinite_size;
|
||||||
|
|
||||||
|
compressible = false;
|
||||||
|
|
||||||
|
for (int i = l-2; i >= (int)l-5 && i >= 0; --i)
|
||||||
|
if (request[i] == '.')
|
||||||
|
{
|
||||||
|
shift = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shift != pfc::infinite_size && (shift + 1) != l)
|
||||||
|
extension = request.get_ptr() + shift + 1;
|
||||||
|
|
||||||
|
if (extension != NULL)
|
||||||
|
{
|
||||||
|
if (m_mimeTypes.have_item(extension))
|
||||||
|
{
|
||||||
|
compressible = m_compressibleTypes.have_item(extension);
|
||||||
|
return m_mimeTypes[extension];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compressible = false;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern mimetypes mime;
|
||||||
|
|
||||||
|
#endif //___HTTPSERVER_H___
|
||||||
30
foo_httpcontrol/src/resource.h
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef IDC_STATIC
|
||||||
|
#define IDC_STATIC (-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IDD_TAB1 101
|
||||||
|
#define IDD_TAB3 104
|
||||||
|
#define IDC_INTERFACE 1001
|
||||||
|
#define IDC_PORT 1002
|
||||||
|
#define IDC_CONTROL_IP 1003
|
||||||
|
#define IDC_CONTROL_CREDENTIALS 1012
|
||||||
|
#define IDC_CONTROL_USERNAME 1013
|
||||||
|
#define IDC_CONTROL_PASSWORD 1014
|
||||||
|
#define IDC_STATIC_USERNAME 1015
|
||||||
|
#define IDC_STATIC_PASSWORD 1016
|
||||||
|
#define IDC_CONTROL_PATH 1018
|
||||||
|
#define IDC_HIDE_NONPLAYABLES 1019
|
||||||
|
#define IDC_LOG_ACCESS 1020
|
||||||
|
#define IDC_SERVER_ROOT 1021
|
||||||
|
#define IDC_EXTRA_FORMATS 1022
|
||||||
|
#define IDC_AUTOPLAYLIST_SENDTODEDICATED 1033
|
||||||
|
#define IDC_AUTOPLAYLIST_SORT_PATTERN 1034
|
||||||
|
#define IDC_SERVERSTARTED 1035
|
||||||
|
#define IDC_AUTOPLAYLIST_QUERY_STEP1 1036
|
||||||
|
#define IDC_AUTOPLAYLIST_QUERY_STEP2 1037
|
||||||
|
#define IDC_AUTOPLAYLIST_QUERY_STEP3 1039
|
||||||
|
#define IDC_STOP_AFTER_QUEUE_ENABLE 1040
|
||||||
|
#define IDC_SERVER_ROOT_BTN 1041
|
||||||
|
#define IDC_GZIP_ENABLE 1042
|
||||||
|
#define IDC_LAUNCH_BROWSER 1046
|
||||||
|
#define IDC_IGNORED_FORMATS 1048
|
||||||
717
foo_httpcontrol/src/state.cpp
Executable file
@@ -0,0 +1,717 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "browsefiles.h"
|
||||||
|
#define _CRT_RAND_S
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
namespace httpc {
|
||||||
|
service_ptr_t<titleformat_object> script_playlist_row;
|
||||||
|
service_ptr_t<titleformat_object> script_helper1;
|
||||||
|
service_ptr_t<titleformat_object> script_helper2;
|
||||||
|
service_ptr_t<titleformat_object> script_helper3;
|
||||||
|
service_ptr_t<titleformat_object> script_albumart_lookup;
|
||||||
|
|
||||||
|
CRITICAL_SECTION cs;
|
||||||
|
|
||||||
|
bool enqueueing; // if enqueueing is in progress;
|
||||||
|
|
||||||
|
size_t pb_state; // current foobar state
|
||||||
|
size_t last_action; // previously selected playlist action
|
||||||
|
size_t state_changed; // previous state change
|
||||||
|
float volume;
|
||||||
|
pfc::string8 pb_helper1;
|
||||||
|
pfc::string8 pb_helper2;
|
||||||
|
pfc::string8 pb_helper3;
|
||||||
|
pfc::string8 pb_helper1x;
|
||||||
|
pfc::string8 pb_helper2x;
|
||||||
|
pfc::string8 pb_helper3x;
|
||||||
|
pfc::string8 pb_albumart_path;
|
||||||
|
pfc::string8 pb_albumart_path_crc32;
|
||||||
|
pfc::string8 pb_albumart_lookup;
|
||||||
|
pfc::string8 pb_albumart_embedded_file;
|
||||||
|
albumart_status pb_albumart_status;
|
||||||
|
album_art_data_ptr pb_albumart_embedded_ptr;
|
||||||
|
size_t pb_item; // playing item
|
||||||
|
double pb_length; // playing item length
|
||||||
|
double pb_time; // playing item position
|
||||||
|
size_t pb_playlist; // playing playlist
|
||||||
|
size_t pb_playlist_item_count; // playing playlist item count
|
||||||
|
size_t pb_item_prev; // previously played item
|
||||||
|
size_t pb_playlist_prev; // previously played playlist
|
||||||
|
size_t playlist_item_focused; // focused item of current playlist
|
||||||
|
size_t playlist_page; // page number of current playlist
|
||||||
|
size_t active_playlist;
|
||||||
|
size_t active_playlist_item_count;
|
||||||
|
size_t query_playlist;
|
||||||
|
bool playlist_page_switched;
|
||||||
|
bool should_focus_on_playing;
|
||||||
|
bool should_update_playlist;
|
||||||
|
bool should_update_playlist_total_time;
|
||||||
|
bool should_update_playlists_list;
|
||||||
|
bool should_update_queue;
|
||||||
|
pfc::list_t<playlist_entry,pfc::alloc_fast_aggressive> playlist_view;
|
||||||
|
pfc::string_simple playlist_total_time;
|
||||||
|
pfc::string_simple queue_total_time;
|
||||||
|
bool sac; // stop after current flag
|
||||||
|
bool reset_sac; // reset stop after current after track stop flag;
|
||||||
|
bool active_playlist_is_undo_available;
|
||||||
|
bool active_playlist_is_redo_available;
|
||||||
|
pfc::string_simple control_credentials_auth_hash;
|
||||||
|
pfc::list_t<pfc::string_simple> extensions; // registered extensions
|
||||||
|
pfc::list_t<pfc::string_simple> extension_names;// registered extension names
|
||||||
|
pfc::string8 restrict_mask; // restrict mask based on registered extensions
|
||||||
|
pfc::list_t<playlist_info> playlist_list; // list of playlists
|
||||||
|
pfc::string8 fb2k_profile_path;
|
||||||
|
pfc::string8 fb2k_path;
|
||||||
|
pfc::string8 srv_home_dir;
|
||||||
|
pfc::string_simple autoplaylist_request;
|
||||||
|
|
||||||
|
pfc::hires_timer timer;
|
||||||
|
|
||||||
|
class albumart_apev2_extractor : public album_art_extractor_impl_stdtags {
|
||||||
|
albumart_apev2_extractor();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void update_previouslyplayed()
|
||||||
|
{
|
||||||
|
if (pb_item != pfc::infinite_size && pb_playlist != pfc::infinite_size)
|
||||||
|
{
|
||||||
|
pb_item_prev = pb_item;
|
||||||
|
pb_playlist_prev = pb_playlist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enqueue(pfc::list_t<t_size> &list)
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
|
||||||
|
if (list.get_count())
|
||||||
|
plm->activeplaylist_set_focus_item(list[list.get_count()-1]);
|
||||||
|
|
||||||
|
for (t_size i = 0; i < list.get_count(); ++i)
|
||||||
|
plm->queue_add_item_playlist(plm->get_active_playlist(), list.get_item(i));
|
||||||
|
|
||||||
|
state_changed |= FSC_PLAYLIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dequeue(pfc::list_t<t_size> &list)
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
|
||||||
|
if (list.get_count())
|
||||||
|
plm->activeplaylist_set_focus_item(list[list.get_count()-1]);
|
||||||
|
|
||||||
|
for (t_size j = 0; j < list.get_count(); ++j)
|
||||||
|
{
|
||||||
|
size_t queue_item = pfc::infinite_size;
|
||||||
|
|
||||||
|
pfc::list_t<t_playback_queue_item> queue;
|
||||||
|
plm->queue_get_contents(queue);
|
||||||
|
|
||||||
|
if (queue.get_count() && plm->activeplaylist_get_item_count() > list.get_item(j))
|
||||||
|
for (unsigned int i = 0; i < queue.get_count() ; ++i)
|
||||||
|
{
|
||||||
|
t_playback_queue_item &qi = queue[i];
|
||||||
|
|
||||||
|
if (qi.m_item == list.get_item(j)
|
||||||
|
&& qi.m_playlist == active_playlist
|
||||||
|
&& plm->activeplaylist_get_item_handle(list.get_item(j)) == qi.m_handle)
|
||||||
|
{
|
||||||
|
queue_item = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue_item != pfc::infinite_size)
|
||||||
|
plm->queue_remove_mask(bit_array_one(queue_item));
|
||||||
|
}
|
||||||
|
|
||||||
|
state_changed |= FSC_PLAYLIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void empty_info()
|
||||||
|
{
|
||||||
|
pb_state = httpc::FOO_STOPPED;
|
||||||
|
pb_time = 0;
|
||||||
|
pb_length = 0;
|
||||||
|
pb_helper1.reset();
|
||||||
|
pb_helper2.reset();
|
||||||
|
pb_helper3.reset();
|
||||||
|
pb_helper1x.reset();
|
||||||
|
pb_helper2x.reset();
|
||||||
|
pb_helper3x.reset();
|
||||||
|
pb_item = pfc::infinite_size;
|
||||||
|
pb_playlist = pfc::infinite_size;
|
||||||
|
pb_playlist_item_count = pfc::infinite_size;
|
||||||
|
pb_albumart_path.reset();
|
||||||
|
pb_albumart_path_crc32 = tcfg.get().albumart_not_available;
|
||||||
|
pb_albumart_embedded_ptr.release();
|
||||||
|
pb_albumart_status = httpc::AS_NO_INFO;
|
||||||
|
active_playlist_item_count = pfc::infinite_size;
|
||||||
|
state_changed = FSC_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void empty_previouslyplayed()
|
||||||
|
{
|
||||||
|
pb_item_prev = pfc::infinite_size;
|
||||||
|
pb_playlist_prev = pfc::infinite_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_volume(float p_volume)
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playback_control> plc;
|
||||||
|
|
||||||
|
if ((abs(p_volume) - 1.0) < 0.001)
|
||||||
|
httpc::volume = plc->get_volume();
|
||||||
|
else
|
||||||
|
httpc::volume = p_volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_volume(t_size percent)
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playback_control> pc;
|
||||||
|
|
||||||
|
if (percent > 100)
|
||||||
|
percent = 100;
|
||||||
|
|
||||||
|
float scale = (float)(percent / 100.0);
|
||||||
|
float gain = (float)(20.0 * log10(scale));
|
||||||
|
pc->set_volume(gain);
|
||||||
|
httpc::volume = pc->get_volume();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte get_volume()
|
||||||
|
{
|
||||||
|
return (byte)(pow(10.0,httpc::volume / 20.0) * 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void retrieve_albumart(metadb_handle_ptr pb_item_ptr)
|
||||||
|
{
|
||||||
|
pb_albumart_status = AS_NOT_FOUND;
|
||||||
|
|
||||||
|
// looking for an external albumart by predefined path mask pb_albumart_lookup
|
||||||
|
if (pb_albumart_lookup.get_length()>0)
|
||||||
|
{
|
||||||
|
pfc::list_t<pfc::string8> lookups;
|
||||||
|
|
||||||
|
get_list(pb_albumart_lookup, lookups, '|', false);
|
||||||
|
|
||||||
|
HANDLE hFind;
|
||||||
|
LPWIN32_FIND_DATAW findFileData;
|
||||||
|
findFileData = new WIN32_FIND_DATAW;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lookups.get_count(); ++i)
|
||||||
|
{
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 mask(lookups[i]);
|
||||||
|
|
||||||
|
hFind = FindFirstFileW(mask.get_ptr(), findFileData);
|
||||||
|
|
||||||
|
if (hFind != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
pfc::stringcvt::string_utf8_from_wide filename(findFileData->cFileName);
|
||||||
|
pfc::string_directory directory(lookups[i]);
|
||||||
|
|
||||||
|
// todo: check for file size
|
||||||
|
t_size filesize = findFileData->nFileSizeHigh * ((long)MAXDWORD+1) + findFileData->nFileSizeLow;
|
||||||
|
|
||||||
|
pb_albumart_path = directory;
|
||||||
|
|
||||||
|
if (pb_albumart_path.get_length())
|
||||||
|
pb_albumart_path.fix_dir_separator('\\');
|
||||||
|
|
||||||
|
pb_albumart_path << filename;
|
||||||
|
|
||||||
|
pb_albumart_path_crc32 = pfc::string_formatter() << "/" << pfc::string8(tcfg.get().root) << pfc::string8("/albumart_") << calcCRC(pb_albumart_path, strlen(pb_albumart_path)) << "." << pfc::string_extension(filename);
|
||||||
|
|
||||||
|
FindClose(hFind);
|
||||||
|
|
||||||
|
if (tcfg.get().albumart_limit_size != 0 && filesize <= tcfg.get().albumart_limit_size || tcfg.get().albumart_limit_size == 0)
|
||||||
|
pb_albumart_status = AS_FILE;
|
||||||
|
else
|
||||||
|
pb_albumart_status = AS_NOT_FOUND;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete findFileData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( /*cfg.main.albumart_embedded_retrieve */
|
||||||
|
pb_albumart_status & AS_NOT_FOUND || tcfg.get().albumart_prefer_embedded )
|
||||||
|
{
|
||||||
|
abort_callback_dummy p_abort;
|
||||||
|
album_art_manager_instance_ptr aami = static_api_ptr_t<album_art_manager>()->instantiate();
|
||||||
|
if (aami->open(pb_item_ptr->get_path(), p_abort))
|
||||||
|
{
|
||||||
|
pb_albumart_embedded_ptr.release();
|
||||||
|
pb_albumart_status = AS_MEMORY;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pb_albumart_embedded_ptr = aami->query(album_art_ids::cover_front, p_abort);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pb_albumart_embedded_ptr = aami->query(album_art_ids::cover_back, p_abort);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pb_albumart_embedded_ptr = aami->query(album_art_ids::disc, p_abort);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pb_albumart_embedded_ptr = aami->query(album_art_ids::icon, p_abort);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
if (pb_albumart_status != AS_FILE)
|
||||||
|
pb_albumart_status = AS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb_albumart_status == AS_MEMORY
|
||||||
|
&& pb_albumart_embedded_ptr.is_valid()
|
||||||
|
&& pb_albumart_embedded_ptr->get_size()
|
||||||
|
&& ((tcfg.get().albumart_limit_size != 0) && (pb_albumart_embedded_ptr->get_size() <= tcfg.get().albumart_limit_size) || tcfg.get().albumart_limit_size == 0 ))
|
||||||
|
{
|
||||||
|
pb_albumart_embedded_file = file_path_display(pb_item_ptr->get_path());
|
||||||
|
pb_albumart_path_crc32 = pfc::string_formatter() << "/" << pfc::string8(tcfg.get().root) <<pfc::string8("/albumart_") << calcCRC(pb_albumart_embedded_file, pb_albumart_embedded_file.get_length());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pb_albumart_status != AS_FILE)
|
||||||
|
pb_albumart_status = AS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aami.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pb_albumart_status & AS_NOT_FOUND)
|
||||||
|
pb_albumart_path_crc32 = tcfg.get().albumart_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_playing_info()
|
||||||
|
{
|
||||||
|
if (!httpc::control::is_active() || !tcfg.get_count())
|
||||||
|
return;
|
||||||
|
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
static_api_ptr_t<playback_control> plc;
|
||||||
|
static_api_ptr_t<play_control> pc;
|
||||||
|
metadb_handle_ptr pb_item_ptr;
|
||||||
|
t_size index;
|
||||||
|
|
||||||
|
pb_item = pfc::infinite_size;
|
||||||
|
pb_playlist = pfc::infinite_size;
|
||||||
|
|
||||||
|
if(pc->get_now_playing(pb_item_ptr))
|
||||||
|
if(plm->get_playing_item_location(&pb_playlist, &index))
|
||||||
|
pb_item = index;
|
||||||
|
|
||||||
|
if (pb_playlist != pfc::infinite_size)
|
||||||
|
pb_playlist_item_count = plm->playlist_get_item_count(pb_playlist);
|
||||||
|
else
|
||||||
|
pb_playlist_item_count = pfc::infinite_size;
|
||||||
|
|
||||||
|
if (plm->get_playlist_count() == 1)
|
||||||
|
plm->set_active_playlist(0);
|
||||||
|
|
||||||
|
active_playlist = plm->get_active_playlist();
|
||||||
|
|
||||||
|
playlist_item_focused = plm->playlist_get_focus_item(plm->get_active_playlist());
|
||||||
|
|
||||||
|
active_playlist_item_count = plm->playlist_get_item_count(plm->get_active_playlist());
|
||||||
|
|
||||||
|
t_size page_prev = httpc::playlist_page;
|
||||||
|
|
||||||
|
if (tcfg.get().playlist_items_per_page != 0)
|
||||||
|
{
|
||||||
|
if (should_focus_on_playing)
|
||||||
|
{
|
||||||
|
if (active_playlist == pb_playlist && pb_item != pfc::infinite_size)
|
||||||
|
playlist_page = (t_size)ceil((pb_item+1)*1.0 / tcfg.get().playlist_items_per_page*1.0);
|
||||||
|
else
|
||||||
|
if (playlist_item_focused != pfc::infinite_size)
|
||||||
|
playlist_page = (t_size)ceil((playlist_item_focused+1)*1.0 / tcfg.get().playlist_items_per_page*1.0);
|
||||||
|
|
||||||
|
should_focus_on_playing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playlist_page == pfc::infinite_size || playlist_page == 0)
|
||||||
|
playlist_page = 1;
|
||||||
|
|
||||||
|
if (playlist_page > (t_size)ceil(active_playlist_item_count*1.0 / tcfg.get().playlist_items_per_page*1.0))
|
||||||
|
playlist_page = (t_size)ceil(active_playlist_item_count*1.0 / tcfg.get().playlist_items_per_page*1.0);
|
||||||
|
|
||||||
|
if (page_prev != playlist_page)
|
||||||
|
httpc::playlist_page_switched = true;
|
||||||
|
else
|
||||||
|
playlist_page_switched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc->get_now_playing(pb_item_ptr))
|
||||||
|
{
|
||||||
|
pb_length = pb_item_ptr->get_length();
|
||||||
|
|
||||||
|
if (pb_playlist == pfc::infinite_size || pb_item == pfc::infinite_size)
|
||||||
|
{
|
||||||
|
pb_item_ptr->format_title(NULL, pb_helper1, script_helper1, NULL);
|
||||||
|
pb_item_ptr->format_title(NULL, pb_helper2, script_helper2, NULL);
|
||||||
|
pb_item_ptr->format_title(NULL, pb_helper3, script_helper3, NULL);
|
||||||
|
pb_item_ptr->format_title(NULL, pb_albumart_lookup, script_albumart_lookup, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plm->playlist_item_format_title(pb_playlist,pb_item,NULL,pb_helper1,script_helper1,NULL,playback_control::display_level_all);
|
||||||
|
plm->playlist_item_format_title(pb_playlist,pb_item,NULL,pb_helper2,script_helper2,NULL,playback_control::display_level_all);
|
||||||
|
plm->playlist_item_format_title(pb_playlist,pb_item,NULL,pb_helper3,script_helper3,NULL,playback_control::display_level_all);
|
||||||
|
plm->playlist_item_format_title(pb_playlist,pb_item,NULL,pb_albumart_lookup,script_albumart_lookup,NULL,playback_control::display_level_all);
|
||||||
|
}
|
||||||
|
|
||||||
|
pb_helper1x = xml_friendly_string(pb_helper1);
|
||||||
|
pb_helper2x = xml_friendly_string(pb_helper2);
|
||||||
|
pb_helper3x = xml_friendly_string(pb_helper3);
|
||||||
|
|
||||||
|
retrieve_albumart(pb_item_ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pb_albumart_path_crc32 = tcfg.get().albumart_not_available;
|
||||||
|
pb_albumart_status = AS_NO_INFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc->is_paused())
|
||||||
|
httpc::pb_state = FOO_PAUSED;
|
||||||
|
else if (pc->is_playing())
|
||||||
|
httpc::pb_state = FOO_PLAYING;
|
||||||
|
else
|
||||||
|
httpc::pb_state = FOO_STOPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_playlist_view()
|
||||||
|
{
|
||||||
|
if (/*cfg.main.retrieve_playlist*/ tcfg.get().playlist_items_per_page == 0 || !httpc::control::is_active() || tcfg.get_count() <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
active_playlist_is_undo_available = static_api_ptr_t<playlist_manager>()->activeplaylist_is_undo_available();
|
||||||
|
active_playlist_is_redo_available = static_api_ptr_t<playlist_manager>()->activeplaylist_is_redo_available();
|
||||||
|
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
|
||||||
|
size_t apl_count = plm->activeplaylist_get_item_count();
|
||||||
|
|
||||||
|
if (apl_count)
|
||||||
|
{
|
||||||
|
pfc::string8_fast_aggressive track_title;
|
||||||
|
|
||||||
|
t_size item_start = (httpc::playlist_page-1) * tcfg.get().playlist_items_per_page;
|
||||||
|
t_size item_end = (httpc::playlist_page-1) * tcfg.get().playlist_items_per_page + tcfg.get().playlist_items_per_page - 1;
|
||||||
|
|
||||||
|
if (item_end > apl_count - 1)
|
||||||
|
item_end = apl_count - 1;
|
||||||
|
|
||||||
|
metadb_handle_list pl;
|
||||||
|
bit_array_range pl_mask(item_start, item_end-item_start+1);
|
||||||
|
plm->activeplaylist_get_items(pl, pl_mask);
|
||||||
|
|
||||||
|
size_t pl_count = pl.get_count();
|
||||||
|
|
||||||
|
playlist_view.set_size(pl_count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pl_count; ++i)
|
||||||
|
pl[i]->format_title(NULL, playlist_view[i].title, script_playlist_row, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
playlist_view.set_size(0);
|
||||||
|
|
||||||
|
playlist_item_focused = plm->playlist_get_focus_item(plm->get_active_playlist());
|
||||||
|
|
||||||
|
should_update_playlist = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_playlist_total_time()
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
|
||||||
|
metadb_handle_list pl;
|
||||||
|
plm->activeplaylist_get_all_items(pl);
|
||||||
|
|
||||||
|
pfc::format_time_ex time_fmt( metadb_handle_list_helper::calc_total_duration(pl) , 0);
|
||||||
|
playlist_total_time = time_fmt;
|
||||||
|
|
||||||
|
should_update_playlist_total_time = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_playback_queue()
|
||||||
|
{
|
||||||
|
if (tcfg.get().playlist_items_per_page == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
|
||||||
|
size_t pl_count = plm->activeplaylist_get_item_count();
|
||||||
|
size_t pl_count2 = playlist_view.get_count();
|
||||||
|
|
||||||
|
queue_total_time = "";
|
||||||
|
|
||||||
|
pfc::list_t<t_playback_queue_item> queue;
|
||||||
|
plm->queue_get_contents(queue);
|
||||||
|
|
||||||
|
if (pl_count)
|
||||||
|
{
|
||||||
|
t_size item_start = (httpc::playlist_page-1) * tcfg.get().playlist_items_per_page;
|
||||||
|
t_size item_end = (httpc::playlist_page-1) * tcfg.get().playlist_items_per_page + tcfg.get().playlist_items_per_page;
|
||||||
|
|
||||||
|
for (t_size i = item_start, j = 0; i < pl_count && i < item_end && j < pl_count2; ++i, ++j)
|
||||||
|
{
|
||||||
|
playlist_entry &ple = playlist_view[j];
|
||||||
|
ple.numinqueue.reset();
|
||||||
|
ple.title_queue.reset();
|
||||||
|
ple.inqueue = false;
|
||||||
|
|
||||||
|
t_size l = queue.get_count();
|
||||||
|
for (t_size y = 0; y < l; ++y)
|
||||||
|
{
|
||||||
|
t_playback_queue_item &qi = queue[y];
|
||||||
|
|
||||||
|
if (qi.m_playlist == active_playlist
|
||||||
|
&& qi.m_item == i
|
||||||
|
&& qi.m_handle == plm->activeplaylist_get_item_handle(i))
|
||||||
|
{
|
||||||
|
plm->playlist_item_format_title(active_playlist,qi.m_item,NULL,ple.title_queue,script_playlist_row,NULL,playback_control::display_level_all);
|
||||||
|
|
||||||
|
ple.inqueue = true;
|
||||||
|
|
||||||
|
if (ple.numinqueue.get_length())
|
||||||
|
ple.numinqueue << " " << y+1;
|
||||||
|
else
|
||||||
|
ple.numinqueue << y+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double queue_pb_time = 0;
|
||||||
|
|
||||||
|
t_size l = queue.get_count();
|
||||||
|
for (t_size y = 0; y < l; ++y)
|
||||||
|
queue_pb_time+=queue[y].m_handle->get_length();
|
||||||
|
|
||||||
|
pfc::format_time_ex time_fmt(queue_pb_time, 0);
|
||||||
|
queue_total_time = time_fmt.operator const char *();
|
||||||
|
}
|
||||||
|
|
||||||
|
should_update_queue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh_playlist_list()
|
||||||
|
{
|
||||||
|
static_api_ptr_t<playlist_manager> plm;
|
||||||
|
|
||||||
|
pfc::string8 pl_str;
|
||||||
|
playlist_info pl_i;
|
||||||
|
|
||||||
|
playlist_list.remove_all();
|
||||||
|
|
||||||
|
t_size l = plm->get_playlist_count();
|
||||||
|
|
||||||
|
for (t_size i = 0; i < l; ++i)
|
||||||
|
if (plm->playlist_get_name(i, pl_str))
|
||||||
|
{
|
||||||
|
pl_i.name = xml_friendly_string(pl_str);
|
||||||
|
pl_i.items = plm->playlist_get_item_count(i);
|
||||||
|
|
||||||
|
playlist_list.add_item(pl_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
active_playlist = plm->get_active_playlist();
|
||||||
|
|
||||||
|
should_update_playlists_list = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t is_extension_registered(const char *path)
|
||||||
|
{
|
||||||
|
size_t path_len = strlen(path);
|
||||||
|
|
||||||
|
if (path_len <= 4)
|
||||||
|
return pfc::infinite_size;
|
||||||
|
|
||||||
|
if (path[path_len-1] == '\\')
|
||||||
|
return pfc::infinite_size;
|
||||||
|
|
||||||
|
if (strstr(path, "cdda:/") == path)
|
||||||
|
for (size_t j = 0; j < httpc::extensions.get_count(); ++j)
|
||||||
|
if (_stricmp(httpc::extensions[j], "cda") == 0)
|
||||||
|
return j;
|
||||||
|
|
||||||
|
t_size l = httpc::extensions.get_count();
|
||||||
|
for (size_t j = 0; j < l; ++j)
|
||||||
|
{
|
||||||
|
size_t ext_len = strlen(httpc::extensions[j]);
|
||||||
|
|
||||||
|
if (ext_len > 0 && path_len > ext_len)
|
||||||
|
{
|
||||||
|
if (_stricmp( (path + path_len - ext_len), httpc::extensions[j]) == 0)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfc::infinite_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_protocol_registered(const char *path)
|
||||||
|
{
|
||||||
|
// hardcoding protocols since there seems to be no way of interrogating fb2k for supported protocols list
|
||||||
|
// protocol should be lowercase so no case insensitive comparision is required
|
||||||
|
|
||||||
|
if (strstr(path, "http://") == path)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_registered_extensions()
|
||||||
|
{
|
||||||
|
extensions.remove_all();
|
||||||
|
extension_names.remove_all();
|
||||||
|
|
||||||
|
{
|
||||||
|
pfc::string8_fastalloc mask;
|
||||||
|
pfc::string8_fastalloc name;
|
||||||
|
|
||||||
|
pfc::list_t<pfc::string8> ignored_extensions;
|
||||||
|
pfc::splitStringSimple_toList(ignored_extensions, '|', cfg.main.ignored_formats);
|
||||||
|
|
||||||
|
for (t_size i = 0; i < ignored_extensions.get_count(); ++i)
|
||||||
|
ignored_extensions[i] = trim(ignored_extensions[i]);
|
||||||
|
|
||||||
|
service_enum_t<input_file_type> e;
|
||||||
|
service_ptr_t<input_file_type> ptr;
|
||||||
|
if (e.first(ptr)) do {
|
||||||
|
unsigned n,m = ptr->get_count();
|
||||||
|
for(n=0;n<m;n++)
|
||||||
|
{
|
||||||
|
mask.reset();
|
||||||
|
name.reset();
|
||||||
|
if (ptr->get_mask(n,mask) && ptr->get_name(n,name))
|
||||||
|
{
|
||||||
|
if (!strchr(mask,'|'))
|
||||||
|
{
|
||||||
|
pfc::string8_fastalloc extension;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while(i < mask.get_length())
|
||||||
|
{
|
||||||
|
if (mask[i] != '*' && mask[i] != '.' && mask[i] != ';')
|
||||||
|
extension.add_char(mask[i]);
|
||||||
|
|
||||||
|
if (mask[i] == ';' || i == mask.get_length() - 1)
|
||||||
|
{
|
||||||
|
bool ignored = false;
|
||||||
|
|
||||||
|
for (t_size j = 0; j < ignored_extensions.get_count(); ++j)
|
||||||
|
if (pfc::stringCompareCaseInsensitive(extension, ignored_extensions[j]) == 0)
|
||||||
|
{
|
||||||
|
ignored = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignored)
|
||||||
|
{
|
||||||
|
extensions.add_item(pfc::string_simple(extension));
|
||||||
|
extension_names.add_item(pfc::string_simple(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(e.next(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
pfc::list_t<pfc::string8> extra_extensions;
|
||||||
|
pfc::splitStringSimple_toList(extra_extensions, '|', cfg.main.extra_formats);
|
||||||
|
pfc::string8 ext;
|
||||||
|
for (t_size i = 0; i < extra_extensions.get_count(); ++i)
|
||||||
|
{
|
||||||
|
ext = trim(extra_extensions[i]);
|
||||||
|
|
||||||
|
if (ext.get_length())
|
||||||
|
{
|
||||||
|
extensions.add_item(ext);
|
||||||
|
extension_names.add_item("Extra format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service_enum_t<playlist_loader> e;
|
||||||
|
service_ptr_t<playlist_loader> ptr;
|
||||||
|
if (e.first(ptr)) do
|
||||||
|
{
|
||||||
|
extensions.add_item(ptr->get_extension());
|
||||||
|
extension_names.add_item("Playlist");
|
||||||
|
} while(e.next(ptr));
|
||||||
|
|
||||||
|
// build restrict mask
|
||||||
|
for (size_t i = 0; i < extensions.get_count(); ++i)
|
||||||
|
{
|
||||||
|
restrict_mask << "*." << extensions[i];
|
||||||
|
if (i != extensions.get_count() - 1 )
|
||||||
|
restrict_mask << ";";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void choose_srv_home_dir()
|
||||||
|
{
|
||||||
|
pfc::string8 server_root_tmp = cfg.main.server_root;
|
||||||
|
remove_trailing_path_separator(server_root_tmp);
|
||||||
|
httpc::srv_home_dir = (server_root_tmp.get_length() > 0 ? server_root_tmp : httpc::fb2k_profile_path);
|
||||||
|
|
||||||
|
for (t_size i = 0; i < tcfg.get_count(); ++i)
|
||||||
|
if (tcfg.get(i).root.get_length())
|
||||||
|
tcfg.get(i).local_path = pfc::string_formatter() << httpc::srv_home_dir << "\\" << tcfg.get(i).root << "\\";
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void build_restrict_to_path_list()
|
||||||
|
{
|
||||||
|
cfg.restrict_to_path_list.remove_all();
|
||||||
|
get_list(cfg.main.restrict_to_path, cfg.restrict_to_path_list, '|', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void control_credentials_auth_hash_update()
|
||||||
|
{
|
||||||
|
pfc::string8 encode_str;
|
||||||
|
encode_str << cfg.main.control_credentials_username << ":" << cfg.main.control_credentials_password;
|
||||||
|
size_t buf_len = static_cast<int>(sizeof(char) * encode_str.length() * 1.4)+16;
|
||||||
|
char *buf = new char[buf_len];
|
||||||
|
memset(buf, 0, buf_len);
|
||||||
|
|
||||||
|
WebServerBaseClass::base64encode(const_cast<char *>(encode_str.operator const char *()), buf);
|
||||||
|
|
||||||
|
control_credentials_auth_hash = pfc::string_formatter() << "Basic " << buf;
|
||||||
|
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void titleformat_compile()
|
||||||
|
{
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(script_playlist_row,tcfg.get().playlist_row);
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(script_helper1,tcfg.get().helper1);
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(script_helper2,tcfg.get().helper2);
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(script_helper3,tcfg.get().helper3);
|
||||||
|
static_api_ptr_t<titleformat_compiler>()->compile_safe(script_albumart_lookup,tcfg.get().albumart);
|
||||||
|
}
|
||||||
|
}
|
||||||
136
foo_httpcontrol/src/state.h
Executable file
@@ -0,0 +1,136 @@
|
|||||||
|
#ifndef __httpcontrol_state_H__
|
||||||
|
#define __httpcontrol_state_H__
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
|
|
||||||
|
#define PLAYLIST_ITEMS_PER_PAGE_MAX 16384
|
||||||
|
|
||||||
|
extern bool foo_httpcontrol_isactive();
|
||||||
|
|
||||||
|
namespace httpc {
|
||||||
|
extern CRITICAL_SECTION cs;
|
||||||
|
|
||||||
|
extern service_ptr_t<titleformat_object> script_playlist_row;
|
||||||
|
extern service_ptr_t<titleformat_object> script_helper1;
|
||||||
|
extern service_ptr_t<titleformat_object> script_helper2;
|
||||||
|
extern service_ptr_t<titleformat_object> script_helper3;
|
||||||
|
extern service_ptr_t<titleformat_object> script_albumart_lookup;
|
||||||
|
|
||||||
|
enum foo_state_enum { FOO_STOPPED = 0, FOO_PLAYING = 1, FOO_PAUSED = 2};
|
||||||
|
enum foo_last_action { FLC_START = 0, FLC_ENQUEUE = 1, FLC_DEQUEUE = 2, FLC_FOCUS = 3, FLC_REMOVE = 4, FLC_SELECT = 5, FLC_SHIFT = 6};
|
||||||
|
|
||||||
|
struct playlist_entry
|
||||||
|
{
|
||||||
|
bool inqueue;
|
||||||
|
pfc::string8 numinqueue;
|
||||||
|
pfc::string8 title;
|
||||||
|
pfc::string8 title_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct playlist_info
|
||||||
|
{
|
||||||
|
pfc::string8 name; // playlist name
|
||||||
|
size_t items; // playlist item count
|
||||||
|
};
|
||||||
|
|
||||||
|
enum foo_state_changed {
|
||||||
|
FSC_NONE = 0, // nothing changed
|
||||||
|
FSC_PLAYBACK = 1, // playback state (start, stop, seek, next track etc)
|
||||||
|
FSC_PLAYLISTS = 2, // playlists state (names, order, removal, addition etc)
|
||||||
|
FSC_PLAYLIST = 4, // playlist content (items addition, removal, modify, reorder etc)
|
||||||
|
FSC_VOLUME = 8, // volume
|
||||||
|
FSC_PLAYBACK_ORDER = 16 // playback order
|
||||||
|
};
|
||||||
|
|
||||||
|
enum albumart_status {
|
||||||
|
AS_NO_INFO = 0, // no playing item so no albumart info
|
||||||
|
AS_FILE = 1, // albumart in file
|
||||||
|
AS_MEMORY = 2, // albumart in memory
|
||||||
|
AS_NOT_FOUND = 4, // albumart not found anywhere
|
||||||
|
};
|
||||||
|
|
||||||
|
extern bool enqueueing;
|
||||||
|
|
||||||
|
extern size_t pb_state;
|
||||||
|
extern size_t last_action;
|
||||||
|
extern size_t state_changed;
|
||||||
|
extern float volume;
|
||||||
|
extern pfc::string8 pb_helper1;
|
||||||
|
extern pfc::string8 pb_helper2;
|
||||||
|
extern pfc::string8 pb_helper3;
|
||||||
|
extern pfc::string8 pb_helper1x;
|
||||||
|
extern pfc::string8 pb_helper2x;
|
||||||
|
extern pfc::string8 pb_helper3x;
|
||||||
|
extern pfc::string8 pb_albumart_path;
|
||||||
|
extern pfc::string8 pb_albumart_path_crc32;
|
||||||
|
extern pfc::string8 pb_albumart_lookup;
|
||||||
|
extern pfc::string8 pb_albumart_embedded_file;
|
||||||
|
extern albumart_status pb_albumart_status;
|
||||||
|
extern album_art_data_ptr pb_albumart_embedded_ptr;
|
||||||
|
extern size_t pb_item;
|
||||||
|
extern double pb_length;
|
||||||
|
extern double pb_time;
|
||||||
|
extern size_t pb_playlist;
|
||||||
|
extern size_t pb_playlist_item_count;
|
||||||
|
extern size_t pb_item_prev;
|
||||||
|
extern size_t pb_playlist_prev;
|
||||||
|
extern size_t playlist_item_focused;
|
||||||
|
extern size_t playlist_page;
|
||||||
|
extern size_t active_playlist;
|
||||||
|
extern size_t active_playlist_item_count;
|
||||||
|
extern size_t query_playlist;
|
||||||
|
extern bool playlist_page_switched;
|
||||||
|
extern bool should_focus_on_playing;
|
||||||
|
extern bool should_update_playlist;
|
||||||
|
extern bool should_update_playlist_total_time;
|
||||||
|
extern bool should_update_playlists_list;
|
||||||
|
extern bool should_update_queue;
|
||||||
|
extern pfc::list_t<playlist_entry,pfc::alloc_fast_aggressive> playlist_view;
|
||||||
|
extern pfc::string_simple playlist_total_time;
|
||||||
|
extern pfc::string_simple queue_total_time;
|
||||||
|
extern bool sac;
|
||||||
|
extern bool reset_sac;
|
||||||
|
extern bool active_playlist_is_undo_available;
|
||||||
|
extern bool active_playlist_is_redo_available;
|
||||||
|
extern pfc::string_simple control_credentials_auth_hash;
|
||||||
|
extern pfc::list_t<pfc::string_simple> extensions;
|
||||||
|
extern pfc::list_t<pfc::string_simple> extension_names;
|
||||||
|
extern pfc::string8 restrict_mask;
|
||||||
|
extern pfc::list_t<playlist_info> playlist_list;
|
||||||
|
extern pfc::string8 fb2k_profile_path;
|
||||||
|
extern pfc::string8 fb2k_path;
|
||||||
|
extern pfc::string8 srv_home_dir;
|
||||||
|
extern pfc::string_simple autoplaylist_request;
|
||||||
|
|
||||||
|
extern pfc::hires_timer timer;
|
||||||
|
|
||||||
|
extern void enqueue(pfc::list_t<t_size> &list);
|
||||||
|
extern void dequeue(pfc::list_t<t_size> &list);
|
||||||
|
extern void empty_info();
|
||||||
|
|
||||||
|
extern void refresh_volume(float p_volume = 0);
|
||||||
|
extern void set_volume(t_size pecent);
|
||||||
|
extern byte get_volume();
|
||||||
|
extern void retrieve_albumart(metadb_handle_ptr pb_item_ptr);
|
||||||
|
extern void refresh_playing_info();
|
||||||
|
extern void refresh_playlist_view();
|
||||||
|
extern void refresh_playlist_total_time();
|
||||||
|
extern void refresh_playback_queue();
|
||||||
|
extern void refresh_playlist_list();
|
||||||
|
|
||||||
|
extern void update_previouslyplayed();
|
||||||
|
extern void empty_previouslyplayed();
|
||||||
|
|
||||||
|
extern void get_registered_extensions();
|
||||||
|
extern size_t is_extension_registered(const char *path); // infininte if not registered, list index elsewere
|
||||||
|
extern bool is_protocol_registered(const char *path);
|
||||||
|
|
||||||
|
extern void choose_srv_home_dir();
|
||||||
|
extern void build_restrict_to_path_list();
|
||||||
|
|
||||||
|
extern void control_credentials_auth_hash_update();
|
||||||
|
|
||||||
|
extern void titleformat_compile();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*__httpcontrol_state_H__*/
|
||||||
8
foo_httpcontrol/src/stdafx.cpp
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
// stdafx.cpp : source file that includes just the standard includes
|
||||||
|
// browsefiles.pch will be the pre-compiled header
|
||||||
|
// stdafx.obj will contain the pre-compiled type information
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
|
||||||
|
// TODO: reference any additional headers you need in STDAFX.H
|
||||||
|
// and not in this file
|
||||||
20
foo_httpcontrol/src/stdafx.h
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
// stdafx.h : include file for standard system include files,
|
||||||
|
// or project specific include files that are used frequently, but
|
||||||
|
// are changed infrequently
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
|
|
||||||
|
#include <Winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include "../lib/foobar2000/ATLHelpers/ATLHelpers.h"
|
||||||
|
#include "../lib/foobar2000/SDK/foobar2000.h"
|
||||||
|
#include "../lib/jnetlib/jnetlib.h"
|
||||||
|
#include "../lib/jnetlib/webserver.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "../lib/zlib/zlib.h"
|
||||||
|
|
||||||
|
// TODO: reference additional headers your program requires here
|
||||||
1004
foo_httpcontrol/src/ui.cpp
Executable file
98
foo_httpcontrol/src/ui.h
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
#ifndef __foo_ui_H__
|
||||||
|
#define __foo_ui_H__
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
|
|
||||||
|
#include "facets.h"
|
||||||
|
#include "browsefiles.h"
|
||||||
|
|
||||||
|
namespace httpc
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
typedef pfc::map_t<const char *, void (* )(pfc::string_base &), pfc::comparator_strcmp> funcs_map;
|
||||||
|
|
||||||
|
extern pfc::string8_fast_aggressive tpl;
|
||||||
|
extern pfc::string8_fast_aggressive *result_ptr; // playlist renderers hack to avoid data copying around
|
||||||
|
extern pfc::string8 browse_path;
|
||||||
|
|
||||||
|
static const size_t cfg_playlist_pages_leftright = 4;
|
||||||
|
|
||||||
|
extern void read_file(const char *path, pfc::string_base &buffer, pfc::string_base &request);
|
||||||
|
|
||||||
|
extern void generate_html_response(pfc::string_base &buffer, pfc::string_base &header, pfc::string_base &body);
|
||||||
|
|
||||||
|
extern void set_buffer_from_file(pfc::string_base &tpl_file, t_size template_id);
|
||||||
|
extern void set_buffer_from_string(pfc::string_base &str);
|
||||||
|
|
||||||
|
extern void parse_buffer_controls(pfc::string8_fast_aggressive &res, pfc::hires_timer &timer);
|
||||||
|
extern void parse_buffer_browser(pfc::string_base &path, pfc::string8_fast_aggressive &res, pfc::hires_timer &timer); // parse file browser template
|
||||||
|
|
||||||
|
void generate_installed_templates_list(pfc::string_base &response);
|
||||||
|
|
||||||
|
namespace gen {
|
||||||
|
extern funcs_map funcs;
|
||||||
|
extern void (*func )(pfc::string_base &);
|
||||||
|
|
||||||
|
extern void gen_func_table();
|
||||||
|
extern void is_enqueueing(pfc::string_base &result);
|
||||||
|
extern void is_playing(pfc::string_base &result);
|
||||||
|
extern void is_paused(pfc::string_base &result);
|
||||||
|
extern void item_playing_pos(pfc::string_base &result);
|
||||||
|
extern void last_action(pfc::string_base &result);
|
||||||
|
extern void item_playing_len(pfc::string_base &result);
|
||||||
|
extern void playlist_item_playing(pfc::string_base &result);
|
||||||
|
extern void playlist_items_count(pfc::string_base &result);
|
||||||
|
extern void playlist_playing(pfc::string_base &result);
|
||||||
|
extern void playlist_playing_items_count(pfc::string_base &result);
|
||||||
|
extern void state_change(pfc::string_base &result);
|
||||||
|
extern void search_request(pfc::string_base &result);
|
||||||
|
extern void volume_option(pfc::string_base &result);
|
||||||
|
extern void volume(pfc::string_base &result);
|
||||||
|
extern void volume_db(pfc::string_base &result);
|
||||||
|
extern void playback_order_option(pfc::string_base &result);
|
||||||
|
extern void playback_order(pfc::string_base &result);
|
||||||
|
extern void helper1(pfc::string_base &result);
|
||||||
|
extern void helper2(pfc::string_base &result);
|
||||||
|
extern void helper3(pfc::string_base &result);
|
||||||
|
extern void helper1x(pfc::string_base &result);
|
||||||
|
extern void helper2x(pfc::string_base &result);
|
||||||
|
extern void helper3x(pfc::string_base &result);
|
||||||
|
extern void query_option(pfc::string_base &result);
|
||||||
|
extern void query_js(pfc::string_base &result);
|
||||||
|
extern void query_info(pfc::string_base &result);
|
||||||
|
extern void query_info_js(pfc::string_base &result);
|
||||||
|
extern void sac(pfc::string_base &result);
|
||||||
|
extern void saq(pfc::string_base &result);
|
||||||
|
extern void auto_refresh(pfc::string_base &result);
|
||||||
|
extern void albumart(pfc::string_base &result);
|
||||||
|
extern void playlists_option(pfc::string_base &result);
|
||||||
|
extern void playlists_js(pfc::string_base &result);
|
||||||
|
extern void playlist_active(pfc::string_base &result);
|
||||||
|
extern void playlist_total_time(pfc::string_base &result);
|
||||||
|
extern void queue_total_time(pfc::string_base &result);
|
||||||
|
extern void pgt(pfc::string_base &result);
|
||||||
|
extern void playlist_pages(pfc::string_base &result);
|
||||||
|
extern void playlist_pages_select(pfc::string_base &result);
|
||||||
|
extern void playlist_page(pfc::string_base &result);
|
||||||
|
extern void playlist_pages_count(pfc::string_base &result);
|
||||||
|
extern void playlist_item_focused(pfc::string_base &result);
|
||||||
|
extern void playlist_item_prev_played(pfc::string_base &result);
|
||||||
|
extern void playlist_js(pfc::string_base &result);
|
||||||
|
extern void playlist(pfc::string_base &result);
|
||||||
|
extern void playlist_is_undo_available(pfc::string_base &result);
|
||||||
|
extern void playlist_is_redo_available(pfc::string_base &result);
|
||||||
|
extern void path(pfc::string_base &result);
|
||||||
|
extern void path_js(pfc::string_base &result);
|
||||||
|
extern void path_parent(pfc::string_base &result);
|
||||||
|
extern void browser(pfc::string_base &result);
|
||||||
|
extern void browser_js(pfc::string_base &result);
|
||||||
|
extern void playlist_items_per_page(pfc::string_base &result);
|
||||||
|
extern void browser_format_row(unsigned int count, foo_browsefiles::entry_data &entry, pfc::string8_fast_aggressive &result);
|
||||||
|
extern void browser_format_row_js(unsigned int count, foo_browsefiles::entry_data &entry, pfc::string8_fast_aggressive &result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*__foo_ui_H__*/
|
||||||
324
foo_httpcontrol/src/utils.cpp
Executable file
@@ -0,0 +1,324 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
void foo_info(const char *msg)
|
||||||
|
{
|
||||||
|
if (cfg.main.log_access)
|
||||||
|
console::formatter() << foo_name << ": " << msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
void foo_error(const char *msg)
|
||||||
|
{
|
||||||
|
console::formatter() << foo_name << " error: " << msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
void str_to_bitarray(pfc::string_base &str, bit_array_bittable &arr) // helper string to bit_array
|
||||||
|
{
|
||||||
|
pfc::string8 number;
|
||||||
|
|
||||||
|
unsigned int size = 0;
|
||||||
|
|
||||||
|
t_size l = str.length();
|
||||||
|
for (t_size i = 0; i < l; ++i)
|
||||||
|
{
|
||||||
|
if (isdigit(str[i]))
|
||||||
|
number.add_char(str[i]);
|
||||||
|
else
|
||||||
|
if (number.get_length() > 0)
|
||||||
|
{
|
||||||
|
unsigned int item = atoi(number.get_ptr());
|
||||||
|
|
||||||
|
if (item + 1 > size)
|
||||||
|
{
|
||||||
|
size = item + 1;
|
||||||
|
arr.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.set(item, true);
|
||||||
|
|
||||||
|
number.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number.get_length() > 0)
|
||||||
|
{
|
||||||
|
unsigned int item = atoi(number.get_ptr());
|
||||||
|
|
||||||
|
if (item + 1 > size)
|
||||||
|
{
|
||||||
|
arr.resize(item + 1);
|
||||||
|
size = item + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.set(item, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void str_to_list(pfc::string_base &str, pfc::list_t<t_size> &list)
|
||||||
|
{
|
||||||
|
pfc::string8 number;
|
||||||
|
|
||||||
|
list.remove_all();
|
||||||
|
|
||||||
|
t_size l = str.length();
|
||||||
|
|
||||||
|
for (t_size i = 0; i < l; ++i)
|
||||||
|
{
|
||||||
|
if (isdigit(str[i]))
|
||||||
|
number.add_char(str[i]);
|
||||||
|
else
|
||||||
|
if (number.get_length() > 0)
|
||||||
|
{
|
||||||
|
list.add_item(atoi(number.get_ptr()));
|
||||||
|
number.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number.get_length() > 0)
|
||||||
|
list.add_item(atoi(number.get_ptr()));
|
||||||
|
};
|
||||||
|
|
||||||
|
void url_decode(pfc::string_base &in, pfc::string_base &out)
|
||||||
|
{
|
||||||
|
t_size maxlen = in.length();;
|
||||||
|
char *buf = new char[maxlen + 2];
|
||||||
|
ZeroMemory(buf, maxlen + 2);
|
||||||
|
WebServerBaseClass::url_decode(const_cast<char *>(in.toString()), buf, maxlen+1);
|
||||||
|
out = buf;
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void url_encode(const char *in, pfc::string_base &out)
|
||||||
|
{
|
||||||
|
t_size maxlen = strlen(in)*4;
|
||||||
|
char *buf = new char[maxlen + 2];
|
||||||
|
ZeroMemory(buf, maxlen + 2);
|
||||||
|
WebServerBaseClass::url_encode(const_cast<char *>(in), buf, maxlen+1);
|
||||||
|
out = buf;
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfc::string8 trim(pfc::string8 &str)
|
||||||
|
{
|
||||||
|
pfc::string8 out = str;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while (i < out.length() && out[i] == ' ')
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if (i == out.length())
|
||||||
|
return pfc::string8("");
|
||||||
|
|
||||||
|
out.remove_chars(0, i);
|
||||||
|
|
||||||
|
i = out.length() - 1;
|
||||||
|
|
||||||
|
while (i > 0 && out[i] == ' ')
|
||||||
|
--i;
|
||||||
|
|
||||||
|
if (i < out.length())
|
||||||
|
out.truncate(i+1);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_list(pfc::string8 &str, pfc::list_t<pfc::string8> &list, char separator, bool fix_dir)
|
||||||
|
{
|
||||||
|
if (str.length() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
pfc::string8 p_str;
|
||||||
|
|
||||||
|
while (i < str.length())
|
||||||
|
{
|
||||||
|
if (str[i] == separator)
|
||||||
|
{
|
||||||
|
p_str = trim(p_str);
|
||||||
|
if (_stricmp(p_str.operator const char *(), "") != 0)
|
||||||
|
{
|
||||||
|
if (fix_dir && p_str[p_str.get_length() - 1] != '\\')
|
||||||
|
p_str.add_char('\\');
|
||||||
|
|
||||||
|
if (p_str != "")
|
||||||
|
list.add_item(p_str);
|
||||||
|
}
|
||||||
|
p_str.reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p_str.add_byte(str[i]);
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_str.length() > 0)
|
||||||
|
{
|
||||||
|
p_str = trim(p_str);
|
||||||
|
if (_stricmp(p_str.operator const char *(), "") != 0)
|
||||||
|
{
|
||||||
|
if (fix_dir && p_str[p_str.get_length() - 1] != '\\')
|
||||||
|
p_str.add_char('\\');
|
||||||
|
if (p_str != "")
|
||||||
|
list.add_item(p_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long calcCRC(const char *data, t_size data_len)
|
||||||
|
{
|
||||||
|
long crc;
|
||||||
|
long q;
|
||||||
|
byte c;
|
||||||
|
crc = 0;
|
||||||
|
for (size_t i=0; i< data_len; i++)
|
||||||
|
{
|
||||||
|
c = data[i];
|
||||||
|
q = (crc ^ c) & 0x0f;
|
||||||
|
crc = (crc >> 4) ^ (q * 0x1081);
|
||||||
|
q = (crc ^ (c >> 4)) & 0xf;
|
||||||
|
crc = (crc >> 4) ^ (q * 0x1081);
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfc::string8 xml_friendly_string(pfc::string_base &str)
|
||||||
|
{
|
||||||
|
pfc::string8 out;
|
||||||
|
t_uint32 c;
|
||||||
|
|
||||||
|
size_t l = str.get_length();
|
||||||
|
for (size_t i = 0; i < l; ++i)
|
||||||
|
{
|
||||||
|
c = str[i];
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '&':
|
||||||
|
out += "&"; break;
|
||||||
|
case '<':
|
||||||
|
out += "<"; break;
|
||||||
|
case'>':
|
||||||
|
out += ">"; break;
|
||||||
|
case '"':
|
||||||
|
out += """; break;
|
||||||
|
case '\'':
|
||||||
|
out += "'"; break;
|
||||||
|
case '\\':
|
||||||
|
out += "\"; break;
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
out.add_char('_'); break;
|
||||||
|
default:
|
||||||
|
out.add_byte(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_fileexists(pfc::string8 &fullpathfile, DWORD &content_length, pfc::string8 &lastwritetime_str)
|
||||||
|
{
|
||||||
|
HANDLE inFile;
|
||||||
|
|
||||||
|
pfc::stringcvt::string_wide_from_utf8 path_w(fullpathfile);
|
||||||
|
inFile = CreateFileW(path_w, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
|
||||||
|
if (inFile == INVALID_HANDLE_VALUE)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FILETIME lastwritetime;
|
||||||
|
content_length = GetFileSize(inFile, &content_length);
|
||||||
|
GetFileTime(inFile, NULL, NULL, &lastwritetime);
|
||||||
|
format_time(&lastwritetime, lastwritetime_str, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(inFile);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void format_time(LPFILETIME filetime, pfc::string8 &out, byte format)
|
||||||
|
{
|
||||||
|
static const char *wMonth[] = { "Jan" /* 1 */, "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||||
|
static const char *wDayOfWeek[] = { "Sun" /* 0 */, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||||
|
|
||||||
|
SYSTEMTIME stUTC, stLocal;
|
||||||
|
FileTimeToSystemTime(filetime, &stUTC);
|
||||||
|
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
if (format == 0)
|
||||||
|
{
|
||||||
|
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
|
||||||
|
|
||||||
|
sprintf_s(buf, "%02d.%02d.%d %02d:%02d",
|
||||||
|
stLocal.wDay, stLocal.wMonth, stLocal.wYear,
|
||||||
|
stLocal.wHour, stLocal.wMinute);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (format == 1)
|
||||||
|
sprintf_s(buf, "%s, %d %s %d %02d:%02d:%02d GMT",
|
||||||
|
wDayOfWeek[stUTC.wDayOfWeek], stUTC.wDay, wMonth[stUTC.wMonth - 1], stUTC.wYear, stUTC.wHour, stUTC.wMinute, stUTC.wSecond );
|
||||||
|
|
||||||
|
out = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_path_separator_my(unsigned c)
|
||||||
|
{
|
||||||
|
return c=='\\' || c=='/';
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_trailing_path_separator(pfc::string8 &path)
|
||||||
|
{
|
||||||
|
t_size i = path.get_length();
|
||||||
|
|
||||||
|
while (i > 0 && is_path_separator_my(path[i-1]))
|
||||||
|
--i;
|
||||||
|
|
||||||
|
path.truncate(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
pfc::string8 string8_safe(const char *p_string)
|
||||||
|
{
|
||||||
|
if (p_string)
|
||||||
|
return p_string;
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_ini_key(const char *key, pfc::string_base &value, const wchar_t *path)
|
||||||
|
{
|
||||||
|
static const DWORD nSize = 16384;
|
||||||
|
wchar_t buf[nSize];
|
||||||
|
DWORD bytesread;
|
||||||
|
|
||||||
|
value.reset();
|
||||||
|
|
||||||
|
bytesread = GetPrivateProfileString(_T("foo_httpcontrol"), pfc::stringcvt::string_wide_from_utf8(key),_T(""), buf, nSize, path);
|
||||||
|
|
||||||
|
if (bytesread > 0)
|
||||||
|
value = trim(pfc::string8(pfc::stringcvt::string_utf8_from_wide(buf)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* foobar2000 SDK / metadb_handle_list.cpp / wchar_t * makeSortString(const char * in) */
|
||||||
|
wchar_t * utf8_to_wide(const char * in)
|
||||||
|
{
|
||||||
|
wchar_t * out = new wchar_t[pfc::stringcvt::estimate_utf8_to_wide(in) + 1];
|
||||||
|
out[0] = ' ';//StrCmpLogicalW bug workaround.
|
||||||
|
pfc::stringcvt::convert_utf8_to_wide_unchecked(out + 1, in);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
int compare_natural_utf8(const char *p1, const char *p2)
|
||||||
|
{
|
||||||
|
wchar_t *wp1 = utf8_to_wide(p1);
|
||||||
|
wchar_t *wp2 = utf8_to_wide(p2);
|
||||||
|
|
||||||
|
int result = StrCmpLogicalW(wp1, wp2);
|
||||||
|
|
||||||
|
delete[] wp1;
|
||||||
|
delete[] wp2;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
38
foo_httpcontrol/src/utils.h
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __FOO_UTILS_H__
|
||||||
|
#define __FOO_UTILS_H__
|
||||||
|
|
||||||
|
void foo_info(const char *msg); // push verbose info to console if logging is enabled
|
||||||
|
void foo_error(const char *msg); // push error to console
|
||||||
|
|
||||||
|
void str_to_bitarray(pfc::string_base &str, bit_array_bittable &arr); // convert c-style string to pfc::bitarray
|
||||||
|
void str_to_list(pfc::string_base &str, pfc::list_t<t_size> &list); // convert c-style string to pfc::list
|
||||||
|
|
||||||
|
void url_decode(pfc::string_base &in, pfc::string_base &out); // url-decode c-style string #2
|
||||||
|
void url_encode(const char *in, pfc::string_base &out);
|
||||||
|
|
||||||
|
pfc::string8 trim(pfc::string8 &str);
|
||||||
|
void get_list(pfc::string8 &str, pfc::list_t<pfc::string8> &list, char separator, bool fix_dir);
|
||||||
|
|
||||||
|
long calcCRC(const char *data, t_size data_len);
|
||||||
|
|
||||||
|
pfc::string8 xml_friendly_string(pfc::string_base &str);
|
||||||
|
|
||||||
|
bool is_fileexists(pfc::string8 &fullpathfile, DWORD &content_length, pfc::string8 &lastwritetime_str);
|
||||||
|
|
||||||
|
void format_time(LPFILETIME filetime, pfc::string8 &out, byte format);
|
||||||
|
|
||||||
|
bool is_path_separator_my(unsigned c);
|
||||||
|
|
||||||
|
void remove_trailing_path_separator(pfc::string8 &path);
|
||||||
|
|
||||||
|
pfc::string8 string8_safe(const char *p_string);
|
||||||
|
|
||||||
|
void read_ini_key(const char *key, pfc::string_base &value, const wchar_t *path);
|
||||||
|
|
||||||
|
wchar_t * utf8_to_wide(const char * in);
|
||||||
|
|
||||||
|
int compare_natural_utf8(const char *p1, const char *p2);
|
||||||
|
|
||||||
|
#endif /*__FOO_UTILS_H__*/
|
||||||
|
|
||||||
|
|
||||||