- replace the questionable magic to conditionally install headers in
[apt.git] / cmdline / acqprogress.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: acqprogress.cc,v 1.24 2003/04/27 01:56:48 doogie Exp $
4 /* ######################################################################
5
6    Acquire Progress - Command line progress meter 
7    
8    ##################################################################### */
9                                                                         /*}}}*/
10 // Include files                                                        /*{{{*/
11 #include "acqprogress.h"
12 #include <apt-pkg/acquire-item.h>
13 #include <apt-pkg/acquire-worker.h>
14 #include <apt-pkg/strutl.h>
15 #include <apt-pkg/error.h>
16
17 #include <apti18n.h>
18     
19 #include <stdio.h>
20 #include <signal.h>
21 #include <termios.h>
22 #include <unistd.h>
23 #include <iostream>
24                                                                         /*}}}*/
25
26 using namespace std;
27
28 // AcqTextStatus::AcqTextStatus - Constructor                           /*{{{*/
29 // ---------------------------------------------------------------------
30 /* */
31 AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet) :
32     ScreenWidth(ScreenWidth), Quiet(Quiet)
33 {
34 }
35                                                                         /*}}}*/
36 // AcqTextStatus::Start - Downloading has started                       /*{{{*/
37 // ---------------------------------------------------------------------
38 /* */
39 void AcqTextStatus::Start() 
40 {
41    pkgAcquireStatus::Start(); 
42    BlankLine[0] = 0;
43    ID = 1;
44 };
45                                                                         /*}}}*/
46 // AcqTextStatus::IMSHit - Called when an item got a HIT response       /*{{{*/
47 // ---------------------------------------------------------------------
48 /* */
49 void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm)
50 {
51    if (Quiet > 1)
52       return;
53
54    if (Quiet <= 0)
55       cout << '\r' << BlankLine << '\r';   
56    
57    cout << _("Hit ") << Itm.Description;
58    if (Itm.Owner->FileSize != 0)
59       cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
60    cout << endl;
61    Update = true;
62 };
63                                                                         /*}}}*/
64 // AcqTextStatus::Fetch - An item has started to download               /*{{{*/
65 // ---------------------------------------------------------------------
66 /* This prints out the short description and the expected size */
67 void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm)
68 {
69    Update = true;
70    if (Itm.Owner->Complete == true)
71       return;
72    
73    Itm.Owner->ID = ID++;
74    
75    if (Quiet > 1)
76       return;
77
78    if (Quiet <= 0)
79       cout << '\r' << BlankLine << '\r';
80    
81    cout << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description;
82    if (Itm.Owner->FileSize != 0)
83       cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
84    cout << endl;
85 };
86                                                                         /*}}}*/
87 // AcqTextStatus::Done - Completed a download                           /*{{{*/
88 // ---------------------------------------------------------------------
89 /* We don't display anything... */
90 void AcqTextStatus::Done(pkgAcquire::ItemDesc &Itm)
91 {
92    Update = true;
93 };
94                                                                         /*}}}*/
95 // AcqTextStatus::Fail - Called when an item fails to download          /*{{{*/
96 // ---------------------------------------------------------------------
97 /* We print out the error text  */
98 void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm)
99 {
100    if (Quiet > 1)
101       return;
102
103    // Ignore certain kinds of transient failures (bad code)
104    if (Itm.Owner->Status == pkgAcquire::Item::StatIdle)
105       return;
106       
107    if (Quiet <= 0)
108       cout << '\r' << BlankLine << '\r';
109    
110    if (Itm.Owner->Status == pkgAcquire::Item::StatDone)
111    {
112       cout << _("Ign ") << Itm.Description << endl;
113    }
114    else
115    {
116       cout << _("Err ") << Itm.Description << endl;
117       cout << "  " << Itm.Owner->ErrorText << endl;
118    }
119    
120    Update = true;
121 };
122                                                                         /*}}}*/
123 // AcqTextStatus::Stop - Finished downloading                           /*{{{*/
124 // ---------------------------------------------------------------------
125 /* This prints out the bytes downloaded and the overall average line
126    speed */
127 void AcqTextStatus::Stop()
128 {
129    pkgAcquireStatus::Stop();
130    if (Quiet > 1)
131       return;
132
133    if (Quiet <= 0)
134       cout << '\r' << BlankLine << '\r' << flush;
135
136    if (FetchedBytes != 0 && _error->PendingError() == false)
137       ioprintf(cout,_("Fetched %sB in %s (%sB/s)\n"),
138                SizeToStr(FetchedBytes).c_str(),
139                TimeToStr(ElapsedTime).c_str(),
140                SizeToStr(CurrentCPS).c_str());
141 }
142                                                                         /*}}}*/
143 // AcqTextStatus::Pulse - Regular event pulse                           /*{{{*/
144 // ---------------------------------------------------------------------
145 /* This draws the current progress. Each line has an overall percent
146    meter and a per active item status meter along with an overall 
147    bandwidth and ETA indicator. */
148 bool AcqTextStatus::Pulse(pkgAcquire *Owner)
149 {
150    if (Quiet > 0)
151       return true;
152    
153    pkgAcquireStatus::Pulse(Owner);
154    
155    enum {Long = 0,Medium,Short} Mode = Long;
156    
157    char Buffer[sizeof(BlankLine)];
158    char *End = Buffer + sizeof(Buffer);
159    char *S = Buffer;
160    if (ScreenWidth >= sizeof(Buffer))
161       ScreenWidth = sizeof(Buffer)-1;
162
163    // Put in the percent done
164    sprintf(S,"%ld%%",long(double((CurrentBytes + CurrentItems)*100.0)/double(TotalBytes+TotalItems)));
165
166    bool Shown = false;
167    for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
168         I = Owner->WorkerStep(I))
169    {
170       S += strlen(S);
171       
172       // There is no item running 
173       if (I->CurrentItem == 0)
174       {
175          if (I->Status.empty() == false)
176          {
177             snprintf(S,End-S," [%s]",I->Status.c_str());
178             Shown = true;
179          }
180          
181          continue;
182       }
183
184       Shown = true;
185       
186       // Add in the short description
187       if (I->CurrentItem->Owner->ID != 0)
188          snprintf(S,End-S," [%lu %s",I->CurrentItem->Owner->ID,
189                   I->CurrentItem->ShortDesc.c_str());
190       else
191          snprintf(S,End-S," [%s",I->CurrentItem->ShortDesc.c_str());
192       S += strlen(S);
193
194       // Show the short mode string
195       if (I->CurrentItem->Owner->Mode != 0)
196       {
197          snprintf(S,End-S," %s",I->CurrentItem->Owner->Mode);
198          S += strlen(S);
199       }
200             
201       // Add the current progress
202       if (Mode == Long)
203          snprintf(S,End-S," %lu",I->CurrentSize);
204       else
205       {
206          if (Mode == Medium || I->TotalSize == 0)
207             snprintf(S,End-S," %sB",SizeToStr(I->CurrentSize).c_str());
208       }
209       S += strlen(S);
210       
211       // Add the total size and percent
212       if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
213       {
214          if (Mode == Short)
215             snprintf(S,End-S," %lu%%",
216                      long(double(I->CurrentSize*100.0)/double(I->TotalSize)));
217          else
218             snprintf(S,End-S,"/%sB %lu%%",SizeToStr(I->TotalSize).c_str(),
219                      long(double(I->CurrentSize*100.0)/double(I->TotalSize)));
220       }      
221       S += strlen(S);
222       snprintf(S,End-S,"]");
223    }
224
225    // Show something..
226    if (Shown == false)
227       snprintf(S,End-S,_(" [Working]"));
228       
229    /* Put in the ETA and cps meter, block off signals to prevent strangeness
230       during resizing */
231    sigset_t Sigs,OldSigs;
232    sigemptyset(&Sigs);
233    sigaddset(&Sigs,SIGWINCH);
234    sigprocmask(SIG_BLOCK,&Sigs,&OldSigs);
235    
236    if (CurrentCPS != 0)
237    {      
238       char Tmp[300];
239       unsigned long ETA = (unsigned long)((TotalBytes - CurrentBytes)/CurrentCPS);
240       sprintf(Tmp," %sB/s %s",SizeToStr(CurrentCPS).c_str(),TimeToStr(ETA).c_str());
241       size_t Len = strlen(Buffer);
242       size_t LenT = strlen(Tmp);
243       if (Len + LenT < ScreenWidth)
244       {  
245          memset(Buffer + Len,' ',ScreenWidth - Len);
246          strcpy(Buffer + ScreenWidth - LenT,Tmp);
247       }      
248    }
249    Buffer[ScreenWidth] = 0;
250    BlankLine[ScreenWidth] = 0;
251    sigprocmask(SIG_SETMASK,&OldSigs,0);
252
253    // Draw the current status
254    if (strlen(Buffer) == strlen(BlankLine))
255       cout << '\r' << Buffer << flush;
256    else
257       cout << '\r' << BlankLine << '\r' << Buffer << flush;
258    memset(BlankLine,' ',strlen(Buffer));
259    BlankLine[strlen(Buffer)] = 0;
260    
261    Update = false;
262
263    return true;
264 }
265                                                                         /*}}}*/
266 // AcqTextStatus::MediaChange - Media need to be swapped                /*{{{*/
267 // ---------------------------------------------------------------------
268 /* Prompt for a media swap */
269 bool AcqTextStatus::MediaChange(string Media,string Drive)
270 {
271    if (Quiet <= 0)
272       cout << '\r' << BlankLine << '\r';
273    ioprintf(cout,_("Media Change: Please insert the disc labeled\n"
274                    " '%s'\n"
275                    "in the drive '%s' and press enter\n"),
276             Media.c_str(),Drive.c_str());
277
278    char C = 0;
279    while (C != '\n' && C != '\r')
280       read(STDIN_FILENO,&C,1);
281    
282    Update = true;
283    return true;
284 }
285                                                                         /*}}}*/
286 // AcqTextStatus::Authenticate - Authenticate the user                  /*{{{*/
287 // ---------------------------------------------------------------------
288 /* Prompt for a username and password */
289 bool AcqTextStatus::Authenticate(string Desc,string &User,string &Pass)
290 {
291    if (Quiet > 0)
292       return false;
293
294    cout << '\r' << BlankLine << '\r';
295
296    ioprintf(cout,_("Please login to %s\nUsername: "), Desc.c_str());
297    cout << flush;
298
299    char S[1024];
300    char C = 0;
301    size_t idx = 0;
302    while (C != '\n' && C != '\r' && idx < (sizeof(S) - 1))
303    {
304       read(STDIN_FILENO,&C,1);
305       S[idx++] = C;
306    }
307    S[--idx] = '\0';
308    User = S;
309
310    ioprintf(cout,_("Password: "));
311    cout << flush;
312
313    // Turn off echo for entering the password
314    struct termios TermIO;
315    tcgetattr(STDIN_FILENO, &TermIO);
316
317    struct termios TermIO_noecho;
318    TermIO_noecho = TermIO;
319    TermIO_noecho.c_lflag &= !ECHO;
320    tcsetattr(STDIN_FILENO, TCSANOW, &TermIO_noecho);
321
322    C = 0;
323    idx = 0;
324    while (C != '\n' && C != '\r' && idx < (sizeof(S) - 1))
325    {
326       read(STDIN_FILENO,&C,1);
327       S[idx++] = C;
328    }
329    S[--idx] = '\0';
330    Pass = S;
331
332    // Turn echo back on
333    tcsetattr(STDIN_FILENO, TCSANOW, &TermIO);
334
335    ioprintf(cout,"\n");
336    cout << flush;
337    
338    Update = true;
339    return true;
340 }
341                                                                         /*}}}*/