From 0b7200f97e02e338395af0c8cf1bfe77c5c1830f Mon Sep 17 00:00:00 2001
From: Terence Denning <terrencedenning@gmail.com>
Date: Sun, 28 Apr 2019 09:57:15 -0700
Subject: [PATCH] print guesses on the webpage

---
 http-server.c | 118 +++++++++++++++++++++++++++++++++++---------------
 image_tagger  | Bin 23152 -> 23344 bytes
 2 files changed, 84 insertions(+), 34 deletions(-)

diff --git a/http-server.c b/http-server.c
index d9ee97b..4b96446 100644
--- a/http-server.c
+++ b/http-server.c
@@ -31,6 +31,8 @@ void set_user(int sockfd);
 void user_ready(int sockfd);
 void print_details();
 void check_win(int user, char *keyword);
+char *substring(char *string, int position, int length);
+void insert_substring(char *a, char *b, int position);
 
 // constants
 static char const * const HTTP_200_FORMAT = "HTTP/1.1 200 OK\r\n\
@@ -117,8 +119,11 @@ static bool handle_http_request(int sockfd)
         
         if (method == GET)
         {
-            
+            // get the size of the file
+            struct stat st;
+
             if( strstr(buff, "start=Start") != NULL ){
+
                 if( strcmp(webpage, "html/2_start.html") ){
                     user_ready(sockfd);
                 }
@@ -131,16 +136,10 @@ static bool handle_http_request(int sockfd)
                     gameover = 0;
                 }                
                 webpage = "html/3_first_turn.html";
-            } else if( strstr(buff, "Cookie:") != NULL ) {
-                webpage = "html/1_intro.html";
             } else {
                 webpage = "html/1_intro.html";
             }
             
-            
-            
-            // get the size of the file
-            struct stat st;
             stat(webpage, &st);
 
             n = sprintf(buff, HTTP_200_FORMAT, st.st_size);
@@ -165,7 +164,6 @@ static bool handle_http_request(int sockfd)
                 return false;
             }
             close(filefd);
-            
         }
         else if (method == POST)
         {
@@ -217,30 +215,40 @@ static bool handle_http_request(int sockfd)
                 size = st.st_size + added_length;
                 n = sprintf(buff, HTTP_200_FORMAT_WITH_COOKIE, username, size);
             }
-            else if(strstr(buff, "guess=Guess") != NULL) {  
-                
+            else if(strstr(buff, "guess=Guess") != NULL) { 
                 char *keyword = strstr(buff, "keyword=")+8;
                 int keyword_length = strlen(keyword);
                 keyword[keyword_length-12] = '\0';
-
-                if (sockfd == user1){            
+                    
+                if (sockfd == user1){                               
                     /* if other player is ready then accept guesses */
-                    if( user2_start == 1  ){
+                    if( user2_start == 1  ){   
                         webpage = "html/4_accepted.html";
                         strcpy(user1_guesses[user1_guess_number], keyword);
                         user1_guess_number++;
-                        check_win(1, keyword);            
+                        check_win(1, keyword); 
+
+                        username_length = strlen(username);
+                        added_length = username_length + 2;
+                        size = st.st_size + added_length;
+                        n = sprintf(buff, HTTP_200_FORMAT_WITH_COOKIE, username, size);          
                     } else if( gameover == 1 ){ 
                         webpage = "html/6_endgame.html"; 
                     } else {
                         webpage = "html/5_discarded.html";
                     }
                 } else if(sockfd == user2){
+                    
                     if( user1_start == 1  ){
                         webpage = "html/4_accepted.html";
                         strcpy(user2_guesses[user2_guess_number], keyword);
                         user2_guess_number++;
                         check_win(2, keyword);
+
+                        username_length = strlen(username);
+                        added_length = username_length + 2;
+                        size = st.st_size + added_length;
+                        n = sprintf(buff, HTTP_200_FORMAT_WITH_COOKIE, username, size);
                     } else if( gameover == 1){    
                         webpage = "html/6_endgame.html"; 
                     } else {
@@ -275,8 +283,26 @@ static bool handle_http_request(int sockfd)
             }
             close(filefd);
 
-            
-            if( strcmp(webpage, "html/4_accepted.html") == 0 ){
+
+            if((strlen(username) > 0) && (strstr(buff, "user=") != NULL) ){
+                // move the trailing part backward
+                int p1, p2;
+                for (p1 = size - 1, p2 = p1 - added_length; p1 >= size - 25; --p1, --p2)
+                    buff[p1] = buff[p2];
+                ++p2;
+                
+                buff[p2++] = ' ';
+                buff[p2++] = ' ';
+                
+                
+                // copy the username
+                strncpy(buff + p2, username, username_length);
+                if (write(sockfd, buff, size) < 0)
+                {
+                    perror("write");
+                    return false;
+                }
+            } else if( strcmp(webpage, "html/4_accepted.html") == 0 ){
                 if(sockfd == user1){
                     memset(user1_current_guesses, '\0', 10100);
                     for(int i=0; i<100; i++){
@@ -285,6 +311,7 @@ static bool handle_http_request(int sockfd)
                             strncat(user1_current_guesses, ", ", 3);
                         }
                     }
+                   insert_substring(buff, user1_current_guesses, 587);
 
                 } else if(sockfd == user2){
                     memset(user2_current_guesses, '\0', 10100);
@@ -294,30 +321,17 @@ static bool handle_http_request(int sockfd)
                             strncat(user2_current_guesses, ", ", 3);
                         }
                     }
+                   insert_substring(buff, user2_current_guesses, 587);
+                   
                 }
-                
-                printf("User1 guesses: %s, User2 guesses: %s\n", user1_current_guesses, user2_current_guesses);
-                
-            }
-            
 
-            if((strlen(username) > 0) && (strstr(buff, "user=") != NULL) ){
-                // move the trailing part backward
-                int p1, p2;
-                for (p1 = size - 1, p2 = p1 - added_length; p1 >= size - 25; --p1, --p2)
-                    buff[p1] = buff[p2];
-                ++p2;
-                // put the separator
-                buff[p2++] = ' ';
-                buff[p2++] = ' ';
-                
-                // copy the username
-                strncpy(buff + p2, username, username_length);
-                if (write(sockfd, buff, size) < 0)
+                if (write(sockfd, buff, st.st_size) < 0)
                 {
                     perror("write");
                     return false;
                 }
+                
+                printf("\nUser1 guesses: %s\n User2 guesses: %s\n", user1_current_guesses, user2_current_guesses); 
             } else {
                 if (write(sockfd, buff, st.st_size) < 0)
                 {
@@ -518,6 +532,42 @@ void check_win(int user, char *keyword){
     }
 }
 
+void insert_substring(char *a, char *b, int position)
+{
+   char *f, *e;
+   int length;
+   
+   length = strlen(a);
+   
+   f = substring(a, 1, position - 1 );      
+   e = substring(a, position, length-position+1);
+ 
+   strcpy(a, "");
+   strcat(a, f);
+   free(f);
+   strcat(a, b);
+   strcat(a, e);
+   free(e);
+}
+ 
+char *substring(char *string, int position, int length)
+{
+   char *pointer;
+   int c;
+ 
+   pointer = malloc(length+1);
+   
+   if( pointer == NULL )
+       exit(EXIT_FAILURE);
+ 
+   for( c = 0 ; c < length ; c++ )
+      *(pointer+c) = *((string+position-1)+c);      
+       
+   *(pointer+c) = '\0';
+ 
+   return pointer;
+}
+
 void print_details(){
     printf("User1: %d, User2: %d, User1_start: %d, User2_start: %d\n\n", user1, user2, user1_start, user2_start);
 }
diff --git a/image_tagger b/image_tagger
index 2287ea3f927d89952185630747eb603cacb866a2..f57b2ea9ce8e6f63aafe76988dda1177b9b0d928 100755
GIT binary patch
delta 8146
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
T$wE<PoJ)fsYPcs)43P%_oBqMp

delta 7558
zcmdn6jq$@4#t9Na4nhoI-~c8W7(N6|)LO=Azzg9TOuVVjby5<-IVm|=h*8h6f(^oj
z(F_6*J|hDI14wFt4TQhI2bJz%hVTU@H!_L~UVy5)09AEi@=C^d#XrUnHRyB=M3|vw
zvL=(iA}$*epf)5-p2-w#vtjD<L?Z<zUuNN|TuTe~3pe#OoR}CG7*rV;7+`K?U~B}L
z%mflsV_;yon0hYP@>93WWJe~6$s0mgCi^gpO#TqUGP#CXhf#B~Bdhr21I!+b`zB9h
z7N4xZ;=y<o%xYkfnC!tOF}WauW%3pl9mbzv(H|@ljGsU(#w%dbb+RL?J|p+!L}u~H
z3s^lE&x1rKu}LuA0WlblfXK-SYzB;bK`h1)h;?iRjE^UOWD{pxH<^?D=;S->v6JmM
zQYSCtaGHFMgR36od`1Q)u#cb-!61^E$;-gN%plCj0FInesZ34=1||kskhd8a7+^8O
z0n*ICz@Q)uVXT101x)+_G;M4^6X!61sNdnkFu9mhRPq3t{0gZ2iOCB&vl&??^Kywx
z3PQAi$rt`$3Y=O*C);v~ODaJGz~m1kS=Gt8T;hyslh1OAPoBfY!~4Jwtb~D`fq{W(
z@?S3T$!EBDct0SCvQF0J7N7iwi-(s1Y7R&(`{Y<|aY>lJKxPOa$#PEa<rbeD!_C91
zfF#O2c`vv4<Q{GwUIQdi-pOyd#V7CK=HYcf66K#P%OgJd4L1*O0FtQCWM3Zf$uc}V
zya`C6B9m)*#3jW*j)39<Bw6vvYk9;c*YNQ0HXw;gPQJ?{K6wof5AOsdQR&INyyBDZ
z@bK_1KoXUmY|AS?nTMB$cLS2B{N!9-@yRy4JiG^xL=`8`<rU{uhPnepU6?$PSA27g
z&IP7P0!sCZ>=+pSt1hu)VBnW`VEC^J;%9)Ay?pTh|NsB0v+NicGC-;7<pnT*5{M7V
zWG@eZ`CTABC|ADR0OmJ=_$&+z3@;ae`Bfl3D~LY<%r64*L50Z61`xkqH47vFiour!
zAOY1R5FZqeFB8E0C=j0$WIzCz9|Yoaf%pz!z88qk4dNSs`A#4{4~VY-=39aIpu+B@
z0GMwC;`4#z8UFwOU;kfK3nah~68P{B<YOfeAC%EvJ^=HjKzvZ*et7}R7XtA?`R3&T
zFrN#=2j#Dq8^C-f5MKmj-U2ZHmn{QBhA4<X0nGmd;)4>$%Z7jd>;L~(eFYK_2Pr53
zD|iIrOMv(ZVE!!-A5=oW3;^>lf%sA&c?U566o@Yk;v0bZhd_K85MKez-v#2!g7^Yp
z{w5G#4#a2pR}b>>Dv*FYNZ`X?5Fcbf+5}J{0Aa(oo}CxtJUSnFG(Y(e5aQFz>Lt#=
z;L*$bSPVqjs`D{0{1+{=WnlQiFYf{t+Gq=+SV87`SpFyx_2_2x0|~VrDB=A7fM31=
zWbR=Q4T=blUfV{HY_Dn6<l90rE~+3->wyxE{}0l@CW2KmFfcUOCfYJEFqG<tdNkXz
zftVhhPfK__x^1~^85myZ{{R2~MaKXC|Bta+PPP^fVq8DDPgqW8sw@M;3+;dZ|G$>(
zZvFG^|NqWo9=*0*vJ4D6K+bq!@b~|JFze-Mp2;_aEjgoQ85le|kH1KsEG44FsSD*9
zO!gH~(@m6NV1St7(Rr@(_zTNF|Nncm9;lS_=(T+z!@%&u18y2K&*TLnCiN4z85o-P
z3Vi?npMk&iDkCUhT0eaM|KFq6v`+?Nk?UWuAtjX_-K-O>K`Kn^p;BId{{L@1P{Iqb
zv-9|il|l>*-K^2p3=FLYO8Mc!j|CYRUTb!X{<8u}f3ad<0Q=HgrXJ?ag}?v*Kh7#|
z4e~R{3f6G26|9QZ3=FR=J$hk|f(Rdfu@U045&@51R&R*XZ&nNpulYQBS*;=bXI2ah
z9^I_>K~(S51dyjXuYp2NR0Je3b;9@m|7ARSdE=!(7D6oOJm=AQ930#)6#h(B5LYo>
z^$YC#N->XK+em2!h8H`3!y=@F3uF#!f)xY9K9IZNTH7Yeh$%5TPqr76tIq-H@&En*
ze|M|K_y7MpkH47o3ueGyPEd3~g{y!4|NrtCCoDP``CIEbK@MZx4{~28>tRa}58}*T
zQ#ol!<b?hPJCDC57aVu20$_30X&}Yjto@eGAWg`gKMIN=NJ2aQqLm-y18_)q^zt%E
zf)qn+KnjS%ljX%#O?`iYEdqzbA4vv=7cp>eh=bhO&B|<v9uAt5E5#L~%76a<-`UFZ
z{r~^wy&#gIQrV-|HVtIPpP!&`(Sd}E{ZCl9tl|KL3shJGWN|lZrv=Dy$UfOGIQh1M
zd|urTu*3K}wV6RGY&Ag!cf!qb;Q)z3Jk@Ku5#+_r<1bEv3~fEY-?Ekg6auV*7^b@m
zBI~P!>YF&ZQ9_c5{l{cSX;Y>K@yQj^3eoR=!2I{plL=YVYY9jk{e`-)MGi&!22}bU
zNV@p|heu~?1SpYqL#WQ<FG42!Nvi12H)CM11jiVE>jnl;2D)p;z|j1Iv9!dam$e3L
z3hN~^ki-@<28PLj>hkpm%@`Ow7!P^C%sS@LdHqGtxBvgUS<6704={GJ=7Q9~73>Gq
zqA&RQ7#Lpu09z6UQul+gRM?}JRS059uo(lx%Uhrj>tz*&2swa+j)OHkG=;lUrFA)2
zNE~WLp+_(4E>N-D$tnPL=r>cSL*>_Cap<Y9AcyWSWngFqIdr`#D2||^a%?}SdVk@|
z3n~}7S*L>({a`Ewl>@;L8>W~tFua!Y=w%Iu@LNE9P`O|X;g^7oW6cFoGAISZVm^>X
zu<Y=5GNX)`*g8;=3{JhTc|3Y;ImH<mUTA%ttScjDru7w^^1xZ*rYHl$3(Ie?6#Rt+
zWD@HG6Z9;>_HA;bj6!|LS6G@s&J)fcLvDgR-)aKM6Ea_6CbqMH@&r_v6=ZWaYnllt
zxtTJ7YP!zjFXX?1N@M=k7A8<y_-G7|j#gzx28LZF>M+Oj%G*9^VqkbN|I7dX$6F;p
zg+HizeFKU!Fc*}DB-lZwGhX1|#?W$rzhxbYq~rx-P`q6L6{k->gQ^P;rf#@axfw9o
zQy$=gUIS#?XRta}nWo9w^2%x78^H#o9cR!{IOf2_&<xhi*t{3yoMiq!_W%F?zcgS3
z`Q(5R!Y6WQKC#u0VqkcY^%>+58B~vexL}WbS^>5S#Un6D$=wi1kViIr0(*q9yA>uY
z*9?<|dZaj#f#JnIusYWCNRUVBog%@eBY6a*o3VK>h=O{=qgPZKq^#F;N&_g$Y_AH#
zDn4V7Vco3`-~a!II#3T>lEX?YV_`@k;tdKtP>ID4lJ0H|0F|dN7(44*6~2QCQ4s0T
zJ=Np;|Noj7I$Kq~|NsA5w;N1*%;4WPg%wn*cY_ss%;<n{o7aMLF*dISsb+*pdUQ_(
z8Sc^iO47sfLhbHmupx{Pvw8y<JEww_d(1f20y2~DzXGz%<h8OAnh<%9-d>QM9*hS)
zApQfTh0gOY7JT^sA8N;BLvdlnOCWyh0shVv;F86*R*-?=#odpvgg=7;RLs{;f~cy@
z_2{*A1gTgEQ}H_9qnlOP02E9IcYzw7`#?pRN3U(H5Cg-DQy>5Te{Hct7i4zw1&?0d
znF64U1ZrtP+elD@ML=yN0Z<zWZZO+~9bluneSb{8smQ~m{$cWSMMtp`eNY^lUIWz-
zu+~DthskzI`s(~2LHQcg(r(@hA{oGi!&H!aTR!~%4=H4KeV9B&Nnb|tJt(_^6$FA5
zSi%+Lf0%q<$yg)nJ;<;l|3Jaj3TmBuG#?P~=mxj`{=NVIpMU#-&f_nhyqj#Ltf)5;
zVcHRpFBZOsS$F+CD1Crjvk%nM={)|z_5J2f<#<M!BX8j@u;FK5cp>r*rpN2uWERyP
z*`Bu`7wq{5s=7fWL#3ccuk8dr28I`jZzr!+?RN=y{r|s5=fUn)kaXuEkIr)*y|$lu
zVX6D#>;L~>7k0O<`3G+Lh`;;)zxe}W%Yl+uxY)hdlN;0u{iI+2|9|pus7L2hkLEW5
z$642FK}JcAv&L#MfcirJkF$ouS)E#-1{VXvan@!ys}ats)|zauZYY_f1<skfQW#(b
zU+3``+h6_vKiN-RsXlN47TKCt|Nl3;{$Xsc{gYhR;L&S4gNK3P#kZIL|4%?TuCw+}
zH*1q71B0dOpHijcti_rz2X57bILo8gHVdS2@5}%HUt4ywMj{k@K^4~@XYE0#_5`V(
z08$OAWZXf#CM=fnLCpchf(uAd?92cEU$%mZX4Y>S5C`#j^x9g1<Qzf9<#e;&)Bv>>
z{+H@>vtELzDN*cpt^d=>dO(ALq1*KjxQLeGfyG%CNS|pp>oTZ5t!~!oP<`?s)vUcp
z+Wv6Ev>9V@Z#+a_sZuxV0u6AVK;k&-Bn?o^f*Pp3w%55C7+%bJ@&Es8?QT{xsA`37
z)^dnyvE!_nVAY@uXS)rgIQPZmL`_$#uz8@^JLJ*r`T$(4Tz_%p1t>9>N<dogx}Z)=
zFY9_x)3lTIgE|94v+EDWZq`fclOJeW)gMwv*Pei)eJ7}U(aUNL(Ov`A{)e%fHA)>E
z$Tf4J$)VdcLY;x3o7WFSiZXym)^BPI433>2z@a*e3l=;Jp8x+pA@*>Z9>07Gc;JbF
zUw-m^ZBcO#Wd?>&k6v969qgkCO8y)#CO@0ZtrN(!;Q8h_okh%>8*~;hZ8BKL$nKn<
zpPiX%HF>S!W}(pH)FMNL^wQMg;?!a*1=V7m$;C#wo9`P*GS*ixFff2RuPS%`|3AXO
zz+iIk|9?>R?sD({|0xU%44U`<|7T%jVCaAI|Gx?&1H<f(|Npx%GB7lL`u{(Lk%8gs
zr~m(37#SFreE$D`2_pjo*O&kQk1#SYFn#_1{|O@lgUi?d|5=zA7?ynf|KEp+fnm$n
z|Nm2%7#KhU3k(blliN)s8COhRXrj*=ar^&&fyq}*l<OVt{{IgeIe}ym1_sa=Knw!|
zgY3Qk|I<K2AdY+jZA{L*Y|M$gJnS4`dC<6P^6UTqc|au>T%Mg3CO?OPfx-X7|NqZG
zhQj2T9)hI7`u8v}Fo=Hq|G$KRp`L*Ot{@+-;0^-=L*~c-|JS1!unI2!hk=3N$H)Kw
z(@^9S;qo$!3=DRk{{IKHnGxoHhRfS9GBAjJ{{P<;>>QW_3c&IVE({C|F^mih7M~{v
znK>zd0y^OH|No#m2V@-xgGPGxfNK2D|Nl=;bQIov!E6WX<OjT&T(CjY2SSr4+4u<_
zfEFg8kr<H11(QG8$TO~(ENH8*cmp(|1sxp+$r*q~#26SDK;u*(e%|CnTYbR;&{0fK
z`x+$5FnOV^ypRD@5j$9jf#C$l<V&`Gj58)H+Q~DzO?I?PXS^_3(Mfo6029mN19ps?
zZ`cbkO2TY}Y64Tt4D1YUlNlYw8D~spbQERgWH<q)xfl#4dpf!^8cd$(D9-3Gd7`5z
z3qQjF&B=!x^%(z5{^%$!Sz!V;0fk^@5N22~S<y+Ham8dsCsAfmh7FSgoy5Ve5oH!<
zI54@<sa&uCG!%xUk8kovC-KP&&Kyh+geGe_>q)}KoMCEmK_j~id<+Vc3!TLo7fkMS
z)}JilBEY!~JZdk>uw(K?XK}^@lV3XPGoF|%>2jS*6*RiWz`&5kJNcK38e_?1MOS^p
z4bbQS#UIFM@E|3FFax@Em5iXmP>kWi<VII<N!Y+RNCyZ{1t$eThCh=xx{AXi2qXi-
z-ji>-$}=s{oczmGPZ8b1rA!PALJWKiA3@U!3=9nGCmXuSGcrzYbQ5P4V`5-XnC!?T
z%-A=1qnkLR5lEELZSq4mamGk6JA1OAyEtPdm~B1T&|92w;^abianBi0Q>TL_EEpIV
z!1<1WfnhOJycTL(3CMj63=Ah285o3^K(PrGfKux~CQBY-Vqg$tkYrd;4iN_RP(Z93
zAX&yQAX1W@8RCzB8Xy@422%*daBlKM4{=FRs4N>)7Mu+k7#QS1vW&)H(gRFJgUMVF
zDcQpenwOAZU<iO32Bl_#WEnSr$s>~kJ;fQ%g4nE&n4#h2`4MX00(FQMaIwI^!0?Be
zfkBW-f`J3gL{1iv4+R()pfeJnp=XdziOCN=#Tj)#q@*JY#D@;hBohl#z`(!|IN8z5
zToX1wrVSNM1)C_z5CF9aW?}`%EW<t)kk2F;G@!CjO$@W3c62L1M8M@K0|Uc+kS@lJ
zVDd1SybdN`gGkB0P`ec7Lv+F7M|d(QMQDIYD-bE^#|rU3y1h}8KYEKxmVjhI@q7$o
zjsP_DnkFmyh%?RunZUSda-fem<1r9>bA!(t#>sVlOE;VNA7Et5$t*5O&71t*Pja$)
zVDIJ=ff`Jk-v%o)f(o}#eL+}J1EcdM2Zrhkx<P9i80|NCVyHgn45;Xg$tOe2xlTZN
zCpac^g_#M$N;(+LFgY-+o>5@(#V~zN186Z~Fqt#l95H7J6>Sio92Bm{1uKFNXin}5
zcVqlH`C_=fAjVAMWWfl1L0EwXqZuX#M(A_Gvj2j~oe}1ou%cqc<dYHRoUl2t4U;(|
z%{dXXmY$L3@Pgrh9VC1mCQpp~&$NSk@}wv;E)MAA*e%w{m!ix#9|c0xa8C{ll?MPY
CV7Wg4

-- 
GitLab